linux/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * This file is provided under a dual BSD/GPLv2 license.  When using or
   4 * redistributing this file, you may do so under either license.
   5 *
   6 * GPL LICENSE SUMMARY
   7 *
   8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
   9 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  10 * Copyright(c) 2016 Intel Deutschland GmbH
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of version 2 of the GNU General Public License as
  14 * published by the Free Software Foundation.
  15 *
  16 * This program is distributed in the hope that it will be useful, but
  17 * WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19 * General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  24 * USA
  25 *
  26 * The full GNU General Public License is included in this distribution
  27 * in the file called COPYING.
  28 *
  29 * Contact Information:
  30 *  Intel Linux Wireless <linuxwifi@intel.com>
  31 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  32 *
  33 * BSD LICENSE
  34 *
  35 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  36 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  37 * All rights reserved.
  38 *
  39 * Redistribution and use in source and binary forms, with or without
  40 * modification, are permitted provided that the following conditions
  41 * are met:
  42 *
  43 *  * Redistributions of source code must retain the above copyright
  44 *    notice, this list of conditions and the following disclaimer.
  45 *  * Redistributions in binary form must reproduce the above copyright
  46 *    notice, this list of conditions and the following disclaimer in
  47 *    the documentation and/or other materials provided with the
  48 *    distribution.
  49 *  * Neither the name Intel Corporation nor the names of its
  50 *    contributors may be used to endorse or promote products derived
  51 *    from this software without specific prior written permission.
  52 *
  53 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  54 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  55 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  56 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  57 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  58 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  59 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  60 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  61 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  62 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  63 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  64 *
  65 *****************************************************************************/
  66#include <linux/vmalloc.h>
  67#include <linux/ieee80211.h>
  68#include <linux/netdevice.h>
  69
  70#include "mvm.h"
  71#include "fw-dbg.h"
  72#include "sta.h"
  73#include "iwl-io.h"
  74#include "debugfs.h"
  75#include "iwl-fw-error-dump.h"
  76
  77static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file,
  78                                          char __user *user_buf,
  79                                          size_t count, loff_t *ppos)
  80{
  81        struct iwl_mvm *mvm = file->private_data;
  82        char buf[16];
  83        int pos, budget;
  84
  85        if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
  86                return -EIO;
  87
  88        mutex_lock(&mvm->mutex);
  89        budget = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_REPORT, 0);
  90        mutex_unlock(&mvm->mutex);
  91
  92        if (budget < 0)
  93                return budget;
  94
  95        pos = scnprintf(buf, sizeof(buf), "%d\n", budget);
  96
  97        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  98}
  99
 100static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf,
 101                                         size_t count, loff_t *ppos)
 102{
 103        int ret;
 104
 105        if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
 106                return -EIO;
 107
 108        mutex_lock(&mvm->mutex);
 109        ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_STOP, 0);
 110        mutex_unlock(&mvm->mutex);
 111
 112        return ret ?: count;
 113}
 114
 115static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
 116                                        size_t count, loff_t *ppos)
 117{
 118        int ret;
 119        u32 scd_q_msk;
 120
 121        if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
 122                return -EIO;
 123
 124        if (sscanf(buf, "%x", &scd_q_msk) != 1)
 125                return -EINVAL;
 126
 127        IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk);
 128
 129        mutex_lock(&mvm->mutex);
 130        ret =  iwl_mvm_flush_tx_path(mvm, scd_q_msk, 0) ? : count;
 131        mutex_unlock(&mvm->mutex);
 132
 133        return ret;
 134}
 135
 136static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
 137                                         size_t count, loff_t *ppos)
 138{
 139        struct iwl_mvm_sta *mvmsta;
 140        int sta_id, drain, ret;
 141
 142        if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
 143                return -EIO;
 144
 145        if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
 146                return -EINVAL;
 147        if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT)
 148                return -EINVAL;
 149        if (drain < 0 || drain > 1)
 150                return -EINVAL;
 151
 152        mutex_lock(&mvm->mutex);
 153
 154        mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
 155
 156        if (!mvmsta)
 157                ret = -ENOENT;
 158        else
 159                ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count;
 160
 161        mutex_unlock(&mvm->mutex);
 162
 163        return ret;
 164}
 165
 166static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
 167                                   size_t count, loff_t *ppos)
 168{
 169        struct iwl_mvm *mvm = file->private_data;
 170        const struct fw_img *img;
 171        unsigned int ofs, len;
 172        size_t ret;
 173        u8 *ptr;
 174
 175        if (!mvm->ucode_loaded)
 176                return -EINVAL;
 177
 178        /* default is to dump the entire data segment */
 179        img = &mvm->fw->img[mvm->cur_ucode];
 180        ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
 181        len = img->sec[IWL_UCODE_SECTION_DATA].len;
 182
 183        if (mvm->dbgfs_sram_len) {
 184                ofs = mvm->dbgfs_sram_offset;
 185                len = mvm->dbgfs_sram_len;
 186        }
 187
 188        ptr = kzalloc(len, GFP_KERNEL);
 189        if (!ptr)
 190                return -ENOMEM;
 191
 192        iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len);
 193
 194        ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len);
 195
 196        kfree(ptr);
 197
 198        return ret;
 199}
 200
 201static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
 202                                    size_t count, loff_t *ppos)
 203{
 204        const struct fw_img *img;
 205        u32 offset, len;
 206        u32 img_offset, img_len;
 207
 208        if (!mvm->ucode_loaded)
 209                return -EINVAL;
 210
 211        img = &mvm->fw->img[mvm->cur_ucode];
 212        img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset;
 213        img_len = img->sec[IWL_UCODE_SECTION_DATA].len;
 214
 215        if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
 216                if ((offset & 0x3) || (len & 0x3))
 217                        return -EINVAL;
 218
 219                if (offset + len > img_offset + img_len)
 220                        return -EINVAL;
 221
 222                mvm->dbgfs_sram_offset = offset;
 223                mvm->dbgfs_sram_len = len;
 224        } else {
 225                mvm->dbgfs_sram_offset = 0;
 226                mvm->dbgfs_sram_len = 0;
 227        }
 228
 229        return count;
 230}
 231
 232static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file,
 233                                                  char __user *user_buf,
 234                                                  size_t count, loff_t *ppos)
 235{
 236        struct iwl_mvm *mvm = file->private_data;
 237        char buf[16];
 238        int pos;
 239
 240        if (!mvm->temperature_test)
 241                pos = scnprintf(buf , sizeof(buf), "disabled\n");
 242        else
 243                pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature);
 244
 245        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 246}
 247
 248/*
 249 * Set NIC Temperature
 250 * Cause the driver to ignore the actual NIC temperature reported by the FW
 251 * Enable: any value between IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -
 252 * IWL_MVM_DEBUG_SET_TEMPERATURE_MAX
 253 * Disable: IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE
 254 */
 255static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
 256                                                   char *buf, size_t count,
 257                                                   loff_t *ppos)
 258{
 259        int temperature;
 260
 261        if (!mvm->ucode_loaded && !mvm->temperature_test)
 262                return -EIO;
 263
 264        if (kstrtoint(buf, 10, &temperature))
 265                return -EINVAL;
 266        /* not a legal temperature */
 267        if ((temperature > IWL_MVM_DEBUG_SET_TEMPERATURE_MAX &&
 268             temperature != IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) ||
 269            temperature < IWL_MVM_DEBUG_SET_TEMPERATURE_MIN)
 270                return -EINVAL;
 271
 272        mutex_lock(&mvm->mutex);
 273        if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) {
 274                if (!mvm->temperature_test)
 275                        goto out;
 276
 277                mvm->temperature_test = false;
 278                /* Since we can't read the temp while awake, just set
 279                 * it to zero until we get the next RX stats from the
 280                 * firmware.
 281                 */
 282                mvm->temperature = 0;
 283        } else {
 284                mvm->temperature_test = true;
 285                mvm->temperature = temperature;
 286        }
 287        IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n",
 288                       mvm->temperature_test ? "En" : "Dis" ,
 289                       mvm->temperature);
 290        /* handle the temperature change */
 291        iwl_mvm_tt_handler(mvm);
 292
 293out:
 294        mutex_unlock(&mvm->mutex);
 295
 296        return count;
 297}
 298
 299static ssize_t iwl_dbgfs_nic_temp_read(struct file *file,
 300                                       char __user *user_buf,
 301                                       size_t count, loff_t *ppos)
 302{
 303        struct iwl_mvm *mvm = file->private_data;
 304        char buf[16];
 305        int pos, ret;
 306        s32 temp;
 307
 308        if (!mvm->ucode_loaded)
 309                return -EIO;
 310
 311        mutex_lock(&mvm->mutex);
 312        ret = iwl_mvm_get_temp(mvm, &temp);
 313        mutex_unlock(&mvm->mutex);
 314
 315        if (ret)
 316                return -EIO;
 317
 318        pos = scnprintf(buf , sizeof(buf), "%d\n", temp);
 319
 320        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 321}
 322
 323static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
 324                                       size_t count, loff_t *ppos)
 325{
 326        struct iwl_mvm *mvm = file->private_data;
 327        struct ieee80211_sta *sta;
 328        char buf[400];
 329        int i, pos = 0, bufsz = sizeof(buf);
 330
 331        mutex_lock(&mvm->mutex);
 332
 333        for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
 334                pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
 335                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
 336                                                lockdep_is_held(&mvm->mutex));
 337                if (!sta)
 338                        pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
 339                else if (IS_ERR(sta))
 340                        pos += scnprintf(buf + pos, bufsz - pos, "%ld\n",
 341                                         PTR_ERR(sta));
 342                else
 343                        pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
 344                                         sta->addr);
 345        }
 346
 347        mutex_unlock(&mvm->mutex);
 348
 349        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 350}
 351
 352static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
 353                                                char __user *user_buf,
 354                                                size_t count, loff_t *ppos)
 355{
 356        struct iwl_mvm *mvm = file->private_data;
 357        char buf[64];
 358        int bufsz = sizeof(buf);
 359        int pos = 0;
 360
 361        pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d0=%d\n",
 362                         mvm->disable_power_off);
 363        pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d3=%d\n",
 364                         mvm->disable_power_off_d3);
 365
 366        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 367}
 368
 369static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,
 370                                                 size_t count, loff_t *ppos)
 371{
 372        int ret, val;
 373
 374        if (!mvm->ucode_loaded)
 375                return -EIO;
 376
 377        if (!strncmp("disable_power_off_d0=", buf, 21)) {
 378                if (sscanf(buf + 21, "%d", &val) != 1)
 379                        return -EINVAL;
 380                mvm->disable_power_off = val;
 381        } else if (!strncmp("disable_power_off_d3=", buf, 21)) {
 382                if (sscanf(buf + 21, "%d", &val) != 1)
 383                        return -EINVAL;
 384                mvm->disable_power_off_d3 = val;
 385        } else {
 386                return -EINVAL;
 387        }
 388
 389        mutex_lock(&mvm->mutex);
 390        ret = iwl_mvm_power_update_device(mvm);
 391        mutex_unlock(&mvm->mutex);
 392
 393        return ret ?: count;
 394}
 395
 396#define BT_MBOX_MSG(_notif, _num, _field)                                    \
 397        ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
 398        >> BT_MBOX##_num##_##_field##_POS)
 399
 400
 401#define BT_MBOX_PRINT(_num, _field, _end)                                   \
 402                        pos += scnprintf(buf + pos, bufsz - pos,            \
 403                                         "\t%s: %d%s",                      \
 404                                         #_field,                           \
 405                                         BT_MBOX_MSG(notif, _num, _field),  \
 406                                         true ? "\n" : ", ");
 407
 408static
 409int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf,
 410                           int pos, int bufsz)
 411{
 412        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
 413
 414        BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
 415        BT_MBOX_PRINT(0, LE_PROF1, false);
 416        BT_MBOX_PRINT(0, LE_PROF2, false);
 417        BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
 418        BT_MBOX_PRINT(0, CHL_SEQ_N, false);
 419        BT_MBOX_PRINT(0, INBAND_S, false);
 420        BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
 421        BT_MBOX_PRINT(0, LE_SCAN, false);
 422        BT_MBOX_PRINT(0, LE_ADV, false);
 423        BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
 424        BT_MBOX_PRINT(0, OPEN_CON_1, true);
 425
 426        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
 427
 428        BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
 429        BT_MBOX_PRINT(1, IP_SR, false);
 430        BT_MBOX_PRINT(1, LE_MSTR, false);
 431        BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
 432        BT_MBOX_PRINT(1, MSG_TYPE, false);
 433        BT_MBOX_PRINT(1, SSN, true);
 434
 435        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
 436
 437        BT_MBOX_PRINT(2, SNIFF_ACT, false);
 438        BT_MBOX_PRINT(2, PAG, false);
 439        BT_MBOX_PRINT(2, INQUIRY, false);
 440        BT_MBOX_PRINT(2, CONN, false);
 441        BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
 442        BT_MBOX_PRINT(2, DISC, false);
 443        BT_MBOX_PRINT(2, SCO_TX_ACT, false);
 444        BT_MBOX_PRINT(2, SCO_RX_ACT, false);
 445        BT_MBOX_PRINT(2, ESCO_RE_TX, false);
 446        BT_MBOX_PRINT(2, SCO_DURATION, true);
 447
 448        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
 449
 450        BT_MBOX_PRINT(3, SCO_STATE, false);
 451        BT_MBOX_PRINT(3, SNIFF_STATE, false);
 452        BT_MBOX_PRINT(3, A2DP_STATE, false);
 453        BT_MBOX_PRINT(3, ACL_STATE, false);
 454        BT_MBOX_PRINT(3, MSTR_STATE, false);
 455        BT_MBOX_PRINT(3, OBX_STATE, false);
 456        BT_MBOX_PRINT(3, OPEN_CON_2, false);
 457        BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
 458        BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
 459        BT_MBOX_PRINT(3, INBAND_P, false);
 460        BT_MBOX_PRINT(3, MSG_TYPE_2, false);
 461        BT_MBOX_PRINT(3, SSN_2, false);
 462        BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
 463
 464        return pos;
 465}
 466
 467static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
 468                                       size_t count, loff_t *ppos)
 469{
 470        struct iwl_mvm *mvm = file->private_data;
 471        struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
 472        char *buf;
 473        int ret, pos = 0, bufsz = sizeof(char) * 1024;
 474
 475        buf = kmalloc(bufsz, GFP_KERNEL);
 476        if (!buf)
 477                return -ENOMEM;
 478
 479        mutex_lock(&mvm->mutex);
 480
 481        pos += iwl_mvm_coex_dump_mbox(notif, buf, pos, bufsz);
 482
 483        pos += scnprintf(buf + pos, bufsz - pos, "bt_ci_compliance = %d\n",
 484                         notif->bt_ci_compliance);
 485        pos += scnprintf(buf + pos, bufsz - pos, "primary_ch_lut = %d\n",
 486                         le32_to_cpu(notif->primary_ch_lut));
 487        pos += scnprintf(buf + pos, bufsz - pos, "secondary_ch_lut = %d\n",
 488                         le32_to_cpu(notif->secondary_ch_lut));
 489        pos += scnprintf(buf + pos,
 490                         bufsz - pos, "bt_activity_grading = %d\n",
 491                         le32_to_cpu(notif->bt_activity_grading));
 492        pos += scnprintf(buf + pos, bufsz - pos,
 493                         "antenna isolation = %d CORUN LUT index = %d\n",
 494                         mvm->last_ant_isol, mvm->last_corun_lut);
 495        pos += scnprintf(buf + pos, bufsz - pos, "bt_rrc = %d\n",
 496                         (notif->ttc_rrc_status >> 4) & 0xF);
 497        pos += scnprintf(buf + pos, bufsz - pos, "bt_ttc = %d\n",
 498                         notif->ttc_rrc_status & 0xF);
 499
 500        pos += scnprintf(buf + pos, bufsz - pos, "sync_sco = %d\n",
 501                         IWL_MVM_BT_COEX_SYNC2SCO);
 502        pos += scnprintf(buf + pos, bufsz - pos, "mplut = %d\n",
 503                         IWL_MVM_BT_COEX_MPLUT);
 504        pos += scnprintf(buf + pos, bufsz - pos, "corunning = %d\n",
 505                         IWL_MVM_BT_COEX_CORUNNING);
 506
 507        mutex_unlock(&mvm->mutex);
 508
 509        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 510        kfree(buf);
 511
 512        return ret;
 513}
 514#undef BT_MBOX_PRINT
 515
 516static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
 517                                     size_t count, loff_t *ppos)
 518{
 519        struct iwl_mvm *mvm = file->private_data;
 520        struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
 521        char buf[256];
 522        int bufsz = sizeof(buf);
 523        int pos = 0;
 524
 525        mutex_lock(&mvm->mutex);
 526
 527        pos += scnprintf(buf + pos, bufsz - pos, "Channel inhibition CMD\n");
 528        pos += scnprintf(buf + pos, bufsz - pos,
 529                         "\tPrimary Channel Bitmap 0x%016llx\n",
 530                         le64_to_cpu(cmd->bt_primary_ci));
 531        pos += scnprintf(buf + pos, bufsz - pos,
 532                         "\tSecondary Channel Bitmap 0x%016llx\n",
 533                         le64_to_cpu(cmd->bt_secondary_ci));
 534
 535        mutex_unlock(&mvm->mutex);
 536
 537        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 538}
 539
 540static ssize_t
 541iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf,
 542                           size_t count, loff_t *ppos)
 543{
 544        u32 bt_tx_prio;
 545
 546        if (sscanf(buf, "%u", &bt_tx_prio) != 1)
 547                return -EINVAL;
 548        if (bt_tx_prio > 4)
 549                return -EINVAL;
 550
 551        mvm->bt_tx_prio = bt_tx_prio;
 552
 553        return count;
 554}
 555
 556static ssize_t
 557iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf,
 558                             size_t count, loff_t *ppos)
 559{
 560        static const char * const modes_str[BT_FORCE_ANT_MAX] = {
 561                [BT_FORCE_ANT_DIS] = "dis",
 562                [BT_FORCE_ANT_AUTO] = "auto",
 563                [BT_FORCE_ANT_BT] = "bt",
 564                [BT_FORCE_ANT_WIFI] = "wifi",
 565        };
 566        int ret, bt_force_ant_mode;
 567
 568        for (bt_force_ant_mode = 0;
 569             bt_force_ant_mode < ARRAY_SIZE(modes_str);
 570             bt_force_ant_mode++) {
 571                if (!strcmp(buf, modes_str[bt_force_ant_mode]))
 572                        break;
 573        }
 574
 575        if (bt_force_ant_mode >= ARRAY_SIZE(modes_str))
 576                return -EINVAL;
 577
 578        ret = 0;
 579        mutex_lock(&mvm->mutex);
 580        if (mvm->bt_force_ant_mode == bt_force_ant_mode)
 581                goto out;
 582
 583        mvm->bt_force_ant_mode = bt_force_ant_mode;
 584        IWL_DEBUG_COEX(mvm, "Force mode: %s\n",
 585                       modes_str[mvm->bt_force_ant_mode]);
 586        ret = iwl_send_bt_init_conf(mvm);
 587
 588out:
 589        mutex_unlock(&mvm->mutex);
 590        return ret ?: count;
 591}
 592
 593#define PRINT_STATS_LE32(_struct, _memb)                                \
 594                         pos += scnprintf(buf + pos, bufsz - pos,       \
 595                                          fmt_table, #_memb,            \
 596                                          le32_to_cpu(_struct->_memb))
 597
 598static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
 599                                          char __user *user_buf, size_t count,
 600                                          loff_t *ppos)
 601{
 602        struct iwl_mvm *mvm = file->private_data;
 603        static const char *fmt_table = "\t%-30s %10u\n";
 604        static const char *fmt_header = "%-32s\n";
 605        int pos = 0;
 606        char *buf;
 607        int ret;
 608        /* 43 is the size of each data line, 33 is the size of each header */
 609        size_t bufsz =
 610                ((sizeof(struct mvm_statistics_rx) / sizeof(__le32)) * 43) +
 611                (4 * 33) + 1;
 612
 613        struct mvm_statistics_rx_phy *ofdm;
 614        struct mvm_statistics_rx_phy *cck;
 615        struct mvm_statistics_rx_non_phy *general;
 616        struct mvm_statistics_rx_ht_phy *ht;
 617
 618        buf = kzalloc(bufsz, GFP_KERNEL);
 619        if (!buf)
 620                return -ENOMEM;
 621
 622        mutex_lock(&mvm->mutex);
 623
 624        ofdm = &mvm->rx_stats.ofdm;
 625        cck = &mvm->rx_stats.cck;
 626        general = &mvm->rx_stats.general;
 627        ht = &mvm->rx_stats.ofdm_ht;
 628
 629        pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 630                         "Statistics_Rx - OFDM");
 631        PRINT_STATS_LE32(ofdm, ina_cnt);
 632        PRINT_STATS_LE32(ofdm, fina_cnt);
 633        PRINT_STATS_LE32(ofdm, plcp_err);
 634        PRINT_STATS_LE32(ofdm, crc32_err);
 635        PRINT_STATS_LE32(ofdm, overrun_err);
 636        PRINT_STATS_LE32(ofdm, early_overrun_err);
 637        PRINT_STATS_LE32(ofdm, crc32_good);
 638        PRINT_STATS_LE32(ofdm, false_alarm_cnt);
 639        PRINT_STATS_LE32(ofdm, fina_sync_err_cnt);
 640        PRINT_STATS_LE32(ofdm, sfd_timeout);
 641        PRINT_STATS_LE32(ofdm, fina_timeout);
 642        PRINT_STATS_LE32(ofdm, unresponded_rts);
 643        PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun);
 644        PRINT_STATS_LE32(ofdm, sent_ack_cnt);
 645        PRINT_STATS_LE32(ofdm, sent_cts_cnt);
 646        PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt);
 647        PRINT_STATS_LE32(ofdm, dsp_self_kill);
 648        PRINT_STATS_LE32(ofdm, mh_format_err);
 649        PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum);
 650        PRINT_STATS_LE32(ofdm, reserved);
 651
 652        pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 653                         "Statistics_Rx - CCK");
 654        PRINT_STATS_LE32(cck, ina_cnt);
 655        PRINT_STATS_LE32(cck, fina_cnt);
 656        PRINT_STATS_LE32(cck, plcp_err);
 657        PRINT_STATS_LE32(cck, crc32_err);
 658        PRINT_STATS_LE32(cck, overrun_err);
 659        PRINT_STATS_LE32(cck, early_overrun_err);
 660        PRINT_STATS_LE32(cck, crc32_good);
 661        PRINT_STATS_LE32(cck, false_alarm_cnt);
 662        PRINT_STATS_LE32(cck, fina_sync_err_cnt);
 663        PRINT_STATS_LE32(cck, sfd_timeout);
 664        PRINT_STATS_LE32(cck, fina_timeout);
 665        PRINT_STATS_LE32(cck, unresponded_rts);
 666        PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun);
 667        PRINT_STATS_LE32(cck, sent_ack_cnt);
 668        PRINT_STATS_LE32(cck, sent_cts_cnt);
 669        PRINT_STATS_LE32(cck, sent_ba_rsp_cnt);
 670        PRINT_STATS_LE32(cck, dsp_self_kill);
 671        PRINT_STATS_LE32(cck, mh_format_err);
 672        PRINT_STATS_LE32(cck, re_acq_main_rssi_sum);
 673        PRINT_STATS_LE32(cck, reserved);
 674
 675        pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 676                         "Statistics_Rx - GENERAL");
 677        PRINT_STATS_LE32(general, bogus_cts);
 678        PRINT_STATS_LE32(general, bogus_ack);
 679        PRINT_STATS_LE32(general, non_bssid_frames);
 680        PRINT_STATS_LE32(general, filtered_frames);
 681        PRINT_STATS_LE32(general, non_channel_beacons);
 682        PRINT_STATS_LE32(general, channel_beacons);
 683        PRINT_STATS_LE32(general, num_missed_bcon);
 684        PRINT_STATS_LE32(general, adc_rx_saturation_time);
 685        PRINT_STATS_LE32(general, ina_detection_search_time);
 686        PRINT_STATS_LE32(general, beacon_silence_rssi_a);
 687        PRINT_STATS_LE32(general, beacon_silence_rssi_b);
 688        PRINT_STATS_LE32(general, beacon_silence_rssi_c);
 689        PRINT_STATS_LE32(general, interference_data_flag);
 690        PRINT_STATS_LE32(general, channel_load);
 691        PRINT_STATS_LE32(general, dsp_false_alarms);
 692        PRINT_STATS_LE32(general, beacon_rssi_a);
 693        PRINT_STATS_LE32(general, beacon_rssi_b);
 694        PRINT_STATS_LE32(general, beacon_rssi_c);
 695        PRINT_STATS_LE32(general, beacon_energy_a);
 696        PRINT_STATS_LE32(general, beacon_energy_b);
 697        PRINT_STATS_LE32(general, beacon_energy_c);
 698        PRINT_STATS_LE32(general, num_bt_kills);
 699        PRINT_STATS_LE32(general, mac_id);
 700        PRINT_STATS_LE32(general, directed_data_mpdu);
 701
 702        pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 703                         "Statistics_Rx - HT");
 704        PRINT_STATS_LE32(ht, plcp_err);
 705        PRINT_STATS_LE32(ht, overrun_err);
 706        PRINT_STATS_LE32(ht, early_overrun_err);
 707        PRINT_STATS_LE32(ht, crc32_good);
 708        PRINT_STATS_LE32(ht, crc32_err);
 709        PRINT_STATS_LE32(ht, mh_format_err);
 710        PRINT_STATS_LE32(ht, agg_crc32_good);
 711        PRINT_STATS_LE32(ht, agg_mpdu_cnt);
 712        PRINT_STATS_LE32(ht, agg_cnt);
 713        PRINT_STATS_LE32(ht, unsupport_mcs);
 714
 715        mutex_unlock(&mvm->mutex);
 716
 717        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 718        kfree(buf);
 719
 720        return ret;
 721}
 722#undef PRINT_STAT_LE32
 723
 724static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
 725                                          char __user *user_buf, size_t count,
 726                                          loff_t *ppos,
 727                                          struct iwl_mvm_frame_stats *stats)
 728{
 729        char *buff, *pos, *endpos;
 730        int idx, i;
 731        int ret;
 732        static const size_t bufsz = 1024;
 733
 734        buff = kmalloc(bufsz, GFP_KERNEL);
 735        if (!buff)
 736                return -ENOMEM;
 737
 738        spin_lock_bh(&mvm->drv_stats_lock);
 739
 740        pos = buff;
 741        endpos = pos + bufsz;
 742
 743        pos += scnprintf(pos, endpos - pos,
 744                         "Legacy/HT/VHT\t:\t%d/%d/%d\n",
 745                         stats->legacy_frames,
 746                         stats->ht_frames,
 747                         stats->vht_frames);
 748        pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n",
 749                         stats->bw_20_frames,
 750                         stats->bw_40_frames,
 751                         stats->bw_80_frames);
 752        pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n",
 753                         stats->ngi_frames,
 754                         stats->sgi_frames);
 755        pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n",
 756                         stats->siso_frames,
 757                         stats->mimo2_frames);
 758        pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n",
 759                         stats->fail_frames,
 760                         stats->success_frames);
 761        pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n",
 762                         stats->agg_frames);
 763        pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n",
 764                         stats->ampdu_count);
 765        pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n",
 766                         stats->ampdu_count > 0 ?
 767                         (stats->agg_frames / stats->ampdu_count) : 0);
 768
 769        pos += scnprintf(pos, endpos - pos, "Last Rates\n");
 770
 771        idx = stats->last_frame_idx - 1;
 772        for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) {
 773                idx = (idx + 1) % ARRAY_SIZE(stats->last_rates);
 774                if (stats->last_rates[idx] == 0)
 775                        continue;
 776                pos += scnprintf(pos, endpos - pos, "Rate[%d]: ",
 777                                 (int)(ARRAY_SIZE(stats->last_rates) - i));
 778                pos += rs_pretty_print_rate(pos, stats->last_rates[idx]);
 779        }
 780        spin_unlock_bh(&mvm->drv_stats_lock);
 781
 782        ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
 783        kfree(buff);
 784
 785        return ret;
 786}
 787
 788static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file,
 789                                           char __user *user_buf, size_t count,
 790                                           loff_t *ppos)
 791{
 792        struct iwl_mvm *mvm = file->private_data;
 793
 794        return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos,
 795                                          &mvm->drv_rx_stats);
 796}
 797
 798static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
 799                                          size_t count, loff_t *ppos)
 800{
 801        int ret;
 802
 803        mutex_lock(&mvm->mutex);
 804
 805        /* allow one more restart that we're provoking here */
 806        if (mvm->restart_fw >= 0)
 807                mvm->restart_fw++;
 808
 809        /* take the return value to make compiler happy - it will fail anyway */
 810        ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL);
 811
 812        mutex_unlock(&mvm->mutex);
 813
 814        return count;
 815}
 816
 817static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
 818                                      size_t count, loff_t *ppos)
 819{
 820        int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI);
 821        if (ret)
 822                return ret;
 823
 824        iwl_force_nmi(mvm->trans);
 825
 826        iwl_mvm_unref(mvm, IWL_MVM_REF_NMI);
 827
 828        return count;
 829}
 830
 831static ssize_t
 832iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
 833                                char __user *user_buf,
 834                                size_t count, loff_t *ppos)
 835{
 836        struct iwl_mvm *mvm = file->private_data;
 837        int pos = 0;
 838        char buf[32];
 839        const size_t bufsz = sizeof(buf);
 840
 841        /* print which antennas were set for the scan command by the user */
 842        pos += scnprintf(buf + pos, bufsz - pos, "Antennas for scan: ");
 843        if (mvm->scan_rx_ant & ANT_A)
 844                pos += scnprintf(buf + pos, bufsz - pos, "A");
 845        if (mvm->scan_rx_ant & ANT_B)
 846                pos += scnprintf(buf + pos, bufsz - pos, "B");
 847        if (mvm->scan_rx_ant & ANT_C)
 848                pos += scnprintf(buf + pos, bufsz - pos, "C");
 849        pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant);
 850
 851        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 852}
 853
 854static ssize_t
 855iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
 856                                 size_t count, loff_t *ppos)
 857{
 858        u8 scan_rx_ant;
 859
 860        if (sscanf(buf, "%hhx", &scan_rx_ant) != 1)
 861                return -EINVAL;
 862        if (scan_rx_ant > ANT_ABC)
 863                return -EINVAL;
 864        if (scan_rx_ant & ~(iwl_mvm_get_valid_rx_ant(mvm)))
 865                return -EINVAL;
 866
 867        if (mvm->scan_rx_ant != scan_rx_ant) {
 868                mvm->scan_rx_ant = scan_rx_ant;
 869                if (fw_has_capa(&mvm->fw->ucode_capa,
 870                                IWL_UCODE_TLV_CAPA_UMAC_SCAN))
 871                        iwl_mvm_config_scan(mvm);
 872        }
 873
 874        return count;
 875}
 876
 877static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
 878                                               char *buf, size_t count,
 879                                               loff_t *ppos)
 880{
 881        struct iwl_rss_config_cmd cmd = {
 882                .flags = cpu_to_le32(IWL_RSS_ENABLE),
 883                .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP |
 884                             IWL_RSS_HASH_TYPE_IPV4_UDP |
 885                             IWL_RSS_HASH_TYPE_IPV4_PAYLOAD |
 886                             IWL_RSS_HASH_TYPE_IPV6_TCP |
 887                             IWL_RSS_HASH_TYPE_IPV6_UDP |
 888                             IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
 889        };
 890        int ret, i, num_repeats, nbytes = count / 2;
 891
 892        ret = hex2bin(cmd.indirection_table, buf, nbytes);
 893        if (ret)
 894                return ret;
 895
 896        /*
 897         * The input is the redirection table, partial or full.
 898         * Repeat the pattern if needed.
 899         * For example, input of 01020F will be repeated 42 times,
 900         * indirecting RSS hash results to queues 1, 2, 15 (skipping
 901         * queues 3 - 14).
 902         */
 903        num_repeats = ARRAY_SIZE(cmd.indirection_table) / nbytes;
 904        for (i = 1; i < num_repeats; i++)
 905                memcpy(&cmd.indirection_table[i * nbytes],
 906                       cmd.indirection_table, nbytes);
 907        /* handle cut in the middle pattern for the last places */
 908        memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table,
 909               ARRAY_SIZE(cmd.indirection_table) % nbytes);
 910
 911        netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key));
 912
 913        mutex_lock(&mvm->mutex);
 914        ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd);
 915        mutex_unlock(&mvm->mutex);
 916
 917        return ret ?: count;
 918}
 919
 920static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
 921                                          char __user *user_buf,
 922                                          size_t count, loff_t *ppos)
 923{
 924        struct iwl_mvm *mvm = file->private_data;
 925        int conf;
 926        char buf[8];
 927        const size_t bufsz = sizeof(buf);
 928        int pos = 0;
 929
 930        mutex_lock(&mvm->mutex);
 931        conf = mvm->fw_dbg_conf;
 932        mutex_unlock(&mvm->mutex);
 933
 934        pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf);
 935
 936        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 937}
 938
 939/*
 940 * Enable / Disable continuous recording.
 941 * Cause the FW to start continuous recording, by sending the relevant hcmd.
 942 * Enable: input of every integer larger than 0, ENABLE_CONT_RECORDING.
 943 * Disable: for 0 as input, DISABLE_CONT_RECORDING.
 944 */
 945static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
 946                                              char *buf, size_t count,
 947                                              loff_t *ppos)
 948{
 949        struct iwl_trans *trans = mvm->trans;
 950        const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv;
 951        struct iwl_continuous_record_cmd cont_rec = {};
 952        int ret, rec_mode;
 953
 954        if (!dest)
 955                return -EOPNOTSUPP;
 956
 957        if (dest->monitor_mode != SMEM_MODE ||
 958            trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
 959                return -EOPNOTSUPP;
 960
 961        ret = kstrtoint(buf, 0, &rec_mode);
 962        if (ret)
 963                return ret;
 964
 965        cont_rec.record_mode.enable_recording = rec_mode ?
 966                cpu_to_le16(ENABLE_CONT_RECORDING) :
 967                cpu_to_le16(DISABLE_CONT_RECORDING);
 968
 969        mutex_lock(&mvm->mutex);
 970        ret = iwl_mvm_send_cmd_pdu(mvm, LDBG_CONFIG_CMD, 0,
 971                                   sizeof(cont_rec), &cont_rec);
 972        mutex_unlock(&mvm->mutex);
 973
 974        return ret ?: count;
 975}
 976
 977static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,
 978                                           char *buf, size_t count,
 979                                           loff_t *ppos)
 980{
 981        unsigned int conf_id;
 982        int ret;
 983
 984        ret = kstrtouint(buf, 0, &conf_id);
 985        if (ret)
 986                return ret;
 987
 988        if (WARN_ON(conf_id >= FW_DBG_CONF_MAX))
 989                return -EINVAL;
 990
 991        mutex_lock(&mvm->mutex);
 992        ret = iwl_mvm_start_fw_dbg_conf(mvm, conf_id);
 993        mutex_unlock(&mvm->mutex);
 994
 995        return ret ?: count;
 996}
 997
 998static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
 999                                              char *buf, size_t count,
