linux/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.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 "mvm.h"
  68#include "fw/api/tof.h"
  69#include "debugfs.h"
  70
  71static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
  72                                 struct ieee80211_vif *vif,
  73                                 enum iwl_dbgfs_pm_mask param, int val)
  74{
  75        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  76        struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
  77
  78        dbgfs_pm->mask |= param;
  79
  80        switch (param) {
  81        case MVM_DEBUGFS_PM_KEEP_ALIVE: {
  82                int dtimper = vif->bss_conf.dtim_period ?: 1;
  83                int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
  84
  85                IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
  86                if (val * MSEC_PER_SEC < 3 * dtimper_msec)
  87                        IWL_WARN(mvm,
  88                                 "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
  89                                 val * MSEC_PER_SEC, 3 * dtimper_msec);
  90                dbgfs_pm->keep_alive_seconds = val;
  91                break;
  92        }
  93        case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
  94                IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
  95                                val ? "enabled" : "disabled");
  96                dbgfs_pm->skip_over_dtim = val;
  97                break;
  98        case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
  99                IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
 100                dbgfs_pm->skip_dtim_periods = val;
 101                break;
 102        case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
 103                IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
 104                dbgfs_pm->rx_data_timeout = val;
 105                break;
 106        case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
 107                IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
 108                dbgfs_pm->tx_data_timeout = val;
 109                break;
 110        case MVM_DEBUGFS_PM_LPRX_ENA:
 111                IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
 112                dbgfs_pm->lprx_ena = val;
 113                break;
 114        case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
 115                IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
 116                dbgfs_pm->lprx_rssi_threshold = val;
 117                break;
 118        case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
 119                IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
 120                dbgfs_pm->snooze_ena = val;
 121                break;
 122        case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
 123                IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
 124                dbgfs_pm->uapsd_misbehaving = val;
 125                break;
 126        case MVM_DEBUGFS_PM_USE_PS_POLL:
 127                IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val);
 128                dbgfs_pm->use_ps_poll = val;
 129                break;
 130        }
 131}
 132
 133static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
 134                                         size_t count, loff_t *ppos)
 135{
 136        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 137        struct iwl_mvm *mvm = mvmvif->mvm;
 138        enum iwl_dbgfs_pm_mask param;
 139        int val, ret;
 140
 141        if (!strncmp("keep_alive=", buf, 11)) {
 142                if (sscanf(buf + 11, "%d", &val) != 1)
 143                        return -EINVAL;
 144                param = MVM_DEBUGFS_PM_KEEP_ALIVE;
 145        } else if (!strncmp("skip_over_dtim=", buf, 15)) {
 146                if (sscanf(buf + 15, "%d", &val) != 1)
 147                        return -EINVAL;
 148                param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
 149        } else if (!strncmp("skip_dtim_periods=", buf, 18)) {
 150                if (sscanf(buf + 18, "%d", &val) != 1)
 151                        return -EINVAL;
 152                param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
 153        } else if (!strncmp("rx_data_timeout=", buf, 16)) {
 154                if (sscanf(buf + 16, "%d", &val) != 1)
 155                        return -EINVAL;
 156                param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
 157        } else if (!strncmp("tx_data_timeout=", buf, 16)) {
 158                if (sscanf(buf + 16, "%d", &val) != 1)
 159                        return -EINVAL;
 160                param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
 161        } else if (!strncmp("lprx=", buf, 5)) {
 162                if (sscanf(buf + 5, "%d", &val) != 1)
 163                        return -EINVAL;
 164                param = MVM_DEBUGFS_PM_LPRX_ENA;
 165        } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
 166                if (sscanf(buf + 20, "%d", &val) != 1)
 167                        return -EINVAL;
 168                if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
 169                    POWER_LPRX_RSSI_THRESHOLD_MIN)
 170                        return -EINVAL;
 171                param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
 172        } else if (!strncmp("snooze_enable=", buf, 14)) {
 173                if (sscanf(buf + 14, "%d", &val) != 1)
 174                        return -EINVAL;
 175                param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
 176        } else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
 177                if (sscanf(buf + 18, "%d", &val) != 1)
 178                        return -EINVAL;
 179                param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
 180        } else if (!strncmp("use_ps_poll=", buf, 12)) {
 181                if (sscanf(buf + 12, "%d", &val) != 1)
 182                        return -EINVAL;
 183                param = MVM_DEBUGFS_PM_USE_PS_POLL;
 184        } else {
 185                return -EINVAL;
 186        }
 187
 188        mutex_lock(&mvm->mutex);
 189        iwl_dbgfs_update_pm(mvm, vif, param, val);
 190        ret = iwl_mvm_power_update_mac(mvm);
 191        mutex_unlock(&mvm->mutex);
 192
 193        return ret ?: count;
 194}
 195
 196static ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file,
 197                                         char __user *user_buf,
 198                                         size_t count, loff_t *ppos)
 199{
 200        struct ieee80211_vif *vif = file->private_data;
 201        char buf[64];
 202        int bufsz = sizeof(buf);
 203        int pos;
 204
 205        pos = scnprintf(buf, bufsz, "bss limit = %d\n",
 206                        vif->bss_conf.txpower);
 207
 208        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 209}
 210
 211static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
 212                                        char __user *user_buf,
 213                                        size_t count, loff_t *ppos)
 214{
 215        struct ieee80211_vif *vif = file->private_data;
 216        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 217        struct iwl_mvm *mvm = mvmvif->mvm;
 218        char buf[512];
 219        int bufsz = sizeof(buf);
 220        int pos;
 221
 222        pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz);
 223
 224        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 225}
 226
 227static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
 228                                         char __user *user_buf,
 229                                         size_t count, loff_t *ppos)
 230{
 231        struct ieee80211_vif *vif = file->private_data;
 232        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 233        struct iwl_mvm *mvm = mvmvif->mvm;
 234        u8 ap_sta_id;
 235        struct ieee80211_chanctx_conf *chanctx_conf;
 236        char buf[512];
 237        int bufsz = sizeof(buf);
 238        int pos = 0;
 239        int i;
 240
 241        mutex_lock(&mvm->mutex);
 242
 243        ap_sta_id = mvmvif->ap_sta_id;
 244
 245        switch (ieee80211_vif_type_p2p(vif)) {
 246        case NL80211_IFTYPE_ADHOC:
 247                pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n");
 248                break;
 249        case NL80211_IFTYPE_STATION:
 250                pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n");
 251                break;
 252        case NL80211_IFTYPE_AP:
 253                pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n");
 254                break;
 255        case NL80211_IFTYPE_P2P_CLIENT:
 256                pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n");
 257                break;
 258        case NL80211_IFTYPE_P2P_GO:
 259                pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n");
 260                break;
 261        case NL80211_IFTYPE_P2P_DEVICE:
 262                pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n");
 263                break;
 264        default:
 265                break;
 266        }
 267
 268        pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
 269                         mvmvif->id, mvmvif->color);
 270        pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
 271                         vif->bss_conf.bssid);
 272        pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
 273        for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++)
 274                pos += scnprintf(buf+pos, bufsz-pos,
 275                                 "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
 276                                 i, mvmvif->queue_params[i].txop,
 277                                 mvmvif->queue_params[i].cw_min,
 278                                 mvmvif->queue_params[i].cw_max,
 279                                 mvmvif->queue_params[i].aifs,
 280                                 mvmvif->queue_params[i].uapsd);
 281
 282        if (vif->type == NL80211_IFTYPE_STATION &&
 283            ap_sta_id != IWL_MVM_INVALID_STA) {
 284                struct iwl_mvm_sta *mvm_sta;
 285
 286                mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id);
 287                if (mvm_sta) {
 288                        pos += scnprintf(buf+pos, bufsz-pos,
 289                                         "ap_sta_id %d - reduced Tx power %d\n",
 290                                         ap_sta_id,
 291                                         mvm_sta->bt_reduced_txpower);
 292                }
 293        }
 294
 295        rcu_read_lock();
 296        chanctx_conf = rcu_dereference(vif->chanctx_conf);
 297        if (chanctx_conf)
 298                pos += scnprintf(buf+pos, bufsz-pos,
 299                                 "idle rx chains %d, active rx chains: %d\n",
 300                                 chanctx_conf->rx_chains_static,
 301                                 chanctx_conf->rx_chains_dynamic);
 302        rcu_read_unlock();
 303
 304        mutex_unlock(&mvm->mutex);
 305
 306        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 307}
 308
 309static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
 310                                enum iwl_dbgfs_bf_mask param, int value)
 311{
 312        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 313        struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
 314
 315        dbgfs_bf->mask |= param;
 316
 317        switch (param) {
 318        case MVM_DEBUGFS_BF_ENERGY_DELTA:
 319                dbgfs_bf->bf_energy_delta = value;
 320                break;
 321        case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
 322                dbgfs_bf->bf_roaming_energy_delta = value;
 323                break;
 324        case MVM_DEBUGFS_BF_ROAMING_STATE:
 325                dbgfs_bf->bf_roaming_state = value;
 326                break;
 327        case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
 328                dbgfs_bf->bf_temp_threshold = value;
 329                break;
 330        case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
 331                dbgfs_bf->bf_temp_fast_filter = value;
 332                break;
 333        case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
 334                dbgfs_bf->bf_temp_slow_filter = value;
 335                break;
 336        case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
 337                dbgfs_bf->bf_enable_beacon_filter = value;
 338                break;
 339        case MVM_DEBUGFS_BF_DEBUG_FLAG:
 340                dbgfs_bf->bf_debug_flag = value;
 341                break;
 342        case MVM_DEBUGFS_BF_ESCAPE_TIMER:
 343                dbgfs_bf->bf_escape_timer = value;
 344                break;
 345        case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
 346                dbgfs_bf->ba_enable_beacon_abort = value;
 347                break;
 348        case MVM_DEBUGFS_BA_ESCAPE_TIMER:
 349                dbgfs_bf->ba_escape_timer = value;
 350                break;
 351        }
 352}
 353
 354static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
 355                                         size_t count, loff_t *ppos)
 356{
 357        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 358        struct iwl_mvm *mvm = mvmvif->mvm;
 359        enum iwl_dbgfs_bf_mask param;
 360        int value, ret = 0;
 361
 362        if (!strncmp("bf_energy_delta=", buf, 16)) {
 363                if (sscanf(buf+16, "%d", &value) != 1)
 364                        return -EINVAL;
 365                if (value < IWL_BF_ENERGY_DELTA_MIN ||
 366                    value > IWL_BF_ENERGY_DELTA_MAX)
 367                        return -EINVAL;
 368                param = MVM_DEBUGFS_BF_ENERGY_DELTA;
 369        } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
 370                if (sscanf(buf+24, "%d", &value) != 1)
 371                        return -EINVAL;
 372                if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
 373                    value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
 374                        return -EINVAL;
 375                param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
 376        } else if (!strncmp("bf_roaming_state=", buf, 17)) {
 377                if (sscanf(buf+17, "%d", &value) != 1)
 378                        return -EINVAL;
 379                if (value < IWL_BF_ROAMING_STATE_MIN ||
 380                    value > IWL_BF_ROAMING_STATE_MAX)
 381                        return -EINVAL;
 382                param = MVM_DEBUGFS_BF_ROAMING_STATE;
 383        } else if (!strncmp("bf_temp_threshold=", buf, 18)) {
 384                if (sscanf(buf+18, "%d", &value) != 1)
 385                        return -EINVAL;
 386                if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
 387                    value > IWL_BF_TEMP_THRESHOLD_MAX)
 388                        return -EINVAL;
 389                param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
 390        } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
 391                if (sscanf(buf+20, "%d", &value) != 1)
 392                        return -EINVAL;
 393                if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
 394                    value > IWL_BF_TEMP_FAST_FILTER_MAX)
 395                        return -EINVAL;
 396                param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
 397        } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
 398                if (sscanf(buf+20, "%d", &value) != 1)
 399                        return -EINVAL;
 400                if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
 401                    value > IWL_BF_TEMP_SLOW_FILTER_MAX)
 402                        return -EINVAL;
 403                param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
 404        } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
 405                if (sscanf(buf+24, "%d", &value) != 1)
 406                        return -EINVAL;
 407                if (value < 0 || value > 1)
 408                        return -EINVAL;
 409                param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
 410        } else if (!strncmp("bf_debug_flag=", buf, 14)) {
 411                if (sscanf(buf+14, "%d", &value) != 1)
 412                        return -EINVAL;
 413                if (value < 0 || value > 1)
 414                        return -EINVAL;
 415                param = MVM_DEBUGFS_BF_DEBUG_FLAG;
 416        } else if (!strncmp("bf_escape_timer=", buf, 16)) {
 417                if (sscanf(buf+16, "%d", &value) != 1)
 418                        return -EINVAL;
 419                if (value < IWL_BF_ESCAPE_TIMER_MIN ||
 420                    value > IWL_BF_ESCAPE_TIMER_MAX)
 421                        return -EINVAL;
 422                param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
 423        } else if (!strncmp("ba_escape_timer=", buf, 16)) {
 424                if (sscanf(buf+16, "%d", &value) != 1)
 425                        return -EINVAL;
 426                if (value < IWL_BA_ESCAPE_TIMER_MIN ||
 427                    value > IWL_BA_ESCAPE_TIMER_MAX)
 428                        return -EINVAL;
 429                param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
 430        } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
 431                if (sscanf(buf+23, "%d", &value) != 1)
 432                        return -EINVAL;
 433                if (value < 0 || value > 1)
 434                        return -EINVAL;
 435                param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
 436        } else {
 437                return -EINVAL;
 438        }
 439
 440        mutex_lock(&mvm->mutex);
 441        iwl_dbgfs_update_bf(vif, param, value);
 442        if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
 443                ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
 444        else
 445                ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0);
 446        mutex_unlock(&mvm->mutex);
 447
 448        return ret ?: count;
 449}
 450
 451static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
 452                                        char __user *user_buf,
 453                                        size_t count, loff_t *ppos)
 454{
 455        struct ieee80211_vif *vif = file->private_data;
 456        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 457        char buf[256];
 458        int pos = 0;
 459        const size_t bufsz = sizeof(buf);
 460        struct iwl_beacon_filter_cmd cmd = {
 461                IWL_BF_CMD_CONFIG_DEFAULTS,
 462                .bf_enable_beacon_filter =
 463                        cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
 464                .ba_enable_beacon_abort =
 465                        cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
 466        };
 467
 468        iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
 469        if (mvmvif->bf_data.bf_enabled)
 470                cmd.bf_enable_beacon_filter = cpu_to_le32(1);
 471        else
 472                cmd.bf_enable_beacon_filter = 0;
 473
 474        pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
 475                         le32_to_cpu(cmd.bf_energy_delta));
 476        pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
 477                         le32_to_cpu(cmd.bf_roaming_energy_delta));
 478        pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
 479                         le32_to_cpu(cmd.bf_roaming_state));
 480        pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
 481                         le32_to_cpu(cmd.bf_temp_threshold));
 482        pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
 483                         le32_to_cpu(cmd.bf_temp_fast_filter));
 484        pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
 485                         le32_to_cpu(cmd.bf_temp_slow_filter));
 486        pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
 487                         le32_to_cpu(cmd.bf_enable_beacon_filter));
 488        pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
 489                         le32_to_cpu(cmd.bf_debug_flag));
 490        pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
 491                         le32_to_cpu(cmd.bf_escape_timer));
 492        pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
 493                         le32_to_cpu(cmd.ba_escape_timer));
 494        pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
 495                         le32_to_cpu(cmd.ba_enable_beacon_abort));
 496
 497        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 498}
 499
 500static inline char *iwl_dbgfs_is_match(char *name, char *buf)
 501{
 502        int len = strlen(name);
 503
 504        return !strncmp(name, buf, len) ? buf + len : NULL;
 505}
 506
 507static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,
 508                                                 char __user *user_buf,
 509                                                 size_t count, loff_t *ppos)
 510{
 511        struct ieee80211_vif *vif = file->private_data;
 512        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 513        struct iwl_mvm *mvm = mvmvif->mvm;
 514        u32 curr_gp2;
 515        u64 curr_os;
 516        s64 diff;
 517        char buf[64];
 518        const size_t bufsz = sizeof(buf);
 519        int pos = 0;
 520
 521        iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os);
 522        do_div(curr_os, NSEC_PER_USEC);
 523        diff = curr_os - curr_gp2;
 524        pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff);
 525
 526        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 527}
 528
 529static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
 530                                          char *buf,
 531                                          size_t count, loff_t *ppos)
 532{
 533        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 534        struct iwl_mvm *mvm = mvmvif->mvm;
 535        u32 value;
 536        int ret = -EINVAL;
 537        char *data;
 538
 539        mutex_lock(&mvm->mutex);
 540
 541        data = iwl_dbgfs_is_match("tof_disabled=", buf);
 542        if (data) {
 543                ret = kstrtou32(data, 10, &value);
 544                if (ret == 0)
 545                        mvm->tof_data.tof_cfg.tof_disabled = value;
 546                goto out;
 547        }
 548
 549        data = iwl_dbgfs_is_match("one_sided_disabled=", buf);
 550        if (data) {
 551                ret = kstrtou32(data, 10, &value);
 552                if (ret == 0)
 553                        mvm->tof_data.tof_cfg.one_sided_disabled = value;
 554                goto out;
 555        }
 556
 557        data = iwl_dbgfs_is_match("is_debug_mode=", buf);
 558        if (data) {
 559                ret = kstrtou32(data, 10, &value);
 560                if (ret == 0)
 561                        mvm->tof_data.tof_cfg.is_debug_mode = value;
 562                goto out;
 563        }
 564
 565        data = iwl_dbgfs_is_match("is_buf=", buf);
 566        if (data) {
 567                ret = kstrtou32(data, 10, &value);
 568                if (ret == 0)
 569                        mvm->tof_data.tof_cfg.is_buf_required = value;
 570                goto out;
 571        }
 572
 573        data = iwl_dbgfs_is_match("send_tof_cfg=", buf);
 574        if (data) {
 575                ret = kstrtou32(data, 10, &value);
 576                if (ret == 0 && value) {
 577                        ret = iwl_mvm_tof_config_cmd(mvm);
 578                        goto out;
 579                }
 580        }
 581
 582out:
 583        mutex_unlock(&mvm->mutex);
 584
 585        return ret ?: count;
 586}
 587
 588static ssize_t iwl_dbgfs_tof_enable_read(struct file *file,
 589                                         char __user *user_buf,
 590                                         size_t count, loff_t *ppos)
 591{
 592        struct ieee80211_vif *vif = file->private_data;
 593        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 594        struct iwl_mvm *mvm = mvmvif->mvm;
 595        char buf[256];
 596        int pos = 0;
 597        const size_t bufsz = sizeof(buf);
 598        struct iwl_tof_config_cmd *cmd;
 599
 600        cmd = &mvm->tof_data.tof_cfg;
 601
 602        mutex_lock(&mvm->mutex);
 603
 604        pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n",
 605                         cmd->tof_disabled);
 606        pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n",
 607                         cmd->one_sided_disabled);
 608        pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n",
 609                         cmd->is_debug_mode);
 610        pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n",
 611                         cmd->is_buf_required);
 612
 613        mutex_unlock(&mvm->mutex);
 614
 615        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 616}
 617
 618static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
 619                                                    char *buf,
 620                                                    size_t count, loff_t *ppos)
 621{
 622        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 623        struct iwl_mvm *mvm = mvmvif->mvm;
 624        u32 value;
 625        int ret = 0;
 626        char *data;
 627
 628        mutex_lock(&mvm->mutex);
 629
 630        data = iwl_dbgfs_is_match("burst_period=", buf);
 631        if (data) {
 632                ret = kstrtou32(data, 10, &value);
 633                if (!ret)
 634                        mvm->tof_data.responder_cfg.burst_period =
 635                                                        cpu_to_le16(value);
 636                goto out;
 637        }
 638
 639        data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
 640        if (data) {
 641                ret = kstrtou32(data, 10, &value);
 642                if (ret == 0)
 643                        mvm->tof_data.responder_cfg.min_delta_ftm = value;
 644                goto out;
 645        }
 646
 647        data = iwl_dbgfs_is_match("burst_duration=", buf);
 648        if (data) {
 649                ret = kstrtou32(data, 10, &value);
 650                if (ret == 0)
 651                        mvm->tof_data.responder_cfg.burst_duration = value;
 652                goto out;
 653        }
 654
 655        data = iwl_dbgfs_is_match("num_of_burst_exp=", buf);
 656        if (data) {
 657                ret = kstrtou32(data, 10, &value);
 658                if (ret == 0)
 659                        mvm->tof_data.responder_cfg.num_of_burst_exp = value;
 660                goto out;
 661        }
 662
 663        data = iwl_dbgfs_is_match("abort_responder=", buf);
 664        if (data) {
 665                ret = kstrtou32(data, 10, &value);
 666                if (ret == 0)
 667                        mvm->tof_data.responder_cfg.abort_responder = value;
 668                goto out;
 669        }
 670
 671        data = iwl_dbgfs_is_match("get_ch_est=", buf);
 672        if (data) {
 673                ret = kstrtou32(data, 10, &value);
 674                if (ret == 0)
 675                        mvm->tof_data.responder_cfg.get_ch_est = value;
 676                goto out;
 677        }
 678
 679        data = iwl_dbgfs_is_match("recv_sta_req_params=", buf);
 680        if (data) {
 681                ret = kstrtou32(data, 10, &value);
 682                if (ret == 0)
 683                        mvm->tof_data.responder_cfg.recv_sta_req_params = value;
 684                goto out;
 685        }
 686
 687        data = iwl_dbgfs_is_match("channel_num=", buf);
 688        if (data) {
 689                ret = kstrtou32(data, 10, &value);
 690                if (ret == 0)
 691                        mvm->tof_data.responder_cfg.channel_num = value;
 692                goto out;
 693        }
 694
 695        data = iwl_dbgfs_is_match("bandwidth=", buf);
 696        if (data) {
 697                ret = kstrtou32(data, 10, &value);
 698                if (ret == 0)
 699                        mvm->tof_data.responder_cfg.bandwidth = value;
 700                goto out;
 701        }
 702
 703        data = iwl_dbgfs_is_match("rate=", buf);
 704        if (data) {
 705                ret = kstrtou32(data, 10, &value);
 706                if (ret == 0)
 707                        mvm->tof_data.responder_cfg.rate = value;
 708                goto out;
 709        }
 710
 711        data = iwl_dbgfs_is_match("bssid=", buf);
 712        if (data) {
 713                u8 *mac = mvm->tof_data.responder_cfg.bssid;
 714
 715                if (!mac_pton(data, mac)) {
 716                        ret = -EINVAL;
 717                        goto out;
 718                }
 719        }
 720
 721        data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf);
 722        if (data) {
 723                ret = kstrtou32(data, 10, &value);
 724                if (ret == 0)
 725                        mvm->tof_data.responder_cfg.tsf_timer_offset_msecs =
 726                                                        cpu_to_le16(value);
 727                goto out;
 728        }
 729
 730        data = iwl_dbgfs_is_match("toa_offset=", buf);
 731        if (data) {
 732                ret = kstrtou32(data, 10, &value);
 733                if (ret == 0)
 734                        mvm->tof_data.responder_cfg.toa_offset =
 735                                                        cpu_to_le16(value);
 736                goto out;
 737        }
 738
 739        data = iwl_dbgfs_is_match("center_freq=", buf);
 740        if (data) {
 741                struct iwl_tof_responder_config_cmd *cmd =
 742                        &mvm->tof_data.responder_cfg;
 743
 744                ret = kstrtou32(data, 10, &value);
 745                if (ret == 0 && value) {
 746                        enum nl80211_band band = (cmd->channel_num <= 14) ?
 747                                                   NL80211_BAND_2GHZ :
 748                                                   NL80211_BAND_5GHZ;
 749                        struct ieee80211_channel chn = {
 750                                .band = band,
 751                                .center_freq = ieee80211_channel_to_frequency(
 752                                        cmd->channel_num, band),
 753                                };
 754                        struct cfg80211_chan_def chandef = {
 755                                .chan =  &chn,
 756                                .center_freq1 =
 757                                        ieee80211_channel_to_frequency(value,
 758                                                                       band),
 759                        };
 760
 761                        cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef);
 762                }
 763                goto out;
 764        }
 765
 766        data = iwl_dbgfs_is_match("ftm_per_burst=", buf);
 767        if (data) {
 768                ret = kstrtou32(data, 10, &value);
 769                if (ret == 0)
 770                        mvm->tof_data.responder_cfg.ftm_per_burst = value;
 771                goto out;
 772        }
 773
 774        data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf);
 775        if (data) {
 776                ret = kstrtou32(data, 10, &value);
 777                if (ret == 0)
 778                        mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value;
 779                goto out;
 780        }
 781
 782        data = iwl_dbgfs_is_match("asap_mode=", buf);
 783        if (data) {
 784                ret = kstrtou32(data, 10, &value);
 785                if (ret == 0)
 786                        mvm->tof_data.responder_cfg.asap_mode = value;
 787                goto out;
 788        }
 789
 790        data = iwl_dbgfs_is_match("send_responder_cfg=", buf);
 791        if (data) {
 792                ret = kstrtou32(data, 10, &value);
 793                if (ret == 0 && value) {
 794                        ret = iwl_mvm_tof_responder_cmd(mvm, vif);
 795                        goto out;
 796                }
 797        }
 798
 799out:
 800        mutex_unlock(&mvm->mutex);
 801
 802        return ret ?: count;
 803}
 804
 805static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file,
 806                                                   char __user *user_buf,
 807                                                   size_t count, loff_t *ppos)
 808{
 809        struct ieee80211_vif *vif = file->private_data;
 810        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 811        struct iwl_mvm *mvm = mvmvif->mvm;
 812        char buf[256];
 813        int pos = 0;
 814        const size_t bufsz = sizeof(buf);
 815        struct iwl_tof_responder_config_cmd *cmd;
 816
 817        cmd = &mvm->tof_data.responder_cfg;
 818
 819        mutex_lock(&mvm->mutex);
 820
 821        pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n",
 822                         le16_to_cpu(cmd->burst_period));
 823        pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n",
 824                         cmd->burst_duration);
 825        pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n",
 826                         cmd->bandwidth);
 827        pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n",
 828                         cmd->channel_num);
 829        pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n",
 830                         cmd->ctrl_ch_position);
 831        pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n",
 832                         cmd->bssid);
 833        pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n",
 834                         cmd->min_delta_ftm);
 835        pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n",
 836                         cmd->num_of_burst_exp);
 837        pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate);
 838        pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n",
 839                         cmd->abort_responder);
 840        pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n",
 841                         cmd->get_ch_est);
 842        pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n",
 843                         cmd->recv_sta_req_params);
 844        pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n",
 845                         cmd->ftm_per_burst);
 846        pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n",
 847                         cmd->ftm_resp_ts_avail);
 848        pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n",
 849                         cmd->asap_mode);
 850        pos += scnprintf(buf + pos, bufsz - pos,
 851                         "tsf_timer_offset_msecs = %d\n",
 852                         le16_to_cpu(cmd->tsf_timer_offset_msecs));
 853        pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n",
 854                         le16_to_cpu(cmd->toa_offset));
 855
 856        mutex_unlock(&mvm->mutex);
 857
 858        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 859}
 860
 861static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
 862                                                 char *buf, size_t count,
 863                                                 loff_t *ppos)
 864{
 865        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 866        struct iwl_mvm *mvm = mvmvif->mvm;
 867        u32 value;
 868        int ret = 0;
 869        char *data;
 870
 871        mutex_lock(&mvm->mutex);
 872
 873        data = iwl_dbgfs_is_match("request_id=", buf);
 874        if (data) {
 875                ret = kstrtou32(data, 10, &value);
 876                if (ret == 0)
 877                        mvm->tof_data.range_req.request_id = value;
 878                goto out;
 879        }
 880
 881        data = iwl_dbgfs_is_match("initiator=", buf);
 882        if (data) {
 883                ret = kstrtou32(data, 10, &value);
 884                if (ret == 0)
 885                        mvm->tof_data.range_req.initiator = value;
 886                goto out;
 887        }
 888
 889        data = iwl_dbgfs_is_match("one_sided_los_disable=", buf);
 890        if (data) {
 891                ret = kstrtou32(data, 10, &value);
 892                if (ret == 0)
 893                        mvm->tof_data.range_req.one_sided_los_disable = value;
 894                goto out;
 895        }
 896
 897        data = iwl_dbgfs_is_match("req_timeout=", buf);
 898        if (data) {
 899                ret = kstrtou32(data, 10, &value);
 900                if (ret == 0)
 901                        mvm->tof_data.range_req.req_timeout = value;
 902                goto out;
 903        }
 904
 905        data = iwl_dbgfs_is_match("report_policy=", buf);
 906        if (data) {
 907                ret = kstrtou32(data, 10, &value);
 908                if (ret == 0)
 909                        mvm->tof_data.range_req.report_policy = value;
 910                goto out;
 911        }
 912
 913        data = iwl_dbgfs_is_match("macaddr_random=", buf);
 914        if (data) {
 915                ret = kstrtou32(data, 10, &value);
 916                if (ret == 0)
 917                        mvm->tof_data.range_req.macaddr_random = value;
 918                goto out;
 919        }
 920
 921        data = iwl_dbgfs_is_match("num_of_ap=", buf);
 922        if (data) {
 923                ret = kstrtou32(data, 10, &value);
 924                if (ret == 0)
 925                        mvm->tof_data.range_req.num_of_ap = value;
 926                goto out;
 927        }
 928
 929        data = iwl_dbgfs_is_match("macaddr_template=", buf);
 930        if (data) {
 931                u8 mac[ETH_ALEN];
 932
 933                if (!mac_pton(data, mac)) {
 934                        ret = -EINVAL;
 935                        goto out;
 936                }
 937                memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN);
 938                goto out;
 939        }
 940
 941        data = iwl_dbgfs_is_match("macaddr_mask=", buf);
 942        if (data) {
 943                u8 mac[ETH_ALEN];
 944
 945                if (!mac_pton(data, mac)) {
 946                        ret = -EINVAL;
 947                        goto out;
 948                }
 949                memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN);
 950                goto out;
 951        }
 952
 953        data = iwl_dbgfs_is_match("ap=", buf);
 954        if (data) {
 955                struct iwl_tof_range_req_ap_entry ap = {};
 956                int size = sizeof(struct iwl_tof_range_req_ap_entry);
 957                u16 burst_period;
 958                u8 *mac = ap.bssid;
 959                unsigned int i;
 960
 961                if (sscanf(data, "%u %hhd %hhd %hhd"
 962                           "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"
 963                           "%hhd %hhd %hd"
 964                           "%hhd %hhd %d"
 965                           "%hhx %hhd %hhd %hhd",
 966                           &i, &ap.channel_num, &ap.bandwidth,
 967                           &ap.ctrl_ch_position,
 968                           mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
 969                           &ap.measure_type, &ap.num_of_bursts,
 970                           &burst_period,
 971                           &ap.samples_per_burst, &ap.retries_per_sample,
 972                           &ap.tsf_delta, &ap.location_req, &ap.asap_mode,
 973                           &ap.enable_dyn_ack, &ap.rssi) != 20) {
 974                        ret = -EINVAL;
 975                        goto out;
 976                }
 977                if (i >= IWL_MVM_TOF_MAX_APS) {
 978                        IWL_ERR(mvm, "Invalid AP index %d\n", i);
 979                        ret = -EINVAL;
 980                        goto out;
 981                }
 982
 983                ap.burst_period = cpu_to_le16(burst_period);
 984
 985                memcpy(&mvm->tof_data.range_req.ap[i], &ap, size);
 986                goto out;
 987        }
 988
 989        data = iwl_dbgfs_is_match("send_range_request=", buf);
 990        if (data) {
 991                ret = kstrtou32(data, 10, &value);
 992                if (ret == 0 && value)
 993                        ret = iwl_mvm_tof_range_request_cmd(mvm, vif);
 994                goto out;
 995        }
 996
 997        ret = -EINVAL;
 998out:
 999        mutex_unlock(&mvm->mutex);
