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 - 2017 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 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
  38 * All rights reserved.
  39 *
  40 * Redistribution and use in source and binary forms, with or without
  41 * modification, are permitted provided that the following conditions
  42 * are met:
  43 *
  44 *  * Redistributions of source code must retain the above copyright
  45 *    notice, this list of conditions and the following disclaimer.
  46 *  * Redistributions in binary form must reproduce the above copyright
  47 *    notice, this list of conditions and the following disclaimer in
  48 *    the documentation and/or other materials provided with the
  49 *    distribution.
  50 *  * Neither the name Intel Corporation nor the names of its
  51 *    contributors may be used to endorse or promote products derived
  52 *    from this software without specific prior written permission.
  53 *
  54 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  55 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  56 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  57 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  58 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  59 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  60 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  61 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  62 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  63 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  64 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  65 *
  66 *****************************************************************************/
  67#include <linux/vmalloc.h>
  68#include <linux/ieee80211.h>
  69#include <linux/netdevice.h>
  70
  71#include "mvm.h"
  72#include "sta.h"
  73#include "iwl-io.h"
  74#include "debugfs.h"
  75#include "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 (!iwl_mvm_is_ctdp_supported(mvm))
  86                return -EOPNOTSUPP;
  87
  88        if (!iwl_mvm_firmware_running(mvm) ||
  89            mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
  90                return -EIO;
  91
  92        mutex_lock(&mvm->mutex);
  93        budget = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_REPORT, 0);
  94        mutex_unlock(&mvm->mutex);
  95
  96        if (budget < 0)
  97                return budget;
  98
  99        pos = scnprintf(buf, sizeof(buf), "%d\n", budget);
 100
 101        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 102}
 103
 104static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf,
 105                                         size_t count, loff_t *ppos)
 106{
 107        int ret;
 108
 109        if (!iwl_mvm_is_ctdp_supported(mvm))
 110                return -EOPNOTSUPP;
 111
 112        if (!iwl_mvm_firmware_running(mvm) ||
 113            mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
 114                return -EIO;
 115
 116        mutex_lock(&mvm->mutex);
 117        ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_STOP, 0);
 118        mutex_unlock(&mvm->mutex);
 119
 120        return ret ?: count;
 121}
 122
 123static ssize_t iwl_dbgfs_force_ctkill_write(struct iwl_mvm *mvm, char *buf,
 124                                            size_t count, loff_t *ppos)
 125{
 126        if (!iwl_mvm_firmware_running(mvm) ||
 127            mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
 128                return -EIO;
 129
 130        iwl_mvm_enter_ctkill(mvm);
 131
 132        return count;
 133}
 134
 135static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
 136                                        size_t count, loff_t *ppos)
 137{
 138        int ret;
 139        u32 flush_arg;
 140
 141        if (!iwl_mvm_firmware_running(mvm) ||
 142            mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
 143                return -EIO;
 144
 145        if (kstrtou32(buf, 0, &flush_arg))
 146                return -EINVAL;
 147
 148        if (iwl_mvm_has_new_tx_api(mvm)) {
 149                IWL_DEBUG_TX_QUEUES(mvm,
 150                                    "FLUSHING all tids queues on sta_id = %d\n",
 151                                    flush_arg);
 152                mutex_lock(&mvm->mutex);
 153                ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFF, 0) ? : count;
 154                mutex_unlock(&mvm->mutex);
 155                return ret;
 156        }
 157
 158        IWL_DEBUG_TX_QUEUES(mvm, "FLUSHING queues mask to flush = 0x%x\n",
 159                            flush_arg);
 160
 161        mutex_lock(&mvm->mutex);
 162        ret =  iwl_mvm_flush_tx_path(mvm, flush_arg, 0) ? : count;
 163        mutex_unlock(&mvm->mutex);
 164
 165        return ret;
 166}
 167
 168static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
 169                                         size_t count, loff_t *ppos)
 170{
 171        struct iwl_mvm_sta *mvmsta;
 172        int sta_id, drain, ret;
 173
 174        if (!iwl_mvm_firmware_running(mvm) ||
 175            mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
 176                return -EIO;
 177
 178        if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
 179                return -EINVAL;
 180        if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT)
 181                return -EINVAL;
 182        if (drain < 0 || drain > 1)
 183                return -EINVAL;
 184
 185        mutex_lock(&mvm->mutex);
 186
 187        mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
 188
 189        if (!mvmsta)
 190                ret = -ENOENT;
 191        else
 192                ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count;
 193
 194        mutex_unlock(&mvm->mutex);
 195
 196        return ret;
 197}
 198
 199static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
 200                                   size_t count, loff_t *ppos)
 201{
 202        struct iwl_mvm *mvm = file->private_data;
 203        const struct fw_img *img;
 204        unsigned int ofs, len;
 205        size_t ret;
 206        u8 *ptr;
 207
 208        if (!iwl_mvm_firmware_running(mvm))
 209                return -EINVAL;
 210
 211        /* default is to dump the entire data segment */
 212        img = &mvm->fw->img[mvm->fwrt.cur_fw_img];
 213        ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
 214        len = img->sec[IWL_UCODE_SECTION_DATA].len;
 215
 216        if (mvm->dbgfs_sram_len) {
 217                ofs = mvm->dbgfs_sram_offset;
 218                len = mvm->dbgfs_sram_len;
 219        }
 220
 221        ptr = kzalloc(len, GFP_KERNEL);
 222        if (!ptr)
 223                return -ENOMEM;
 224
 225        iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len);
 226
 227        ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len);
 228
 229        kfree(ptr);
 230
 231        return ret;
 232}
 233
 234static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
 235                                    size_t count, loff_t *ppos)
 236{
 237        const struct fw_img *img;
 238        u32 offset, len;
 239        u32 img_offset, img_len;
 240
 241        if (!iwl_mvm_firmware_running(mvm))
 242                return -EINVAL;
 243
 244        img = &mvm->fw->img[mvm->fwrt.cur_fw_img];
 245        img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset;
 246        img_len = img->sec[IWL_UCODE_SECTION_DATA].len;
 247
 248        if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
 249                if ((offset & 0x3) || (len & 0x3))
 250                        return -EINVAL;
 251
 252                if (offset + len > img_offset + img_len)
 253                        return -EINVAL;
 254
 255                mvm->dbgfs_sram_offset = offset;
 256                mvm->dbgfs_sram_len = len;
 257        } else {
 258                mvm->dbgfs_sram_offset = 0;
 259                mvm->dbgfs_sram_len = 0;
 260        }
 261
 262        return count;
 263}
 264
 265static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file,
 266                                                  char __user *user_buf,
 267                                                  size_t count, loff_t *ppos)
 268{
 269        struct iwl_mvm *mvm = file->private_data;
 270        char buf[16];
 271        int pos;
 272
 273        if (!mvm->temperature_test)
 274                pos = scnprintf(buf , sizeof(buf), "disabled\n");
 275        else
 276                pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature);
 277
 278        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 279}
 280
 281/*
 282 * Set NIC Temperature
 283 * Cause the driver to ignore the actual NIC temperature reported by the FW
 284 * Enable: any value between IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -
 285 * IWL_MVM_DEBUG_SET_TEMPERATURE_MAX
 286 * Disable: IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE
 287 */
 288static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
 289                                                   char *buf, size_t count,
 290                                                   loff_t *ppos)
 291{
 292        int temperature;
 293
 294        if (!iwl_mvm_firmware_running(mvm) && !mvm->temperature_test)
 295                return -EIO;
 296
 297        if (kstrtoint(buf, 10, &temperature))
 298                return -EINVAL;
 299        /* not a legal temperature */
 300        if ((temperature > IWL_MVM_DEBUG_SET_TEMPERATURE_MAX &&
 301             temperature != IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) ||
 302            temperature < IWL_MVM_DEBUG_SET_TEMPERATURE_MIN)
 303                return -EINVAL;
 304
 305        mutex_lock(&mvm->mutex);
 306        if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) {
 307                if (!mvm->temperature_test)
 308                        goto out;
 309
 310                mvm->temperature_test = false;
 311                /* Since we can't read the temp while awake, just set
 312                 * it to zero until we get the next RX stats from the
 313                 * firmware.
 314                 */
 315                mvm->temperature = 0;
 316        } else {
 317                mvm->temperature_test = true;
 318                mvm->temperature = temperature;
 319        }
 320        IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n",
 321                       mvm->temperature_test ? "En" : "Dis" ,
 322                       mvm->temperature);
 323        /* handle the temperature change */
 324        iwl_mvm_tt_handler(mvm);
 325
 326out:
 327        mutex_unlock(&mvm->mutex);
 328
 329        return count;
 330}
 331
 332static ssize_t iwl_dbgfs_nic_temp_read(struct file *file,
 333                                       char __user *user_buf,
 334                                       size_t count, loff_t *ppos)
 335{
 336        struct iwl_mvm *mvm = file->private_data;
 337        char buf[16];
 338        int pos, ret;
 339        s32 temp;
 340
 341        if (!iwl_mvm_firmware_running(mvm))
 342                return -EIO;
 343
 344        mutex_lock(&mvm->mutex);
 345        ret = iwl_mvm_get_temp(mvm, &temp);
 346        mutex_unlock(&mvm->mutex);
 347
 348        if (ret)
 349                return -EIO;
 350
 351        pos = scnprintf(buf , sizeof(buf), "%d\n", temp);
 352
 353        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 354}
 355
 356#ifdef CONFIG_ACPI
 357static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file,
 358                                              char __user *user_buf,
 359                                              size_t count, loff_t *ppos)
 360{
 361        struct iwl_mvm *mvm = file->private_data;
 362        char buf[256];
 363        int pos = 0;
 364        int bufsz = sizeof(buf);
 365        int tbl_idx;
 366        u8 *value;
 367
 368        if (!iwl_mvm_firmware_running(mvm))
 369                return -EIO;
 370
 371        mutex_lock(&mvm->mutex);
 372        tbl_idx = iwl_mvm_get_sar_geo_profile(mvm);
 373        if (tbl_idx < 0) {
 374                mutex_unlock(&mvm->mutex);
 375                return tbl_idx;
 376        }
 377
 378        if (!tbl_idx) {
 379                pos = scnprintf(buf, bufsz,
 380                                "SAR geographic profile disabled\n");
 381        } else {
 382                value = &mvm->geo_profiles[tbl_idx - 1].values[0];
 383
 384                pos += scnprintf(buf + pos, bufsz - pos,
 385                                 "Use geographic profile %d\n", tbl_idx);
 386                pos += scnprintf(buf + pos, bufsz - pos,
 387                                 "2.4GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n",
 388                                 value[1], value[2], value[0]);
 389                pos += scnprintf(buf + pos, bufsz - pos,
 390                                 "5.2GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n",
 391                                 value[4], value[5], value[3]);
 392        }
 393        mutex_unlock(&mvm->mutex);
 394
 395        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 396}
 397#endif
 398
 399static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
 400                                       size_t count, loff_t *ppos)
 401{
 402        struct iwl_mvm *mvm = file->private_data;
 403        struct ieee80211_sta *sta;
 404        char buf[400];
 405        int i, pos = 0, bufsz = sizeof(buf);
 406
 407        mutex_lock(&mvm->mutex);
 408
 409        for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
 410                pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
 411                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
 412                                                lockdep_is_held(&mvm->mutex));
 413                if (!sta)
 414                        pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
 415                else if (IS_ERR(sta))
 416                        pos += scnprintf(buf + pos, bufsz - pos, "%ld\n",
 417                                         PTR_ERR(sta));
 418                else
 419                        pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
 420                                         sta->addr);
 421        }
 422
 423        mutex_unlock(&mvm->mutex);
 424
 425        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 426}
 427
 428static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
 429                                                char __user *user_buf,
 430                                                size_t count, loff_t *ppos)
 431{
 432        struct iwl_mvm *mvm = file->private_data;
 433        char buf[64];
 434        int bufsz = sizeof(buf);
 435        int pos = 0;
 436
 437        pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d0=%d\n",
 438                         mvm->disable_power_off);
 439        pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d3=%d\n",
 440                         mvm->disable_power_off_d3);
 441
 442        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 443}
 444
 445static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,
 446                                                 size_t count, loff_t *ppos)
 447{
 448        int ret, val;
 449
 450        if (!iwl_mvm_firmware_running(mvm))
 451                return -EIO;
 452
 453        if (!strncmp("disable_power_off_d0=", buf, 21)) {
 454                if (sscanf(buf + 21, "%d", &val) != 1)
 455                        return -EINVAL;
 456                mvm->disable_power_off = val;
 457        } else if (!strncmp("disable_power_off_d3=", buf, 21)) {
 458                if (sscanf(buf + 21, "%d", &val) != 1)
 459                        return -EINVAL;
 460                mvm->disable_power_off_d3 = val;
 461        } else {
 462                return -EINVAL;
 463        }
 464
 465        mutex_lock(&mvm->mutex);
 466        ret = iwl_mvm_power_update_device(mvm);
 467        mutex_unlock(&mvm->mutex);
 468
 469        return ret ?: count;
 470}
 471
 472static
 473int iwl_mvm_coex_dump_mbox(struct iwl_mvm *mvm,
 474                           struct iwl_bt_coex_profile_notif *notif, char *buf,
 475                           int pos, int bufsz)
 476{
 477        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
 478
 479        BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
 480        BT_MBOX_PRINT(0, LE_PROF1, false);
 481        BT_MBOX_PRINT(0, LE_PROF2, false);
 482        BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
 483        BT_MBOX_PRINT(0, CHL_SEQ_N, false);
 484        BT_MBOX_PRINT(0, INBAND_S, false);
 485        BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
 486        BT_MBOX_PRINT(0, LE_SCAN, false);
 487        BT_MBOX_PRINT(0, LE_ADV, false);
 488        BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
 489        BT_MBOX_PRINT(0, OPEN_CON_1, true);
 490
 491        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
 492
 493        BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
 494        BT_MBOX_PRINT(1, IP_SR, false);
 495        BT_MBOX_PRINT(1, LE_MSTR, false);
 496        BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
 497        BT_MBOX_PRINT(1, MSG_TYPE, false);
 498        BT_MBOX_PRINT(1, SSN, true);
 499
 500        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
 501
 502        BT_MBOX_PRINT(2, SNIFF_ACT, false);
 503        BT_MBOX_PRINT(2, PAG, false);
 504        BT_MBOX_PRINT(2, INQUIRY, false);
 505        BT_MBOX_PRINT(2, CONN, false);
 506        BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
 507        BT_MBOX_PRINT(2, DISC, false);
 508        BT_MBOX_PRINT(2, SCO_TX_ACT, false);
 509        BT_MBOX_PRINT(2, SCO_RX_ACT, false);
 510        BT_MBOX_PRINT(2, ESCO_RE_TX, false);
 511        BT_MBOX_PRINT(2, SCO_DURATION, true);
 512
 513        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
 514
 515        BT_MBOX_PRINT(3, SCO_STATE, false);
 516        BT_MBOX_PRINT(3, SNIFF_STATE, false);
 517        BT_MBOX_PRINT(3, A2DP_STATE, false);
 518        BT_MBOX_PRINT(3, A2DP_SRC, false);
 519        BT_MBOX_PRINT(3, ACL_STATE, false);
 520        BT_MBOX_PRINT(3, MSTR_STATE, false);
 521        BT_MBOX_PRINT(3, OBX_STATE, false);
 522        BT_MBOX_PRINT(3, OPEN_CON_2, false);
 523        BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
 524        BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
 525        BT_MBOX_PRINT(3, INBAND_P, false);
 526        BT_MBOX_PRINT(3, MSG_TYPE_2, false);
 527        BT_MBOX_PRINT(3, SSN_2, false);
 528        BT_MBOX_PRINT(3, UPDATE_REQUEST, !iwl_mvm_has_new_ats_coex_api(mvm));
 529
 530        if (iwl_mvm_has_new_ats_coex_api(mvm)) {
 531                BT_MBOX_PRINT(4, ATS_BT_INTERVAL, false);
 532                BT_MBOX_PRINT(4, ATS_BT_ACTIVE_MAX_TH, true);
 533        }
 534
 535        return pos;
 536}
 537
 538static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
 539                                       size_t count, loff_t *ppos)
 540{
 541        struct iwl_mvm *mvm = file->private_data;
 542        struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
 543        char *buf;
 544        int ret, pos = 0, bufsz = sizeof(char) * 1024;
 545
 546        buf = kmalloc(bufsz, GFP_KERNEL);
 547        if (!buf)
 548                return -ENOMEM;
 549
 550        mutex_lock(&mvm->mutex);
 551
 552        pos += iwl_mvm_coex_dump_mbox(mvm, notif, buf, pos, bufsz);
 553
 554        pos += scnprintf(buf + pos, bufsz - pos, "bt_ci_compliance = %d\n",
 555                         notif->bt_ci_compliance);
 556        pos += scnprintf(buf + pos, bufsz - pos, "primary_ch_lut = %d\n",
 557                         le32_to_cpu(notif->primary_ch_lut));
 558        pos += scnprintf(buf + pos, bufsz - pos, "secondary_ch_lut = %d\n",
 559                         le32_to_cpu(notif->secondary_ch_lut));
 560        pos += scnprintf(buf + pos,
 561                         bufsz - pos, "bt_activity_grading = %d\n",
 562                         le32_to_cpu(notif->bt_activity_grading));
 563        pos += scnprintf(buf + pos, bufsz - pos, "bt_rrc = %d\n",
 564                         notif->rrc_status & 0xF);
 565        pos += scnprintf(buf + pos, bufsz - pos, "bt_ttc = %d\n",
 566                         notif->ttc_status & 0xF);
 567
 568        pos += scnprintf(buf + pos, bufsz - pos, "sync_sco = %d\n",
 569                         IWL_MVM_BT_COEX_SYNC2SCO);
 570        pos += scnprintf(buf + pos, bufsz - pos, "mplut = %d\n",
 571                         IWL_MVM_BT_COEX_MPLUT);
 572
 573        mutex_unlock(&mvm->mutex);
 574
 575        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 576        kfree(buf);
 577
 578        return ret;
 579}
 580#undef BT_MBOX_PRINT
 581
 582static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
 583                                     size_t count, loff_t *ppos)
 584{
 585        struct iwl_mvm *mvm = file->private_data;
 586        struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
 587        char buf[256];
 588        int bufsz = sizeof(buf);
 589        int pos = 0;
 590
 591        mutex_lock(&mvm->mutex);
 592
 593        pos += scnprintf(buf + pos, bufsz - pos, "Channel inhibition CMD\n");
 594        pos += scnprintf(buf + pos, bufsz - pos,
 595                         "\tPrimary Channel Bitmap 0x%016llx\n",
 596                         le64_to_cpu(cmd->bt_primary_ci));
 597        pos += scnprintf(buf + pos, bufsz - pos,
 598                         "\tSecondary Channel Bitmap 0x%016llx\n",
 599                         le64_to_cpu(cmd->bt_secondary_ci));
 600
 601        mutex_unlock(&mvm->mutex);
 602
 603        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 604}
 605
 606static ssize_t
 607iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf,
 608                           size_t count, loff_t *ppos)
 609{
 610        u32 bt_tx_prio;
 611
 612        if (sscanf(buf, "%u", &bt_tx_prio) != 1)
 613                return -EINVAL;
 614        if (bt_tx_prio > 4)
 615                return -EINVAL;
 616
 617        mvm->bt_tx_prio = bt_tx_prio;
 618
 619        return count;
 620}
 621
 622static ssize_t
 623iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf,
 624                             size_t count, loff_t *ppos)
 625{
 626        static const char * const modes_str[BT_FORCE_ANT_MAX] = {
 627                [BT_FORCE_ANT_DIS] = "dis",
 628                [BT_FORCE_ANT_AUTO] = "auto",
 629                [BT_FORCE_ANT_BT] = "bt",
 630                [BT_FORCE_ANT_WIFI] = "wifi",
 631        };
 632        int ret, bt_force_ant_mode;
 633
 634        for (bt_force_ant_mode = 0;
 635             bt_force_ant_mode < ARRAY_SIZE(modes_str);
 636             bt_force_ant_mode++) {
 637                if (!strcmp(buf, modes_str[bt_force_ant_mode]))
 638                        break;
 639        }
 640
 641        if (bt_force_ant_mode >= ARRAY_SIZE(modes_str))
 642                return -EINVAL;
 643
 644        ret = 0;
 645        mutex_lock(&mvm->mutex);
 646        if (mvm->bt_force_ant_mode == bt_force_ant_mode)
 647                goto out;
 648
 649        mvm->bt_force_ant_mode = bt_force_ant_mode;
 650        IWL_DEBUG_COEX(mvm, "Force mode: %s\n",
 651                       modes_str[mvm->bt_force_ant_mode]);
 652
 653        if (iwl_mvm_firmware_running(mvm))
 654                ret = iwl_mvm_send_bt_init_conf(mvm);
 655        else
 656                ret = 0;
 657
 658out:
 659        mutex_unlock(&mvm->mutex);
 660        return ret ?: count;
 661}
 662
 663#define PRINT_STATS_LE32(_struct, _memb)                                \
 664                         pos += scnprintf(buf + pos, bufsz - pos,       \
 665                                          fmt_table, #_memb,            \
 666                                          le32_to_cpu(_struct->_memb))
 667
 668static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
 669                                          char __user *user_buf, size_t count,
 670                                          loff_t *ppos)
 671{
 672        struct iwl_mvm *mvm = file->private_data;
 673        static const char *fmt_table = "\t%-30s %10u\n";
 674        static const char *fmt_header = "%-32s\n";
 675        int pos = 0;
 676        char *buf;
 677        int ret;
 678        size_t bufsz;
 679
 680        if (iwl_mvm_has_new_rx_stats_api(mvm))
 681                bufsz = ((sizeof(struct mvm_statistics_rx) /
 682                          sizeof(__le32)) * 43) + (4 * 33) + 1;
 683        else
 684                /* 43 = size of each data line; 33 = size of each header */
 685                bufsz = ((sizeof(struct mvm_statistics_rx_v3) /
 686                          sizeof(__le32)) * 43) + (4 * 33) + 1;
 687
 688        buf = kzalloc(bufsz, GFP_KERNEL);
 689        if (!buf)
 690                return -ENOMEM;
 691
 692        mutex_lock(&mvm->mutex);
 693
 694        pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 695                         "Statistics_Rx - OFDM");
 696        if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
 697                struct mvm_statistics_rx_phy_v2 *ofdm = &mvm->rx_stats_v3.ofdm;
 698
 699                PRINT_STATS_LE32(ofdm, ina_cnt);
 700                PRINT_STATS_LE32(ofdm, fina_cnt);
 701                PRINT_STATS_LE32(ofdm, plcp_err);
 702                PRINT_STATS_LE32(ofdm, crc32_err);
 703                PRINT_STATS_LE32(ofdm, overrun_err);
 704                PRINT_STATS_LE32(ofdm, early_overrun_err);
 705                PRINT_STATS_LE32(ofdm, crc32_good);
 706                PRINT_STATS_LE32(ofdm, false_alarm_cnt);
 707                PRINT_STATS_LE32(ofdm, fina_sync_err_cnt);
 708                PRINT_STATS_LE32(ofdm, sfd_timeout);
 709                PRINT_STATS_LE32(ofdm, fina_timeout);
 710                PRINT_STATS_LE32(ofdm, unresponded_rts);
 711                PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun);
 712                PRINT_STATS_LE32(ofdm, sent_ack_cnt);
 713                PRINT_STATS_LE32(ofdm, sent_cts_cnt);
 714                PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt);
 715                PRINT_STATS_LE32(ofdm, dsp_self_kill);
 716                PRINT_STATS_LE32(ofdm, mh_format_err);
 717                PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum);
 718                PRINT_STATS_LE32(ofdm, reserved);
 719        } else {
 720                struct mvm_statistics_rx_phy *ofdm = &mvm->rx_stats.ofdm;
 721
 722                PRINT_STATS_LE32(ofdm, unresponded_rts);
 723                PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun);
 724                PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt);
 725                PRINT_STATS_LE32(ofdm, dsp_self_kill);
 726                PRINT_STATS_LE32(ofdm, reserved);
 727        }
 728
 729        pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 730                         "Statistics_Rx - CCK");
 731        if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
 732                struct mvm_statistics_rx_phy_v2 *cck = &mvm->rx_stats_v3.cck;
 733
 734                PRINT_STATS_LE32(cck, ina_cnt);
 735                PRINT_STATS_LE32(cck, fina_cnt);
 736                PRINT_STATS_LE32(cck, plcp_err);
 737                PRINT_STATS_LE32(cck, crc32_err);
 738                PRINT_STATS_LE32(cck, overrun_err);
 739                PRINT_STATS_LE32(cck, early_overrun_err);
 740                PRINT_STATS_LE32(cck, crc32_good);
 741                PRINT_STATS_LE32(cck, false_alarm_cnt);
 742                PRINT_STATS_LE32(cck, fina_sync_err_cnt);
 743                PRINT_STATS_LE32(cck, sfd_timeout);
 744                PRINT_STATS_LE32(cck, fina_timeout);
 745                PRINT_STATS_LE32(cck, unresponded_rts);
 746                PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun);
 747                PRINT_STATS_LE32(cck, sent_ack_cnt);
 748                PRINT_STATS_LE32(cck, sent_cts_cnt);
 749                PRINT_STATS_LE32(cck, sent_ba_rsp_cnt);
 750                PRINT_STATS_LE32(cck, dsp_self_kill);
 751                PRINT_STATS_LE32(cck, mh_format_err);
 752                PRINT_STATS_LE32(cck, re_acq_main_rssi_sum);
 753                PRINT_STATS_LE32(cck, reserved);
 754        } else {
 755                struct mvm_statistics_rx_phy *cck = &mvm->rx_stats.cck;
 756
 757                PRINT_STATS_LE32(cck, unresponded_rts);
 758                PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun);
 759                PRINT_STATS_LE32(cck, sent_ba_rsp_cnt);
 760                PRINT_STATS_LE32(cck, dsp_self_kill);
 761                PRINT_STATS_LE32(cck, reserved);
 762        }
 763
 764        pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 765                         "Statistics_Rx - GENERAL");
 766        if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
 767                struct mvm_statistics_rx_non_phy_v3 *general =
 768                        &mvm->rx_stats_v3.general;
 769
 770                PRINT_STATS_LE32(general, bogus_cts);
 771                PRINT_STATS_LE32(general, bogus_ack);
 772                PRINT_STATS_LE32(general, non_bssid_frames);
 773                PRINT_STATS_LE32(general, filtered_frames);
 774                PRINT_STATS_LE32(general, non_channel_beacons);
 775                PRINT_STATS_LE32(general, channel_beacons);
 776                PRINT_STATS_LE32(general, num_missed_bcon);
 777                PRINT_STATS_LE32(general, adc_rx_saturation_time);
 778                PRINT_STATS_LE32(general, ina_detection_search_time);
 779                PRINT_STATS_LE32(general, beacon_silence_rssi_a);
 780                PRINT_STATS_LE32(general, beacon_silence_rssi_b);
 781                PRINT_STATS_LE32(general, beacon_silence_rssi_c);
 782                PRINT_STATS_LE32(general, interference_data_flag);
 783                PRINT_STATS_LE32(general, channel_load);
 784                PRINT_STATS_LE32(general, dsp_false_alarms);
 785                PRINT_STATS_LE32(general, beacon_rssi_a);
 786                PRINT_STATS_LE32(general, beacon_rssi_b);
 787                PRINT_STATS_LE32(general, beacon_rssi_c);
 788                PRINT_STATS_LE32(general, beacon_energy_a);
 789                PRINT_STATS_LE32(general, beacon_energy_b);
 790                PRINT_STATS_LE32(general, beacon_energy_c);
 791                PRINT_STATS_LE32(general, num_bt_kills);
 792                PRINT_STATS_LE32(general, mac_id);
 793                PRINT_STATS_LE32(general, directed_data_mpdu);
 794        } else {
 795                struct mvm_statistics_rx_non_phy *general =
 796                        &mvm->rx_stats.general;
 797
 798                PRINT_STATS_LE32(general, bogus_cts);
 799                PRINT_STATS_LE32(general, bogus_ack);
 800                PRINT_STATS_LE32(general, non_channel_beacons);
 801                PRINT_STATS_LE32(general, channel_beacons);
 802                PRINT_STATS_LE32(general, num_missed_bcon);
 803                PRINT_STATS_LE32(general, adc_rx_saturation_time);
 804                PRINT_STATS_LE32(general, ina_detection_search_time);
 805                PRINT_STATS_LE32(general, beacon_silence_rssi_a);
 806                PRINT_STATS_LE32(general, beacon_silence_rssi_b);
 807                PRINT_STATS_LE32(general, beacon_silence_rssi_c);
 808                PRINT_STATS_LE32(general, interference_data_flag);
 809                PRINT_STATS_LE32(general, channel_load);
 810                PRINT_STATS_LE32(general, beacon_rssi_a);
 811                PRINT_STATS_LE32(general, beacon_rssi_b);
 812                PRINT_STATS_LE32(general, beacon_rssi_c);
 813                PRINT_STATS_LE32(general, beacon_energy_a);
 814                PRINT_STATS_LE32(general, beacon_energy_b);
 815                PRINT_STATS_LE32(general, beacon_energy_c);
 816                PRINT_STATS_LE32(general, num_bt_kills);
 817                PRINT_STATS_LE32(general, mac_id);
 818        }
 819
 820        pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 821                         "Statistics_Rx - HT");
 822        if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
 823                struct mvm_statistics_rx_ht_phy_v1 *ht =
 824                        &mvm->rx_stats_v3.ofdm_ht;
 825
 826                PRINT_STATS_LE32(ht, plcp_err);
 827                PRINT_STATS_LE32(ht, overrun_err);
 828                PRINT_STATS_LE32(ht, early_overrun_err);
 829                PRINT_STATS_LE32(ht, crc32_good);
 830                PRINT_STATS_LE32(ht, crc32_err);
 831                PRINT_STATS_LE32(ht, mh_format_err);
 832                PRINT_STATS_LE32(ht, agg_crc32_good);
 833                PRINT_STATS_LE32(ht, agg_mpdu_cnt);
 834                PRINT_STATS_LE32(ht, agg_cnt);
 835                PRINT_STATS_LE32(ht, unsupport_mcs);
 836        } else {
 837                struct mvm_statistics_rx_ht_phy *ht =
 838                        &mvm->rx_stats.ofdm_ht;
 839
 840                PRINT_STATS_LE32(ht, mh_format_err);
 841                PRINT_STATS_LE32(ht, agg_mpdu_cnt);
 842                PRINT_STATS_LE32(ht, agg_cnt);
 843                PRINT_STATS_LE32(ht, unsupport_mcs);
 844        }
 845
 846        mutex_unlock(&mvm->mutex);
 847
 848        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 849        kfree(buf);
 850
 851        return ret;
 852}
 853#undef PRINT_STAT_LE32
 854
 855static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
 856                                          char __user *user_buf, size_t count,
 857                                          loff_t *ppos,
 858                                          struct iwl_mvm_frame_stats *stats)
 859{
 860        char *buff, *pos, *endpos;
 861        int idx, i;
 862        int ret;
 863        static const size_t bufsz = 1024;
 864
 865        buff = kmalloc(bufsz, GFP_KERNEL);
 866        if (!buff)
 867                return -ENOMEM;
 868
 869        spin_lock_bh(&mvm->drv_stats_lock);
 870
 871        pos = buff;
 872        endpos = pos + bufsz;
 873
 874        pos += scnprintf(pos, endpos - pos,
 875                         "Legacy/HT/VHT\t:\t%d/%d/%d\n",
 876                         stats->legacy_frames,
 877                         stats->ht_frames,
 878                         stats->vht_frames);
 879        pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n",
 880                         stats->bw_20_frames,
 881                         stats->bw_40_frames,
 882                         stats->bw_80_frames);
 883        pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n",
 884                         stats->ngi_frames,
 885                         stats->sgi_frames);
 886        pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n",
 887                         stats->siso_frames,
 888                         stats->mimo2_frames);
 889        pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n",
 890                         stats->fail_frames,
 891                         stats->success_frames);
 892        pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n",
 893                         stats->agg_frames);
 894        pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n",
 895                         stats->ampdu_count);
 896        pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n",
 897                         stats->ampdu_count > 0 ?
 898                         (stats->agg_frames / stats->ampdu_count) : 0);
 899
 900        pos += scnprintf(pos, endpos - pos, "Last Rates\n");
 901
 902        idx = stats->last_frame_idx - 1;
 903        for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) {
 904                idx = (idx + 1) % ARRAY_SIZE(stats->last_rates);
 905                if (stats->last_rates[idx] == 0)
 906                        continue;
 907                pos += scnprintf(pos, endpos - pos, "Rate[%d]: ",
 908                                 (int)(ARRAY_SIZE(stats->last_rates) - i));
 909                pos += rs_pretty_print_rate(pos, stats->last_rates[idx]);
 910        }
 911        spin_unlock_bh(&mvm->drv_stats_lock);
 912
 913        ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
 914        kfree(buff);
 915
 916        return ret;
 917}
 918
 919static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file,
 920                                           char __user *user_buf, size_t count,
 921                                           loff_t *ppos)
 922{
 923        struct iwl_mvm *mvm = file->private_data;
 924
 925        return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos,
 926                                          &mvm->drv_rx_stats);
 927}
 928
 929static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
 930                                          size_t count, loff_t *ppos)
 931{
 932        int __maybe_unused ret;
 933
 934        if (!iwl_mvm_firmware_running(mvm))
 935                return -EIO;
 936
 937        mutex_lock(&mvm->mutex);
 938
 939        /* allow one more restart that we're provoking here */
 940        if (mvm->fw_restart >= 0)
 941                mvm->fw_restart++;
 942
 943        /* take the return value to make compiler happy - it will fail anyway */
 944        ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL);
 945
 946        mutex_unlock(&mvm->mutex);
 947
 948        return count;
 949}
 950
 951static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
 952                                      size_t count, loff_t *ppos)
 953{
 954        int ret;
 955
 956        if (!iwl_mvm_firmware_running(mvm))
 957                return -EIO;
 958
 959        ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI);
 960        if (ret)
 961                return ret;
 962
 963        iwl_force_nmi(mvm->trans);
 964
 965        iwl_mvm_unref(mvm, IWL_MVM_REF_NMI);
 966
 967        return count;
 968}
 969
 970static ssize_t
 971iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
 972                                char __user *user_buf,
 973                                size_t count, loff_t *ppos)
 974{
 975        struct iwl_mvm *mvm = file->private_data;
 976        int pos = 0;
 977        char buf[32];
 978        const size_t bufsz = sizeof(buf);
 979
 980        /* print which antennas were set for the scan command by the user */
 981        pos += scnprintf(buf + pos, bufsz - pos, "Antennas for scan: ");
 982        if (mvm->scan_rx_ant & ANT_A)
 983                pos += scnprintf(buf + pos, bufsz - pos, "A");
 984        if (mvm->scan_rx_ant & ANT_B)
 985                pos += scnprintf(buf + pos, bufsz - pos, "B");
 986        if (mvm->scan_rx_ant & ANT_C)
 987                pos += scnprintf(buf + pos, bufsz - pos, "C");
 988        pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant);
 989
 990        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 991}
 992
 993static ssize_t
 994iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
 995                                 size_t count, loff_t *ppos)
 996{
 997        u8 scan_rx_ant;
 998
 999        if (!iwl_mvm_firmware_running(mvm))
1000                return -EIO;
1001
1002        if (sscanf(buf, "%hhx", &scan_rx_ant) != 1)
1003                return -EINVAL;
1004        if (scan_rx_ant > ANT_ABC)
1005                return -EINVAL;
1006        if (scan_rx_ant & ~(iwl_mvm_get_valid_rx_ant(mvm)))
1007                return -EINVAL;
1008
1009        if (mvm->scan_rx_ant != scan_rx_ant) {
1010                mvm->scan_rx_ant = scan_rx_ant;
1011                if (fw_has_capa(&mvm->fw->ucode_capa,
1012                                IWL_UCODE_TLV_CAPA_UMAC_SCAN))
1013                        iwl_mvm_config_scan(mvm);
1014        }
1015
1016        return count;
1017}
1018
1019static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
1020                                               char *buf, size_t count,
1021                                               loff_t *ppos)
1022{
1023        struct iwl_rss_config_cmd cmd = {
1024                .flags = cpu_to_le32(IWL_RSS_ENABLE),
1025                .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP |
1026                             IWL_RSS_HASH_TYPE_IPV4_UDP |
1027                             IWL_RSS_HASH_TYPE_IPV4_PAYLOAD |
1028                             IWL_RSS_HASH_TYPE_IPV6_TCP |
1029                             IWL_RSS_HASH_TYPE_IPV6_UDP |
1030                             IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
1031        };
1032        int ret, i, num_repeats, nbytes = count / 2;
1033
1034        ret = hex2bin(cmd.indirection_table, buf, nbytes);
1035        if (ret)
1036                return ret;
1037
1038        /*
1039         * The input is the redirection table, partial or full.
1040         * Repeat the pattern if needed.
1041         * For example, input of 01020F will be repeated 42 times,
1042         * indirecting RSS hash results to queues 1, 2, 15 (skipping
1043         * queues 3 - 14).
1044         */
1045        num_repeats = ARRAY_SIZE(cmd.indirection_table) / nbytes;
1046        for (i = 1; i < num_repeats; i++)
1047                memcpy(&cmd.indirection_table[i * nbytes],
1048                       cmd.indirection_table, nbytes);
1049        /* handle cut in the middle pattern for the last places */
1050        memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table,
1051               ARRAY_SIZE(cmd.indirection_table) % nbytes);
1052
1053        netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key));
1054
1055        mutex_lock(&mvm->mutex);
1056        if (iwl_mvm_firmware_running(mvm))
1057                ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0,
1058                                           sizeof(cmd), &cmd);
1059        else
1060                ret = 0;
1061        mutex_unlock(&mvm->mutex);
1062
1063        return ret ?: count;
1064}
1065
1066static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm,
1067                                             char *buf, size_t count,
1068                                             loff_t *ppos)
1069{
1070        struct iwl_rx_cmd_buffer rxb = {
1071                ._rx_page_order = 0,
1072                .truesize = 0, /* not used */
1073                ._offset = 0,
1074        };
1075        struct iwl_rx_packet *pkt;
1076        struct iwl_rx_mpdu_desc *desc;
1077        int bin_len = count / 2;
1078        int ret = -EINVAL;
1079
1080        if (!iwl_mvm_firmware_running(mvm))
1081                return -EIO;
1082
1083        /* supporting only 9000 descriptor */
1084        if (!mvm->trans->cfg->mq_rx_supported)
1085                return -ENOTSUPP;
1086
1087        rxb._page = alloc_pages(GFP_ATOMIC, 0);
1088        if (!rxb._page)
1089                return -ENOMEM;
1090        pkt = rxb_addr(&rxb);
1091
1092        ret = hex2bin(page_address(rxb._page), buf, bin_len);
1093        if (ret)
1094                goto out;
1095
1096        /* avoid invalid memory access */
1097        if (bin_len < sizeof(*pkt) + sizeof(*desc))
1098                goto out;
1099
1100        /* check this is RX packet */
1101        if (WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd) !=
1102            WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD))
1103                goto out;
1104
1105        /* check the length in metadata matches actual received length */
1106        desc = (void *)pkt->data;
1107        if (le16_to_cpu(desc->mpdu_len) !=
1108            (bin_len - sizeof(*desc) - sizeof(*pkt)))
1109                goto out;
1110
1111        local_bh_disable();
1112        iwl_mvm_rx_mpdu_mq(mvm, NULL, &rxb, 0);
1113        local_bh_enable();
1114        ret = 0;
1115
1116out:
1117        iwl_free_rxb(&rxb);
1118
1119        return ret ?: count;
1120}
1121
1122static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
1123                                          char __user *user_buf,
1124                                          size_t count, loff_t *ppos)
1125{
1126        struct iwl_mvm *mvm = file->private_data;
1127        int conf;
1128        char buf[8];
1129        const size_t bufsz = sizeof(buf);
1130        int pos = 0;
1131
1132        mutex_lock(&mvm->mutex);
1133        conf = mvm->fwrt.dump.conf;
1134        mutex_unlock(&mvm->mutex);
1135
1136        pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf);
1137
1138        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1139}
1140
1141/*
1142 * Enable / Disable continuous recording.
1143 * Cause the FW to start continuous recording, by sending the relevant hcmd.
1144 * Enable: input of every integer larger than 0, ENABLE_CONT_RECORDING.
1145 * Disable: for 0 as input, DISABLE_CONT_RECORDING.
1146 */
1147static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
1148                                              char *buf, size_t count,
1149                                              loff_t *ppos)
1150{
1151        struct iwl_trans *trans = mvm->trans;
1152        const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv;
1153        struct iwl_continuous_record_cmd cont_rec = {};
1154        int ret, rec_mode;
1155
1156        if (!iwl_mvm_firmware_running(mvm))
1157                return -EIO;
1158
1159        if (!dest)
1160                return -EOPNOTSUPP;
1161
1162        if (dest->monitor_mode != SMEM_MODE ||
1163            trans->cfg->device_family < IWL_DEVICE_FAMILY_8000)
1164                return -EOPNOTSUPP;
1165
1166        ret = kstrtoint(buf, 0, &rec_mode);
1167        if (ret)
1168                return ret;
1169
1170        cont_rec.record_mode.enable_recording = rec_mode ?
1171                cpu_to_le16(ENABLE_CONT_RECORDING) :
1172                cpu_to_le16(DISABLE_CONT_RECORDING);
1173
1174        mutex_lock(&mvm->mutex);
1175        ret = iwl_mvm_send_cmd_pdu(mvm, LDBG_CONFIG_CMD, 0,
1176                                   sizeof(cont_rec), &cont_rec);
1177        mutex_unlock(&mvm->mutex);
1178
1179        return ret ?: count;
1180}
1181
1182static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,
1183                                           char *buf, size_t count,
1184                                           loff_t *ppos)
1185{
1186        unsigned int conf_id;
1187        int ret;
1188
1189        if (!iwl_mvm_firmware_running(mvm))
1190                return -EIO;
1191
1192        ret = kstrtouint(buf, 0, &conf_id);
1193        if (ret)
1194                return ret;
1195
1196        if (WARN_ON(conf_id >= FW_DBG_CONF_MAX))
1197                return -EINVAL;
1198
1199        mutex_lock(&mvm->mutex);
1200        ret = iwl_fw_start_dbg_conf(&mvm->fwrt, conf_id);
1201        mutex_unlock(&mvm->mutex);
1202
1203        return ret ?: count;
1204}
1205
1206static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
1207                                              char *buf, size_t count,
1208                                              loff_t *ppos)
1209{
1210        int ret;
1211
1212        if (!iwl_mvm_firmware_running(mvm))
1213                return -EIO;
1214
1215        ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
1216        if (ret)
1217                return ret;
1218        if (count == 0)
1219                return 0;
1220
1221        iwl_fw_dbg_collect(&mvm->fwrt, FW_DBG_TRIGGER_USER, buf,
1222                           (count - 1), NULL);
1223
1224        iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
1225
1226        return count;
1227}
1228
1229static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm,
1230                                             char *buf, size_t count,
1231                                             loff_t *ppos)
1232{
1233        unsigned int max_amsdu_len;
1234        int ret;
1235
1236        ret = kstrtouint(buf, 0, &max_amsdu_len);
1237        if (ret)
1238                return ret;
1239
1240        if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454)
1241                return -EINVAL;
1242        mvm->max_amsdu_len = max_amsdu_len;
1243
1244        return count;
1245}
1246
1247#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
1248#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1249static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
1250                                            char __user *user_buf,
1251                                            size_t count, loff_t *ppos)
1252{
1253        struct iwl_mvm *mvm = file->private_data;
1254        struct iwl_bcast_filter_cmd cmd;
1255        const struct iwl_fw_bcast_filter *filter;
1256        char *buf;
1257        int bufsz = 1024;
1258        int i, j, pos = 0;
1259        ssize_t ret;
1260
1261        buf = kzalloc(bufsz, GFP_KERNEL);
1262        if (!buf)
1263                return -ENOMEM;
1264
1265        mutex_lock(&mvm->mutex);
1266        if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
1267                ADD_TEXT("None\n");
1268                mutex_unlock(&mvm->mutex);
1269                goto out;
1270        }
1271        mutex_unlock(&mvm->mutex);
1272
1273        for (i = 0; cmd.filters[i].attrs[0].mask; i++) {
1274                filter = &cmd.filters[i];
1275
1276                ADD_TEXT("Filter [%d]:\n", i);
1277                ADD_TEXT("\tDiscard=%d\n", filter->discard);
1278                ADD_TEXT("\tFrame Type: %s\n",
1279                         filter->frame_type ? "IPv4" : "Generic");
1280
1281                for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) {
1282                        const struct iwl_fw_bcast_filter_attr *attr;
1283
1284                        attr = &filter->attrs[j];
1285                        if (!attr->mask)
1286                                break;
1287
1288                        ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n",
1289                                 j, attr->offset,
1290                                 attr->offset_type ? "IP End" :
1291                                                     "Payload Start",
1292                                 be32_to_cpu(attr->mask),
1293                                 be32_to_cpu(attr->val),
1294                                 le16_to_cpu(attr->reserved1));
1295                }
1296        }
1297out:
1298        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1299        kfree(buf);
1300        return ret;
1301}
1302
1303static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf,
1304                                             size_t count, loff_t *ppos)
1305{
1306        int pos, next_pos;
1307        struct iwl_fw_bcast_filter filter = {};
1308        struct iwl_bcast_filter_cmd cmd;
1309        u32 filter_id, attr_id, mask, value;
1310        int err = 0;
1311
1312        if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard,
1313                   &filter.frame_type, &pos) != 3)
1314                return -EINVAL;
1315
1316        if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) ||
1317            filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4)
1318                return -EINVAL;
1319
1320        for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs);
1321             attr_id++) {
1322                struct iwl_fw_bcast_filter_attr *attr =
1323                                &filter.attrs[attr_id];
1324
1325                if (pos >= count)
1326                        break;
1327
1328                if (sscanf(&buf[pos], "%hhi %hhi %i %i %n",
1329                           &attr->offset, &attr->offset_type,
1330                           &mask, &value, &next_pos) != 4)
1331                        return -EINVAL;
1332
1333                attr->mask = cpu_to_be32(mask);
1334                attr->val = cpu_to_be32(value);
1335                if (mask)
1336                        filter.num_attrs++;
1337
1338                pos += next_pos;
1339        }
1340
1341        mutex_lock(&mvm->mutex);
1342        memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id],
1343               &filter, sizeof(filter));
1344
1345        /* send updated bcast filtering configuration */
1346        if (iwl_mvm_firmware_running(mvm) &&
1347            mvm->dbgfs_bcast_filtering.override &&
1348            iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
1349                err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
1350                                           sizeof(cmd), &cmd);
1351        mutex_unlock(&mvm->mutex);
1352
1353        return err ?: count;
1354}
1355
1356static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file,
1357                                                 char __user *user_buf,
1358                                                 size_t count, loff_t *ppos)
1359{
1360        struct iwl_mvm *mvm = file->private_data;
1361        struct iwl_bcast_filter_cmd cmd;
1362        char *buf;
1363        int bufsz = 1024;
1364        int i, pos = 0;
1365        ssize_t ret;
1366
1367        buf = kzalloc(bufsz, GFP_KERNEL);
1368        if (!buf)
1369                return -ENOMEM;
1370
1371        mutex_lock(&mvm->mutex);
1372        if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
1373                ADD_TEXT("None\n");
1374                mutex_unlock(&mvm->mutex);
1375                goto out;
1376        }
1377        mutex_unlock(&mvm->mutex);
1378
1379        for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) {
1380                const struct iwl_fw_bcast_mac *mac = &cmd.macs[i];
1381
1382                ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n",
1383                         i, mac->default_discard, mac->attached_filters);
1384        }
1385out:
1386        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1387        kfree(buf);
1388        return ret;
1389}
1390
1391static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
1392                                                  char *buf, size_t count,
1393                                                  loff_t *ppos)
1394{
1395        struct iwl_bcast_filter_cmd cmd;
1396        struct iwl_fw_bcast_mac mac = {};
1397        u32 mac_id, attached_filters;
1398        int err = 0;
1399
1400        if (!mvm->bcast_filters)
1401                return -ENOENT;
1402
1403        if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard,
1404                   &attached_filters) != 3)
1405                return -EINVAL;
1406
1407        if (mac_id >= ARRAY_SIZE(cmd.macs) ||
1408            mac.default_discard > 1 ||
1409            attached_filters >= BIT(ARRAY_SIZE(cmd.filters)))
1410                return -EINVAL;
1411
1412        mac.attached_filters = cpu_to_le16(attached_filters);
1413
1414        mutex_lock(&mvm->mutex);
1415        memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id],
1416               &mac, sizeof(mac));
1417
1418        /* send updated bcast filtering configuration */
1419        if (iwl_mvm_firmware_running(mvm) &&
1420            mvm->dbgfs_bcast_filtering.override &&
1421            iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
1422                err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
1423                                           sizeof(cmd), &cmd);
1424        mutex_unlock(&mvm->mutex);
1425
1426        return err ?: count;
1427}
1428#endif
1429
1430#ifdef CONFIG_PM_SLEEP
1431static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf,
1432                                       size_t count, loff_t *ppos)
1433{
1434        int store;
1435
1436        if (sscanf(buf, "%d", &store) != 1)
1437                return -EINVAL;
1438
1439        mvm->store_d3_resume_sram = store;
1440
1441        return count;
1442}
1443
1444static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
1445                                      size_t count, loff_t *ppos)
1446{
1447        struct iwl_mvm *mvm = file->private_data;
1448        const struct fw_img *img;
1449        int ofs, len, pos = 0;
1450        size_t bufsz, ret;
1451        char *buf;
1452        u8 *ptr = mvm->d3_resume_sram;
1453
1454        img = &mvm->fw->img[IWL_UCODE_WOWLAN];
1455        len = img->sec[IWL_UCODE_SECTION_DATA].len;
1456
1457        bufsz = len * 4 + 256;
1458        buf = kzalloc(bufsz, GFP_KERNEL);
1459        if (!buf)
1460                return -ENOMEM;
1461
1462        pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n",
1463                         mvm->store_d3_resume_sram ? "en" : "dis");
1464
1465        if (ptr) {
1466                for (ofs = 0; ofs < len; ofs += 16) {
1467                        pos += scnprintf(buf + pos, bufsz - pos,
1468                                         "0x%.4x %16ph\n", ofs, ptr + ofs);
1469                }
1470        } else {
1471                pos += scnprintf(buf + pos, bufsz - pos,
1472                                 "(no data captured)\n");
1473        }
1474
1475        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1476
1477        kfree(buf);
1478
1479        return ret;
1480}
1481#endif
1482
1483#define PRINT_MVM_REF(ref) do {                                         \
1484        if (mvm->refs[ref])                                             \
1485                pos += scnprintf(buf + pos, bufsz - pos,                \
1486                                 "\t(0x%lx): %d %s\n",                  \
1487                                 BIT(ref), mvm->refs[ref], #ref);       \
1488} while (0)
1489
1490static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
1491                                        char __user *user_buf,
1492                                        size_t count, loff_t *ppos)
1493{
1494        struct iwl_mvm *mvm = file->private_data;
1495        int i, pos = 0;
1496        char buf[256];
1497        const size_t bufsz = sizeof(buf);
1498        u32 refs = 0;
1499
1500        for (i = 0; i < IWL_MVM_REF_COUNT; i++)
1501                if (mvm->refs[i])
1502                        refs |= BIT(i);
1503
1504        pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%x\n",
1505                         refs);
1506
1507        PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
1508        PRINT_MVM_REF(IWL_MVM_REF_SCAN);
1509        PRINT_MVM_REF(IWL_MVM_REF_ROC);
1510        PRINT_MVM_REF(IWL_MVM_REF_ROC_AUX);
1511        PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
1512        PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
1513        PRINT_MVM_REF(IWL_MVM_REF_USER);
1514        PRINT_MVM_REF(IWL_MVM_REF_TX);
1515        PRINT_MVM_REF(IWL_MVM_REF_TX_AGG);
1516        PRINT_MVM_REF(IWL_MVM_REF_ADD_IF);
1517        PRINT_MVM_REF(IWL_MVM_REF_START_AP);
1518        PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED);
1519        PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX);
1520        PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS);
1521        PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL);
1522        PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ);
1523        PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE);
1524        PRINT_MVM_REF(IWL_MVM_REF_NMI);
1525        PRINT_MVM_REF(IWL_MVM_REF_TM_CMD);
1526        PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
1527        PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA);
1528        PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT);
1529        PRINT_MVM_REF(IWL_MVM_REF_INIT_UCODE);
1530        PRINT_MVM_REF(IWL_MVM_REF_SENDING_CMD);
1531        PRINT_MVM_REF(IWL_MVM_REF_RX);
1532
1533        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1534}
1535
1536static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
1537                                         size_t count, loff_t *ppos)
1538{
1539        unsigned long value;
1540        int ret;
1541        bool taken;
1542
1543        ret = kstrtoul(buf, 10, &value);
1544        if (ret < 0)
1545                return ret;
1546
1547        mutex_lock(&mvm->mutex);
1548
1549        taken = mvm->refs[IWL_MVM_REF_USER];
1550        if (value == 1 && !taken)
1551                iwl_mvm_ref(mvm, IWL_MVM_REF_USER);
1552        else if (value == 0 && taken)
1553                iwl_mvm_unref(mvm, IWL_MVM_REF_USER);
1554        else
1555                ret = -EINVAL;
1556
1557        mutex_unlock(&mvm->mutex);
1558
1559        if (ret < 0)
1560                return ret;
1561        return count;
1562}
1563
1564#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1565        _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
1566#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1567        _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
1568#define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do {      \
1569                if (!debugfs_create_file(alias, mode, parent, mvm,      \
1570                                         &iwl_dbgfs_##name##_ops))      \
1571                        goto err;                                       \
1572        } while (0)
1573#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
1574        MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
1575
1576static ssize_t
1577iwl_dbgfs_prph_reg_read(struct file *file,
1578                        char __user *user_buf,
1579                        size_t count, loff_t *ppos)
1580{
1581        struct iwl_mvm *mvm = file->private_data;
1582        int pos = 0;
1583        char buf[32];
1584        const size_t bufsz = sizeof(buf);
1585        int ret;
1586
1587        if (!mvm->dbgfs_prph_reg_addr)
1588                return -EINVAL;
1589
1590        ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_READ);
1591        if (ret)
1592                return ret;
1593
1594        pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
1595                mvm->dbgfs_prph_reg_addr,
1596                iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
1597
1598        iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_READ);
1599
1600        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1601}
1602
1603static ssize_t
1604iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
1605                         size_t count, loff_t *ppos)
1606{
1607        u8 args;
1608        u32 value;
1609        int ret;
1610
1611        args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
1612        /* if we only want to set the reg address - nothing more to do */
1613        if (args == 1)
1614                goto out;
1615
1616        /* otherwise, make sure we have both address and value */
1617        if (args != 2)
1618                return -EINVAL;
1619
1620        ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
1621        if (ret)
1622                return ret;
1623
1624        iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
1625
1626        iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
1627out:
1628        return count;
1629}
1630
1631static ssize_t
1632iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf,
1633                              size_t count, loff_t *ppos)
1634{
1635        int ret;
1636
1637        if (!iwl_mvm_firmware_running(mvm))
1638                return -EIO;
1639
1640        mutex_lock(&mvm->mutex);
1641        ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL);
1642        mutex_unlock(&mvm->mutex);
1643
1644        return ret ?: count;
1645}
1646
1647MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
1648
1649/* Device wide debugfs entries */
1650MVM_DEBUGFS_READ_FILE_OPS(ctdp_budget);
1651MVM_DEBUGFS_WRITE_FILE_OPS(stop_ctdp, 8);
1652MVM_DEBUGFS_WRITE_FILE_OPS(force_ctkill, 8);
1653MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
1654MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
1655MVM_DEBUGFS_WRITE_FILE_OPS(send_echo_cmd, 8);
1656MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
1657MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64);
1658MVM_DEBUGFS_READ_FILE_OPS(nic_temp);
1659MVM_DEBUGFS_READ_FILE_OPS(stations);
1660MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
1661MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
1662MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
1663MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
1664MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
1665MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
1666MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
1667MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
1668MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
1669MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
1670MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
1671MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
1672MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
1673MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8);
1674MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8);
1675MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
1676                           (IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
1677MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512);
1678
1679#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1680MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
1681MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
1682#endif
1683
1684#ifdef CONFIG_PM_SLEEP
1685MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
1686#endif
1687#ifdef CONFIG_ACPI
1688MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile);
1689#endif
1690
1691static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
1692                                  size_t count, loff_t *ppos)
1693{
1694        struct iwl_mvm *mvm = file->private_data;
1695        struct iwl_dbg_mem_access_cmd cmd = {};
1696        struct iwl_dbg_mem_access_rsp *rsp;
1697        struct iwl_host_cmd hcmd = {
1698                .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
1699                .data = { &cmd, },
1700                .len = { sizeof(cmd) },
1701        };
1702        size_t delta;
1703        ssize_t ret, len;
1704
1705        if (!iwl_mvm_firmware_running(mvm))
1706                return -EIO;
1707
1708        hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
1709                             DEBUG_GROUP, 0);
1710        cmd.op = cpu_to_le32(DEBUG_MEM_OP_READ);
1711
1712        /* Take care of alignment of both the position and the length */
1713        delta = *ppos & 0x3;
1714        cmd.addr = cpu_to_le32(*ppos - delta);
1715        cmd.len = cpu_to_le32(min(ALIGN(count + delta, 4) / 4,
1716                                  (size_t)DEBUG_MEM_MAX_SIZE_DWORDS));
1717
1718        mutex_lock(&mvm->mutex);
1719        ret = iwl_mvm_send_cmd(mvm, &hcmd);
1720        mutex_unlock(&mvm->mutex);
1721
1722        if (ret < 0)
1723                return ret;
1724
1725        rsp = (void *)hcmd.resp_pkt->data;
1726        if (le32_to_cpu(rsp->status) != DEBUG_MEM_STATUS_SUCCESS) {
1727                ret = -ENXIO;
1728                goto out;
1729        }
1730
1731        len = min((size_t)le32_to_cpu(rsp->len) << 2,
1732                  iwl_rx_packet_payload_len(hcmd.resp_pkt) - sizeof(*rsp));
1733        len = min(len - delta, count);
1734        if (len < 0) {
1735                ret = -EFAULT;
1736                goto out;
1737        }
1738
1739        ret = len - copy_to_user(user_buf, (void *)rsp->data + delta, len);
1740        *ppos += ret;
1741
1742out:
1743        iwl_free_resp(&hcmd);
1744        return ret;
1745}
1746
1747static ssize_t iwl_dbgfs_mem_write(struct file *file,
1748                                   const char __user *user_buf, size_t count,
1749                                   loff_t *ppos)
1750{
1751        struct iwl_mvm *mvm = file->private_data;
1752        struct iwl_dbg_mem_access_cmd *cmd;
1753        struct iwl_dbg_mem_access_rsp *rsp;
1754        struct iwl_host_cmd hcmd = {};
1755        size_t cmd_size;
1756        size_t data_size;
1757        u32 op, len;
1758        ssize_t ret;
1759
1760        if (!iwl_mvm_firmware_running(mvm))
1761                return -EIO;
1762
1763        hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
1764                             DEBUG_GROUP, 0);
1765
1766        if (*ppos & 0x3 || count < 4) {
1767                op = DEBUG_MEM_OP_WRITE_BYTES;
1768                len = min(count, (size_t)(4 - (*ppos & 0x3)));
1769                data_size = len;
1770        } else {
1771                op = DEBUG_MEM_OP_WRITE;
1772                len = min(count >> 2, (size_t)DEBUG_MEM_MAX_SIZE_DWORDS);
1773                data_size = len << 2;
1774        }
1775
1776        cmd_size = sizeof(*cmd) + ALIGN(data_size, 4);
1777        cmd = kzalloc(cmd_size, GFP_KERNEL);
1778        if (!cmd)
1779                return -ENOMEM;
1780
1781        cmd->op = cpu_to_le32(op);
1782        cmd->len = cpu_to_le32(len);
1783        cmd->addr = cpu_to_le32(*ppos);
1784        if (copy_from_user((void *)cmd->data, user_buf, data_size)) {
1785                kfree(cmd);
1786                return -EFAULT;
1787        }
1788
1789        hcmd.flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
1790        hcmd.data[0] = (void *)cmd;
1791        hcmd.len[0] = cmd_size;
1792
1793        mutex_lock(&mvm->mutex);
1794        ret = iwl_mvm_send_cmd(mvm, &hcmd);
1795        mutex_unlock(&mvm->mutex);
1796
1797        kfree(cmd);
1798
1799        if (ret < 0)
1800                return ret;
1801
1802        rsp = (void *)hcmd.resp_pkt->data;
1803        if (rsp->status != DEBUG_MEM_STATUS_SUCCESS) {
1804                ret = -ENXIO;
1805                goto out;
1806        }
1807
1808        ret = data_size;
1809        *ppos += ret;
1810
1811out:
1812        iwl_free_resp(&hcmd);
1813        return ret;
1814}
1815
1816static const struct file_operations iwl_dbgfs_mem_ops = {
1817        .read = iwl_dbgfs_mem_read,
1818        .write = iwl_dbgfs_mem_write,
1819        .open = simple_open,
1820        .llseek = default_llseek,
1821};
1822
1823int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
1824{
1825        struct dentry *bcast_dir __maybe_unused;
1826        char buf[100];
1827
1828        spin_lock_init(&mvm->drv_stats_lock);
1829
1830        mvm->debugfs_dir = dbgfs_dir;
1831
1832        MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
1833        MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
1834        MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
1835        MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir,
1836                             S_IWUSR | S_IRUSR);
1837        MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
1838        MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, S_IRUSR);
1839        MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, S_IWUSR);
1840        MVM_DEBUGFS_ADD_FILE(force_ctkill, dbgfs_dir, S_IWUSR);
1841        MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
1842        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
1843        MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
1844        MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
1845                             S_IRUSR | S_IWUSR);
1846        MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
1847        MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
1848        MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
1849        MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
1850        MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR);
1851        MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, S_IWUSR);
1852        MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
1853                             S_IWUSR | S_IRUSR);
1854        MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
1855        MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
1856        MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
1857        MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
1858        MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, S_IWUSR);
1859        MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR);
1860        MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR);
1861        MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR);
1862        MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, S_IWUSR);
1863#ifdef CONFIG_ACPI
1864        MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, S_IRUSR);
1865#endif
1866
1867        if (!debugfs_create_bool("enable_scan_iteration_notif",
1868                                 S_IRUSR | S_IWUSR,
1869                                 mvm->debugfs_dir,
1870                                 &mvm->scan_iter_notif_enabled))
1871                goto err;
1872        if (!debugfs_create_bool("drop_bcn_ap_mode", S_IRUSR | S_IWUSR,
1873                                 mvm->debugfs_dir, &mvm->drop_bcn_ap_mode))
1874                goto err;
1875
1876#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1877        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
1878                bcast_dir = debugfs_create_dir("bcast_filtering",
1879                                               mvm->debugfs_dir);
1880                if (!bcast_dir)
1881                        goto err;
1882
1883                if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR,
1884                                bcast_dir,
1885                                &mvm->dbgfs_bcast_filtering.override))
1886                        goto err;
1887
1888                MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters,
1889                                           bcast_dir, S_IWUSR | S_IRUSR);
1890                MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs,
1891                                           bcast_dir, S_IWUSR | S_IRUSR);
1892        }
1893#endif
1894
1895#ifdef CONFIG_PM_SLEEP
1896        MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
1897        MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
1898        if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
1899                                 mvm->debugfs_dir, &mvm->d3_wake_sysassert))
1900                goto err;
1901        if (!debugfs_create_u32("last_netdetect_scans", S_IRUSR,
1902                                mvm->debugfs_dir, &mvm->last_netdetect_scans))
1903                goto err;
1904#endif
1905
1906        if (!debugfs_create_u8("ps_disabled", S_IRUSR,
1907                               mvm->debugfs_dir, &mvm->ps_disabled))
1908                goto err;
1909        if (!debugfs_create_blob("nvm_hw", S_IRUSR,
1910                                  mvm->debugfs_dir, &mvm->nvm_hw_blob))
1911                goto err;
1912        if (!debugfs_create_blob("nvm_sw", S_IRUSR,
1913                                  mvm->debugfs_dir, &mvm->nvm_sw_blob))
1914                goto err;
1915        if (!debugfs_create_blob("nvm_calib", S_IRUSR,
1916                                  mvm->debugfs_dir, &mvm->nvm_calib_blob))
1917                goto err;
1918        if (!debugfs_create_blob("nvm_prod", S_IRUSR,
1919                                  mvm->debugfs_dir, &mvm->nvm_prod_blob))
1920                goto err;
1921        if (!debugfs_create_blob("nvm_phy_sku", S_IRUSR,
1922                                 mvm->debugfs_dir, &mvm->nvm_phy_sku_blob))
1923                goto err;
1924
1925        debugfs_create_file("mem", S_IRUSR | S_IWUSR, dbgfs_dir, mvm,
1926                            &iwl_dbgfs_mem_ops);
1927
1928        /*
1929         * Create a symlink with mac80211. It will be removed when mac80211
1930         * exists (before the opmode exists which removes the target.)
1931         */
1932        snprintf(buf, 100, "../../%pd2", dbgfs_dir->d_parent);
1933        if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
1934                goto err;
1935
1936        return 0;
1937err:
1938        IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
1939        return -ENOMEM;
1940}
1941