1000                                              loff_t *ppos)
1001{
1002        int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
1003
1004        if (ret)
1005                return ret;
1006
1007        iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, buf,
1008                               (count - 1), NULL);
1009
1010        iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
1011
1012        return count;
1013}
1014
1015static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm,
1016                                             char *buf, size_t count,
1017                                             loff_t *ppos)
1018{
1019        unsigned int max_amsdu_len;
1020        int ret;
1021
1022        ret = kstrtouint(buf, 0, &max_amsdu_len);
1023        if (ret)
1024                return ret;
1025
1026        if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454)
1027                return -EINVAL;
1028        mvm->max_amsdu_len = max_amsdu_len;
1029
1030        return count;
1031}
1032
1033#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
1034#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1035static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
1036                                            char __user *user_buf,
1037                                            size_t count, loff_t *ppos)
1038{
1039        struct iwl_mvm *mvm = file->private_data;
1040        struct iwl_bcast_filter_cmd cmd;
1041        const struct iwl_fw_bcast_filter *filter;
1042        char *buf;
1043        int bufsz = 1024;
1044        int i, j, pos = 0;
1045        ssize_t ret;
1046
1047        buf = kzalloc(bufsz, GFP_KERNEL);
1048        if (!buf)
1049                return -ENOMEM;
1050
1051        mutex_lock(&mvm->mutex);
1052        if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
1053                ADD_TEXT("None\n");
1054                mutex_unlock(&mvm->mutex);
1055                goto out;
1056        }
1057        mutex_unlock(&mvm->mutex);
1058
1059        for (i = 0; cmd.filters[i].attrs[0].mask; i++) {
1060                filter = &cmd.filters[i];
1061
1062                ADD_TEXT("Filter [%d]:\n", i);
1063                ADD_TEXT("\tDiscard=%d\n", filter->discard);
1064                ADD_TEXT("\tFrame Type: %s\n",
1065                         filter->frame_type ? "IPv4" : "Generic");
1066
1067                for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) {
1068                        const struct iwl_fw_bcast_filter_attr *attr;
1069
1070                        attr = &filter->attrs[j];
1071                        if (!attr->mask)
1072                                break;
1073
1074                        ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n",
1075                                 j, attr->offset,
1076                                 attr->offset_type ? "IP End" :
1077                                                     "Payload Start",
1078                                 be32_to_cpu(attr->mask),
1079                                 be32_to_cpu(attr->val),
1080                                 le16_to_cpu(attr->reserved1));
1081                }
1082        }
1083out:
1084        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1085        kfree(buf);
1086        return ret;
1087}
1088
1089static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf,
1090                                             size_t count, loff_t *ppos)
1091{
1092        int pos, next_pos;
1093        struct iwl_fw_bcast_filter filter = {};
1094        struct iwl_bcast_filter_cmd cmd;
1095        u32 filter_id, attr_id, mask, value;
1096        int err = 0;
1097
1098        if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard,
1099                   &filter.frame_type, &pos) != 3)
1100                return -EINVAL;
1101
1102        if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) ||
1103            filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4)
1104                return -EINVAL;
1105
1106        for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs);
1107             attr_id++) {
1108                struct iwl_fw_bcast_filter_attr *attr =
1109                                &filter.attrs[attr_id];
1110
1111                if (pos >= count)
1112                        break;
1113
1114                if (sscanf(&buf[pos], "%hhi %hhi %i %i %n",
1115                           &attr->offset, &attr->offset_type,
1116                           &mask, &value, &next_pos) != 4)
1117                        return -EINVAL;
1118
1119                attr->mask = cpu_to_be32(mask);
1120                attr->val = cpu_to_be32(value);
1121                if (mask)
1122                        filter.num_attrs++;
1123
1124                pos += next_pos;
1125        }
1126
1127        mutex_lock(&mvm->mutex);
1128        memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id],
1129               &filter, sizeof(filter));
1130
1131        /* send updated bcast filtering configuration */
1132        if (mvm->dbgfs_bcast_filtering.override &&
1133            iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
1134                err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
1135                                           sizeof(cmd), &cmd);
1136        mutex_unlock(&mvm->mutex);
1137
1138        return err ?: count;
1139}
1140
1141static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file,
1142                                                 char __user *user_buf,
1143                                                 size_t count, loff_t *ppos)
1144{
1145        struct iwl_mvm *mvm = file->private_data;
1146        struct iwl_bcast_filter_cmd cmd;
1147        char *buf;
1148        int bufsz = 1024;
1149        int i, pos = 0;
1150        ssize_t ret;
1151
1152        buf = kzalloc(bufsz, GFP_KERNEL);
1153        if (!buf)
1154                return -ENOMEM;
1155
1156        mutex_lock(&mvm->mutex);
1157        if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
1158                ADD_TEXT("None\n");
1159                mutex_unlock(&mvm->mutex);
1160                goto out;
1161        }
1162        mutex_unlock(&mvm->mutex);
1163
1164        for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) {
1165                const struct iwl_fw_bcast_mac *mac = &cmd.macs[i];
1166
1167                ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n",
1168                         i, mac->default_discard, mac->attached_filters);
1169        }
1170out:
1171        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1172        kfree(buf);
1173        return ret;
1174}
1175
1176static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
1177                                                  char *buf, size_t count,
1178                                                  loff_t *ppos)
1179{
1180        struct iwl_bcast_filter_cmd cmd;
1181        struct iwl_fw_bcast_mac mac = {};
1182        u32 mac_id, attached_filters;
1183        int err = 0;
1184
1185        if (!mvm->bcast_filters)
1186                return -ENOENT;
1187
1188        if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard,
1189                   &attached_filters) != 3)
1190                return -EINVAL;
1191
1192        if (mac_id >= ARRAY_SIZE(cmd.macs) ||
1193            mac.default_discard > 1 ||
1194            attached_filters >= BIT(ARRAY_SIZE(cmd.filters)))
1195                return -EINVAL;
1196
1197        mac.attached_filters = cpu_to_le16(attached_filters);
1198
1199        mutex_lock(&mvm->mutex);
1200        memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id],
1201               &mac, sizeof(mac));
1202
1203        /* send updated bcast filtering configuration */
1204        if (mvm->dbgfs_bcast_filtering.override &&
1205            iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
1206                err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
1207                                           sizeof(cmd), &cmd);
1208        mutex_unlock(&mvm->mutex);
1209
1210        return err ?: count;
1211}
1212#endif
1213
1214#ifdef CONFIG_PM_SLEEP
1215static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf,
1216                                       size_t count, loff_t *ppos)
1217{
1218        int store;
1219
1220        if (sscanf(buf, "%d", &store) != 1)
1221                return -EINVAL;
1222
1223        mvm->store_d3_resume_sram = store;
1224
1225        return count;
1226}
1227
1228static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
1229                                      size_t count, loff_t *ppos)
1230{
1231        struct iwl_mvm *mvm = file->private_data;
1232        const struct fw_img *img;
1233        int ofs, len, pos = 0;
1234        size_t bufsz, ret;
1235        char *buf;
1236        u8 *ptr = mvm->d3_resume_sram;
1237
1238        img = &mvm->fw->img[IWL_UCODE_WOWLAN];
1239        len = img->sec[IWL_UCODE_SECTION_DATA].len;
1240
1241        bufsz = len * 4 + 256;
1242        buf = kzalloc(bufsz, GFP_KERNEL);
1243        if (!buf)
1244                return -ENOMEM;
1245
1246        pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n",
1247                         mvm->store_d3_resume_sram ? "en" : "dis");
1248
1249        if (ptr) {
1250                for (ofs = 0; ofs < len; ofs += 16) {
1251                        pos += scnprintf(buf + pos, bufsz - pos,
1252                                         "0x%.4x %16ph\n", ofs, ptr + ofs);
1253                }
1254        } else {
1255                pos += scnprintf(buf + pos, bufsz - pos,
1256                                 "(no data captured)\n");
1257        }
1258
1259        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1260
1261        kfree(buf);
1262
1263        return ret;
1264}
1265#endif
1266
1267#define PRINT_MVM_REF(ref) do {                                         \
1268        if (mvm->refs[ref])                                             \
1269                pos += scnprintf(buf + pos, bufsz - pos,                \
1270                                 "\t(0x%lx): %d %s\n",                  \
1271                                 BIT(ref), mvm->refs[ref], #ref);       \
1272} while (0)
1273
1274static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
1275                                        char __user *user_buf,
1276                                        size_t count, loff_t *ppos)
1277{
1278        struct iwl_mvm *mvm = file->private_data;
1279        int i, pos = 0;
1280        char buf[256];
1281        const size_t bufsz = sizeof(buf);
1282        u32 refs = 0;
1283
1284        for (i = 0; i < IWL_MVM_REF_COUNT; i++)
1285                if (mvm->refs[i])
1286                        refs |= BIT(i);
1287
1288        pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%x\n",
1289                         refs);
1290
1291        PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
1292        PRINT_MVM_REF(IWL_MVM_REF_SCAN);
1293        PRINT_MVM_REF(IWL_MVM_REF_ROC);
1294        PRINT_MVM_REF(IWL_MVM_REF_ROC_AUX);
1295        PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
1296        PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
1297        PRINT_MVM_REF(IWL_MVM_REF_USER);
1298        PRINT_MVM_REF(IWL_MVM_REF_TX);
1299        PRINT_MVM_REF(IWL_MVM_REF_TX_AGG);
1300        PRINT_MVM_REF(IWL_MVM_REF_ADD_IF);
1301        PRINT_MVM_REF(IWL_MVM_REF_START_AP);
1302        PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED);
1303        PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX);
1304        PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS);
1305        PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL);
1306        PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ);
1307        PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE);
1308        PRINT_MVM_REF(IWL_MVM_REF_NMI);
1309        PRINT_MVM_REF(IWL_MVM_REF_TM_CMD);
1310        PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
1311        PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA);
1312        PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT);
1313        PRINT_MVM_REF(IWL_MVM_REF_INIT_UCODE);
1314        PRINT_MVM_REF(IWL_MVM_REF_SENDING_CMD);
1315        PRINT_MVM_REF(IWL_MVM_REF_RX);
1316
1317        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1318}
1319
1320static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
1321                                         size_t count, loff_t *ppos)
1322{
1323        unsigned long value;
1324        int ret;
1325        bool taken;
1326
1327        ret = kstrtoul(buf, 10, &value);
1328        if (ret < 0)
1329                return ret;
1330
1331        mutex_lock(&mvm->mutex);
1332
1333        taken = mvm->refs[IWL_MVM_REF_USER];
1334        if (value == 1 && !taken)
1335                iwl_mvm_ref(mvm, IWL_MVM_REF_USER);
1336        else if (value == 0 && taken)
1337                iwl_mvm_unref(mvm, IWL_MVM_REF_USER);
1338        else
1339                ret = -EINVAL;
1340
1341        mutex_unlock(&mvm->mutex);
1342
1343        if (ret < 0)
1344                return ret;
1345        return count;
1346}
1347
1348#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1349        _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
1350#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1351        _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
1352#define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do {      \
1353                if (!debugfs_create_file(alias, mode, parent, mvm,      \
1354                                         &iwl_dbgfs_##name##_ops))      \
1355                        goto err;                                       \
1356        } while (0)
1357#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
1358        MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
1359
1360static ssize_t
1361iwl_dbgfs_prph_reg_read(struct file *file,
1362                        char __user *user_buf,
1363                        size_t count, loff_t *ppos)
1364{
1365        struct iwl_mvm *mvm = file->private_data;
1366        int pos = 0;
1367        char buf[32];
1368        const size_t bufsz = sizeof(buf);
1369        int ret;
1370
1371        if (!mvm->dbgfs_prph_reg_addr)
1372                return -EINVAL;
1373
1374        ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_READ);
1375        if (ret)
1376                return ret;
1377
1378        pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
1379                mvm->dbgfs_prph_reg_addr,
1380                iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
1381
1382        iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_READ);
1383
1384        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1385}
1386
1387static ssize_t
1388iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
1389                         size_t count, loff_t *ppos)
1390{
1391        u8 args;
1392        u32 value;
1393        int ret;
1394
1395        args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
1396        /* if we only want to set the reg address - nothing more to do */
1397        if (args == 1)
1398                goto out;
1399
1400        /* otherwise, make sure we have both address and value */
1401        if (args != 2)
1402                return -EINVAL;
1403
1404        ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
1405        if (ret)
1406                return ret;
1407
1408        iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
1409
1410        iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
1411out:
1412        return count;
1413}
1414
1415static ssize_t
1416iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf,
1417                              size_t count, loff_t *ppos)
1418{
1419        int ret;
1420
1421        mutex_lock(&mvm->mutex);
1422        ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL);
1423        mutex_unlock(&mvm->mutex);
1424
1425        return ret ?: count;
1426}
1427
1428MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
1429
1430/* Device wide debugfs entries */
1431MVM_DEBUGFS_READ_FILE_OPS(ctdp_budget);
1432MVM_DEBUGFS_WRITE_FILE_OPS(stop_ctdp, 8);
1433MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
1434MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
1435MVM_DEBUGFS_WRITE_FILE_OPS(send_echo_cmd, 8);
1436MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
1437MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64);
1438MVM_DEBUGFS_READ_FILE_OPS(nic_temp);
1439MVM_DEBUGFS_READ_FILE_OPS(stations);
1440MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
1441MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
1442MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
1443MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
1444MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
1445MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
1446MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
1447MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
1448MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
1449MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
1450MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
1451MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
1452MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
1453MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8);
1454MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8);
1455MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
1456                           (IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
1457
1458#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1459MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
1460MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
1461#endif
1462
1463#ifdef CONFIG_PM_SLEEP
1464MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
1465#endif
1466
1467int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
1468{
1469        struct dentry *bcast_dir __maybe_unused;
1470        char buf[100];
1471
1472        spin_lock_init(&mvm->drv_stats_lock);
1473
1474        mvm->debugfs_dir = dbgfs_dir;
1475
1476        MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
1477        MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
1478        MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
1479        MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir,
1480                             S_IWUSR | S_IRUSR);
1481        MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
1482        MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, S_IRUSR);
1483        MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, S_IWUSR);
1484        MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
1485        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
1486        MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
1487        MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
1488                             S_IRUSR | S_IWUSR);
1489        MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
1490        MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
1491        MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
1492        MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
1493        MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR);
1494        MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, S_IWUSR);
1495        MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
1496                             S_IWUSR | S_IRUSR);
1497        MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
1498        MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
1499        MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
1500        MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
1501        MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, S_IWUSR);
1502        MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR);
1503        MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR);
1504        MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR);
1505        if (!debugfs_create_bool("enable_scan_iteration_notif",
1506                                 S_IRUSR | S_IWUSR,
1507                                 mvm->debugfs_dir,
1508                                 &mvm->scan_iter_notif_enabled))
1509                goto err;
1510        if (!debugfs_create_bool("drop_bcn_ap_mode", S_IRUSR | S_IWUSR,
1511                                 mvm->debugfs_dir, &mvm->drop_bcn_ap_mode))
1512                goto err;
1513
1514#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1515        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
1516                bcast_dir = debugfs_create_dir("bcast_filtering",
1517                                               mvm->debugfs_dir);
1518                if (!bcast_dir)
1519                        goto err;
1520
1521                if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR,
1522                                bcast_dir,
1523                                &mvm->dbgfs_bcast_filtering.override))
1524                        goto err;
1525
1526                MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters,
1527                                           bcast_dir, S_IWUSR | S_IRUSR);
1528                MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs,
1529                                           bcast_dir, S_IWUSR | S_IRUSR);
1530        }
1531#endif
1532
1533#ifdef CONFIG_PM_SLEEP
1534        MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
1535        MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
1536        if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
1537                                 mvm->debugfs_dir, &mvm->d3_wake_sysassert))
1538                goto err;
1539        if (!debugfs_create_u32("last_netdetect_scans", S_IRUSR,
1540                                mvm->debugfs_dir, &mvm->last_netdetect_scans))
1541                goto err;
1542#endif
1543
1544        if (!debugfs_create_u8("ps_disabled", S_IRUSR,
1545                               mvm->debugfs_dir, &mvm->ps_disabled))
1546                goto err;
1547        if (!debugfs_create_blob("nvm_hw", S_IRUSR,
1548                                  mvm->debugfs_dir, &mvm->nvm_hw_blob))
1549                goto err;
1550        if (!debugfs_create_blob("nvm_sw", S_IRUSR,
1551                                  mvm->debugfs_dir, &mvm->nvm_sw_blob))
1552                goto err;
1553        if (!debugfs_create_blob("nvm_calib", S_IRUSR,
1554                                  mvm->debugfs_dir, &mvm->nvm_calib_blob))
1555                goto err;
1556        if (!debugfs_create_blob("nvm_prod", S_IRUSR,
1557                                  mvm->debugfs_dir, &mvm->nvm_prod_blob))
1558                goto err;
1559        if (!debugfs_create_blob("nvm_phy_sku", S_IRUSR,
1560                                 mvm->debugfs_dir, &mvm->nvm_phy_sku_blob))
1561                goto err;
1562
1563        /*
1564         * Create a symlink with mac80211. It will be removed when mac80211
1565         * exists (before the opmode exists which removes the target.)
1566         */
1567        snprintf(buf, 100, "../../%s/%s",
1568                 dbgfs_dir->d_parent->d_parent->d_name.name,
1569                 dbgfs_dir->d_parent->d_name.name);
1570        if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
1571                goto err;
1572
1573        return 0;
1574err:
1575        IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
1576        return -ENOMEM;
1577}
1578