1000        return ret ?: count;
1001}
1002
1003static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file,
1004                                                char __user *user_buf,
1005                                                size_t count, loff_t *ppos)
1006{
1007        struct ieee80211_vif *vif = file->private_data;
1008        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1009        struct iwl_mvm *mvm = mvmvif->mvm;
1010        char buf[512];
1011        int pos = 0;
1012        const size_t bufsz = sizeof(buf);
1013        struct iwl_tof_range_req_cmd *cmd;
1014        int i;
1015
1016        cmd = &mvm->tof_data.range_req;
1017
1018        mutex_lock(&mvm->mutex);
1019
1020        pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n",
1021                         cmd->request_id);
1022        pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n",
1023                         cmd->initiator);
1024        pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n",
1025                         cmd->one_sided_los_disable);
1026        pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n",
1027                         cmd->req_timeout);
1028        pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n",
1029                         cmd->report_policy);
1030        pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n",
1031                         cmd->macaddr_random);
1032        pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n",
1033                         cmd->macaddr_template);
1034        pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n",
1035                         cmd->macaddr_mask);
1036        pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n",
1037                         cmd->num_of_ap);
1038        for (i = 0; i < cmd->num_of_ap; i++) {
1039                struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i];
1040
1041                pos += scnprintf(buf + pos, bufsz - pos,
1042                                "ap %.2d: channel_num=%hhd bw=%hhd"
1043                                " control=%hhd bssid=%pM type=%hhd"
1044                                " num_of_bursts=%hhd burst_period=%hd ftm=%hhd"
1045                                " retries=%hhd tsf_delta=%d"
1046                                " tsf_delta_direction=%hhd location_req=0x%hhx "
1047                                " asap=%hhd enable=%hhd rssi=%hhd\n",
1048                                i, ap->channel_num, ap->bandwidth,
1049                                ap->ctrl_ch_position, ap->bssid,
1050                                ap->measure_type, ap->num_of_bursts,
1051                                ap->burst_period, ap->samples_per_burst,
1052                                ap->retries_per_sample, ap->tsf_delta,
1053                                ap->tsf_delta_direction,
1054                                ap->location_req, ap->asap_mode,
1055                                ap->enable_dyn_ack, ap->rssi);
1056        }
1057
1058        mutex_unlock(&mvm->mutex);
1059
1060        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1061}
1062
1063static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
1064                                                 char *buf,
1065                                                 size_t count, loff_t *ppos)
1066{
1067        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1068        struct iwl_mvm *mvm = mvmvif->mvm;
1069        u32 value;
1070        int ret = 0;
1071        char *data;
1072
1073        mutex_lock(&mvm->mutex);
1074
1075        data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf);
1076        if (data) {
1077                ret = kstrtou32(data, 10, &value);
1078                if (ret == 0)
1079                        mvm->tof_data.range_req_ext.tsf_timer_offset_msec =
1080                                                        cpu_to_le16(value);
1081                goto out;
1082        }
1083
1084        data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
1085        if (data) {
1086                ret = kstrtou32(data, 10, &value);
1087                if (ret == 0)
1088                        mvm->tof_data.range_req_ext.min_delta_ftm = value;
1089                goto out;
1090        }
1091
1092        data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf);
1093        if (data) {
1094                ret = kstrtou32(data, 10, &value);
1095                if (ret == 0)
1096                        mvm->tof_data.range_req_ext.ftm_format_and_bw20M =
1097                                                                        value;
1098                goto out;
1099        }
1100
1101        data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf);
1102        if (data) {
1103                ret = kstrtou32(data, 10, &value);
1104                if (ret == 0)
1105                        mvm->tof_data.range_req_ext.ftm_format_and_bw40M =
1106                                                                        value;
1107                goto out;
1108        }
1109
1110        data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf);
1111        if (data) {
1112                ret = kstrtou32(data, 10, &value);
1113                if (ret == 0)
1114                        mvm->tof_data.range_req_ext.ftm_format_and_bw80M =
1115                                                                        value;
1116                goto out;
1117        }
1118
1119        data = iwl_dbgfs_is_match("send_range_req_ext=", buf);
1120        if (data) {
1121                ret = kstrtou32(data, 10, &value);
1122                if (ret == 0 && value)
1123                        ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif);
1124                goto out;
1125        }
1126
1127        ret = -EINVAL;
1128out:
1129        mutex_unlock(&mvm->mutex);
1130        return ret ?: count;
1131}
1132
1133static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file,
1134                                                char __user *user_buf,
1135                                                size_t count, loff_t *ppos)
1136{
1137        struct ieee80211_vif *vif = file->private_data;
1138        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1139        struct iwl_mvm *mvm = mvmvif->mvm;
1140        char buf[256];
1141        int pos = 0;
1142        const size_t bufsz = sizeof(buf);
1143        struct iwl_tof_range_req_ext_cmd *cmd;
1144
1145        cmd = &mvm->tof_data.range_req_ext;
1146
1147        mutex_lock(&mvm->mutex);
1148
1149        pos += scnprintf(buf + pos, bufsz - pos,
1150                         "tsf_timer_offset_msec = %hd\n",
1151                         cmd->tsf_timer_offset_msec);
1152        pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n",
1153                         cmd->min_delta_ftm);
1154        pos += scnprintf(buf + pos, bufsz - pos,
1155                         "ftm_format_and_bw20M = %hhd\n",
1156                         cmd->ftm_format_and_bw20M);
1157        pos += scnprintf(buf + pos, bufsz - pos,
1158                         "ftm_format_and_bw40M = %hhd\n",
1159                         cmd->ftm_format_and_bw40M);
1160        pos += scnprintf(buf + pos, bufsz - pos,
1161                         "ftm_format_and_bw80M = %hhd\n",
1162                         cmd->ftm_format_and_bw80M);
1163
1164        mutex_unlock(&mvm->mutex);
1165        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1166}
1167
1168static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif,
1169                                               char *buf,
1170                                               size_t count, loff_t *ppos)
1171{
1172        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1173        struct iwl_mvm *mvm = mvmvif->mvm;
1174        u32 value;
1175        int abort_id, ret = 0;
1176        char *data;
1177
1178        mutex_lock(&mvm->mutex);
1179
1180        data = iwl_dbgfs_is_match("abort_id=", buf);
1181        if (data) {
1182                ret = kstrtou32(data, 10, &value);
1183                if (ret == 0)
1184                        mvm->tof_data.last_abort_id = value;
1185                goto out;
1186        }
1187
1188        data = iwl_dbgfs_is_match("send_range_abort=", buf);
1189        if (data) {
1190                ret = kstrtou32(data, 10, &value);
1191                if (ret == 0 && value) {
1192                        abort_id = mvm->tof_data.last_abort_id;
1193                        ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id);
1194                        goto out;
1195                }
1196        }
1197
1198out:
1199        mutex_unlock(&mvm->mutex);
1200        return ret ?: count;
1201}
1202
1203static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file,
1204                                              char __user *user_buf,
1205                                              size_t count, loff_t *ppos)
1206{
1207        struct ieee80211_vif *vif = file->private_data;
1208        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1209        struct iwl_mvm *mvm = mvmvif->mvm;
1210        char buf[32];
1211        int pos = 0;
1212        const size_t bufsz = sizeof(buf);
1213        int last_abort_id;
1214
1215        mutex_lock(&mvm->mutex);
1216        last_abort_id = mvm->tof_data.last_abort_id;
1217        mutex_unlock(&mvm->mutex);
1218
1219        pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n",
1220                         last_abort_id);
1221        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1222}
1223
1224static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file,
1225                                                 char __user *user_buf,
1226                                                 size_t count, loff_t *ppos)
1227{
1228        struct ieee80211_vif *vif = file->private_data;
1229        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1230        struct iwl_mvm *mvm = mvmvif->mvm;
1231        char *buf;
1232        int pos = 0;
1233        const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256;
1234        struct iwl_tof_range_rsp_ntfy *cmd;
1235        int i, ret;
1236
1237        buf = kzalloc(bufsz, GFP_KERNEL);
1238        if (!buf)
1239                return -ENOMEM;
1240
1241        mutex_lock(&mvm->mutex);
1242        cmd = &mvm->tof_data.range_resp;
1243
1244        pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n",
1245                         cmd->request_id);
1246        pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n",
1247                         cmd->request_status);
1248        pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n",
1249                         cmd->last_in_batch);
1250        pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n",
1251                         cmd->num_of_aps);
1252        for (i = 0; i < cmd->num_of_aps; i++) {
1253                struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i];
1254
1255                pos += scnprintf(buf + pos, bufsz - pos,
1256                                "ap %.2d: bssid=%pM status=%hhd bw=%hhd"
1257                                " rtt=%d rtt_var=%d rtt_spread=%d"
1258                                " rssi=%hhd  rssi_spread=%hhd"
1259                                " range=%d range_var=%d"
1260                                " time_stamp=%d\n",
1261                                i, ap->bssid, ap->measure_status,
1262                                ap->measure_bw,
1263                                ap->rtt, ap->rtt_variance, ap->rtt_spread,
1264                                ap->rssi, ap->rssi_spread, ap->range,
1265                                ap->range_variance, ap->timestamp);
1266        }
1267        mutex_unlock(&mvm->mutex);
1268
1269        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1270        kfree(buf);
1271        return ret;
1272}
1273
1274static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
1275                                           size_t count, loff_t *ppos)
1276{
1277        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1278        struct iwl_mvm *mvm = mvmvif->mvm;
1279        bool prev;
1280        u8 value;
1281        int ret;
1282
1283        ret = kstrtou8(buf, 0, &value);
1284        if (ret)
1285                return ret;
1286        if (value > 1)
1287                return -EINVAL;
1288
1289        mutex_lock(&mvm->mutex);
1290        prev = iwl_mvm_vif_low_latency(mvmvif);
1291        mvmvif->low_latency_dbgfs = value;
1292        iwl_mvm_update_low_latency(mvm, vif, prev);
1293        mutex_unlock(&mvm->mutex);
1294
1295        return count;
1296}
1297
1298static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
1299                                          char __user *user_buf,
1300                                          size_t count, loff_t *ppos)
1301{
1302        struct ieee80211_vif *vif = file->private_data;
1303        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1304        char buf[30] = {};
1305        int len;
1306
1307        len = scnprintf(buf, sizeof(buf) - 1,
1308                        "traffic=%d\ndbgfs=%d\nvcmd=%d\n",
1309                        mvmvif->low_latency_traffic,
1310                        mvmvif->low_latency_dbgfs,
1311                        mvmvif->low_latency_vcmd);
1312        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1313}
1314
1315static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
1316                                                char __user *user_buf,
1317                                                size_t count, loff_t *ppos)
1318{
1319        struct ieee80211_vif *vif = file->private_data;
1320        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1321        char buf[20];
1322        int len;
1323
1324        len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
1325        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1326}
1327
1328static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
1329                                                 char *buf, size_t count,
1330                                                 loff_t *ppos)
1331{
1332        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1333        struct iwl_mvm *mvm = mvmvif->mvm;
1334        bool ret;
1335
1336        mutex_lock(&mvm->mutex);
1337        ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
1338        mutex_unlock(&mvm->mutex);
1339
1340        return ret ? count : -EINVAL;
1341}
1342
1343static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
1344                                          size_t count, loff_t *ppos)
1345{
1346        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1347        struct iwl_mvm *mvm = mvmvif->mvm;
1348        struct ieee80211_chanctx_conf *chanctx_conf;
1349        struct iwl_mvm_phy_ctxt *phy_ctxt;
1350        u16 value;
1351        int ret;
1352
1353        ret = kstrtou16(buf, 0, &value);
1354        if (ret)
1355                return ret;
1356
1357        mutex_lock(&mvm->mutex);
1358        rcu_read_lock();
1359
1360        chanctx_conf = rcu_dereference(vif->chanctx_conf);
1361        /* make sure the channel context is assigned */
1362        if (!chanctx_conf) {
1363                rcu_read_unlock();
1364                mutex_unlock(&mvm->mutex);
1365                return -EINVAL;
1366        }
1367
1368        phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
1369        rcu_read_unlock();
1370
1371        mvm->dbgfs_rx_phyinfo = value;
1372
1373        ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
1374                                       chanctx_conf->rx_chains_static,
1375                                       chanctx_conf->rx_chains_dynamic);
1376        mutex_unlock(&mvm->mutex);
1377
1378        return ret ?: count;
1379}
1380
1381static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
1382                                         char __user *user_buf,
1383                                         size_t count, loff_t *ppos)
1384{
1385        struct ieee80211_vif *vif = file->private_data;
1386        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1387        char buf[8];
1388        int len;
1389
1390        len = scnprintf(buf, sizeof(buf), "0x%04x\n",
1391                        mvmvif->mvm->dbgfs_rx_phyinfo);
1392
1393        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1394}
1395
1396static void iwl_dbgfs_quota_check(void *data, u8 *mac,
1397                                  struct ieee80211_vif *vif)
1398{
1399        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1400        int *ret = data;
1401
1402        if (mvmvif->dbgfs_quota_min)
1403                *ret = -EINVAL;
1404}
1405
1406static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
1407                                         size_t count, loff_t *ppos)
1408{
1409        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1410        struct iwl_mvm *mvm = mvmvif->mvm;
1411        u16 value;
1412        int ret;
1413
1414        ret = kstrtou16(buf, 0, &value);
1415        if (ret)
1416                return ret;
1417
1418        if (value > 95)
1419                return -EINVAL;
1420
1421        mutex_lock(&mvm->mutex);
1422
1423        mvmvif->dbgfs_quota_min = 0;
1424        ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1425                                     iwl_dbgfs_quota_check, &ret);
1426        if (ret == 0) {
1427                mvmvif->dbgfs_quota_min = value;
1428                iwl_mvm_update_quotas(mvm, false, NULL);
1429        }
1430        mutex_unlock(&mvm->mutex);
1431
1432        return ret ?: count;
1433}
1434
1435static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
1436                                        char __user *user_buf,
1437                                        size_t count, loff_t *ppos)
1438{
1439        struct ieee80211_vif *vif = file->private_data;
1440        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1441        char buf[10];
1442        int len;
1443
1444        len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
1445
1446        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1447}
1448
1449static const char * const chanwidths[] = {
1450        [NL80211_CHAN_WIDTH_20_NOHT] = "noht",
1451        [NL80211_CHAN_WIDTH_20] = "ht20",
1452        [NL80211_CHAN_WIDTH_40] = "ht40",
1453        [NL80211_CHAN_WIDTH_80] = "vht80",
1454        [NL80211_CHAN_WIDTH_80P80] = "vht80p80",
1455        [NL80211_CHAN_WIDTH_160] = "vht160",
1456};
1457
1458static bool iwl_mvm_lqm_notif_wait(struct iwl_notif_wait_data *notif_wait,
1459                                   struct iwl_rx_packet *pkt, void *data)
1460{
1461        struct ieee80211_vif *vif = data;
1462        struct iwl_mvm *mvm =
1463                container_of(notif_wait, struct iwl_mvm, notif_wait);
1464        struct iwl_link_qual_msrmnt_notif *report = (void *)pkt->data;
1465        u32 num_of_stations = le32_to_cpu(report->number_of_stations);
1466        int i;
1467
1468        IWL_INFO(mvm, "LQM report:\n");
1469        IWL_INFO(mvm, "\tstatus: %d\n", report->status);
1470        IWL_INFO(mvm, "\tmacID: %d\n", le32_to_cpu(report->mac_id));
1471        IWL_INFO(mvm, "\ttx_frame_dropped: %d\n",
1472                 le32_to_cpu(report->tx_frame_dropped));
1473        IWL_INFO(mvm, "\ttime_in_measurement_window: %d us\n",
1474                 le32_to_cpu(report->time_in_measurement_window));
1475        IWL_INFO(mvm, "\ttotal_air_time_other_stations: %d\n",
1476                 le32_to_cpu(report->total_air_time_other_stations));
1477        IWL_INFO(mvm, "\tchannel_freq: %d\n",
1478                 vif->bss_conf.chandef.center_freq1);
1479        IWL_INFO(mvm, "\tchannel_width: %s\n",
1480                 chanwidths[vif->bss_conf.chandef.width]);
1481        IWL_INFO(mvm, "\tnumber_of_stations: %d\n", num_of_stations);
1482        for (i = 0; i < num_of_stations; i++)
1483                IWL_INFO(mvm, "\t\tsta[%d]: %d\n", i,
1484                         report->frequent_stations_air_time[i]);
1485
1486        return true;
1487}
1488
1489static ssize_t iwl_dbgfs_lqm_send_cmd_write(struct ieee80211_vif *vif,
1490                                            char *buf, size_t count,
1491                                            loff_t *ppos)
1492{
1493        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1494        struct iwl_mvm *mvm = mvmvif->mvm;
1495        struct iwl_notification_wait wait_lqm_notif;
1496        static u16 lqm_notif[] = {
1497                WIDE_ID(MAC_CONF_GROUP,
1498                        LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF)
1499        };
1500        int err;
1501        u32 duration;
1502        u32 timeout;
1503
1504        if (sscanf(buf, "%d,%d", &duration, &timeout) != 2)
1505                return -EINVAL;
1506
1507        iwl_init_notification_wait(&mvm->notif_wait, &wait_lqm_notif,
1508                                   lqm_notif, ARRAY_SIZE(lqm_notif),
1509                                   iwl_mvm_lqm_notif_wait, vif);
1510        mutex_lock(&mvm->mutex);
1511        err = iwl_mvm_send_lqm_cmd(vif, LQM_CMD_OPERATION_START_MEASUREMENT,
1512                                   duration, timeout);
1513        mutex_unlock(&mvm->mutex);
1514
1515        if (err) {
1516                IWL_ERR(mvm, "Failed to send lqm cmdf(err=%d)\n", err);
1517                iwl_remove_notification(&mvm->notif_wait, &wait_lqm_notif);
1518                return err;
1519        }
1520
1521        /* wait for 2 * timeout (safety guard) and convert to jiffies*/
1522        timeout = msecs_to_jiffies((timeout * 2) / 1000);
1523
1524        err = iwl_wait_notification(&mvm->notif_wait, &wait_lqm_notif,
1525                                    timeout);
1526        if (err)
1527                IWL_ERR(mvm, "Getting lqm notif timed out\n");
1528
1529        return count;
1530}
1531
1532#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1533        _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1534#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1535        _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1536#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {               \
1537                if (!debugfs_create_file(#name, mode, parent, vif,      \
1538                                         &iwl_dbgfs_##name##_ops))      \
1539                        goto err;                                       \
1540        } while (0)
1541
1542MVM_DEBUGFS_READ_FILE_OPS(mac_params);
1543MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
1544MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
1545MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
1546MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
1547MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
1548MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
1549MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32);
1550MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512);
1551MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
1552MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
1553MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
1554MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
1555MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
1556MVM_DEBUGFS_WRITE_FILE_OPS(lqm_send_cmd, 64);
1557MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
1558
1559
1560void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1561{
1562        struct dentry *dbgfs_dir = vif->debugfs_dir;
1563        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1564        char buf[100];
1565
1566        /*
1567         * Check if debugfs directory already exist before creating it.
1568         * This may happen when, for example, resetting hw or suspend-resume
1569         */
1570        if (!dbgfs_dir || mvmvif->dbgfs_dir)
1571                return;
1572
1573        mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
1574
1575        if (!mvmvif->dbgfs_dir) {
1576                IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
1577                        dbgfs_dir);
1578                return;
1579        }
1580
1581        if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
1582            ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
1583             (vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
1584                MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
1585                                         S_IRUSR);
1586
1587        MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR);
1588        MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR);
1589        MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir,
1590                                 S_IRUSR | S_IWUSR);
1591        MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir,
1592                                 S_IRUSR | S_IWUSR);
1593        MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir,
1594                                 S_IRUSR | S_IWUSR);
1595        MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
1596                                 S_IRUSR | S_IWUSR);
1597        MVM_DEBUGFS_ADD_FILE_VIF(lqm_send_cmd, mvmvif->dbgfs_dir, S_IWUSR);
1598        MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff,
1599                                 mvmvif->dbgfs_dir, S_IRUSR);
1600
1601        if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
1602            mvmvif == mvm->bf_allowed_vif)
1603                MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
1604                                         S_IRUSR | S_IWUSR);
1605
1606        if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) &&
1607            !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) {
1608                if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP)
1609                        MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params,
1610                                                 mvmvif->dbgfs_dir,
1611                                                 S_IRUSR | S_IWUSR);
1612
1613                MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir,
1614                                         S_IRUSR | S_IWUSR);
1615                MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir,
1616                                         S_IRUSR | S_IWUSR);
1617                MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir,
1618                                         S_IRUSR | S_IWUSR);
1619                MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir,
1620                                         S_IRUSR | S_IWUSR);
1621                MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir,
1622                                         S_IRUSR);
1623        }
1624
1625        /*
1626         * Create symlink for convenience pointing to interface specific
1627         * debugfs entries for the driver. For example, under
1628         * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
1629         * find
1630         * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
1631         */
1632        snprintf(buf, 100, "../../../%pd3/%pd",
1633                 dbgfs_dir,
1634                 mvmvif->dbgfs_dir);
1635
1636        mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
1637                                                     mvm->debugfs_dir, buf);
1638        if (!mvmvif->dbgfs_slink)
1639                IWL_ERR(mvm, "Can't create debugfs symbolic link under %pd\n",
1640                        dbgfs_dir);
1641        return;
1642err:
1643        IWL_ERR(mvm, "Can't create debugfs entity\n");
1644}
1645
1646void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1647{
1648        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1649
1650        debugfs_remove(mvmvif->dbgfs_slink);
1651        mvmvif->dbgfs_slink = NULL;
1652
1653        debugfs_remove_recursive(mvmvif->dbgfs_dir);
1654        mvmvif->dbgfs_dir = NULL;
1655}
1656