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 * The full GNU General Public License is included in this distribution
  22 * in the file called COPYING.
  23 *
  24 * Contact Information:
  25 *  Intel Linux Wireless <linuxwifi@intel.com>
  26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  27 *
  28 * BSD LICENSE
  29 *
  30 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  31 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  32 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
  33 * All rights reserved.
  34 *
  35 * Redistribution and use in source and binary forms, with or without
  36 * modification, are permitted provided that the following conditions
  37 * are met:
  38 *
  39 *  * Redistributions of source code must retain the above copyright
  40 *    notice, this list of conditions and the following disclaimer.
  41 *  * Redistributions in binary form must reproduce the above copyright
  42 *    notice, this list of conditions and the following disclaimer in
  43 *    the documentation and/or other materials provided with the
  44 *    distribution.
  45 *  * Neither the name Intel Corporation nor the names of its
  46 *    contributors may be used to endorse or promote products derived
  47 *    from this software without specific prior written permission.
  48 *
  49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  53 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  55 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  59 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  60 *
  61 *****************************************************************************/
  62#include "mvm.h"
  63#include "debugfs.h"
  64
  65static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
  66                                 struct ieee80211_vif *vif,
  67                                 enum iwl_dbgfs_pm_mask param, int val)
  68{
  69        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  70        struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
  71
  72        dbgfs_pm->mask |= param;
  73
  74        switch (param) {
  75        case MVM_DEBUGFS_PM_KEEP_ALIVE: {
  76                int dtimper = vif->bss_conf.dtim_period ?: 1;
  77                int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
  78
  79                IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
  80                if (val * MSEC_PER_SEC < 3 * dtimper_msec)
  81                        IWL_WARN(mvm,
  82                                 "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
  83                                 val * MSEC_PER_SEC, 3 * dtimper_msec);
  84                dbgfs_pm->keep_alive_seconds = val;
  85                break;
  86        }
  87        case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
  88                IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
  89                                val ? "enabled" : "disabled");
  90                dbgfs_pm->skip_over_dtim = val;
  91                break;
  92        case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
  93                IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
  94                dbgfs_pm->skip_dtim_periods = val;
  95                break;
  96        case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
  97                IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
  98                dbgfs_pm->rx_data_timeout = val;
  99                break;
 100        case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
 101                IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
 102                dbgfs_pm->tx_data_timeout = val;
 103                break;
 104        case MVM_DEBUGFS_PM_LPRX_ENA:
 105                IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
 106                dbgfs_pm->lprx_ena = val;
 107                break;
 108        case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
 109                IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
 110                dbgfs_pm->lprx_rssi_threshold = val;
 111                break;
 112        case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
 113                IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
 114                dbgfs_pm->snooze_ena = val;
 115                break;
 116        case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
 117                IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
 118                dbgfs_pm->uapsd_misbehaving = val;
 119                break;
 120        case MVM_DEBUGFS_PM_USE_PS_POLL:
 121                IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val);
 122                dbgfs_pm->use_ps_poll = val;
 123                break;
 124        }
 125}
 126
 127static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
 128                                         size_t count, loff_t *ppos)
 129{
 130        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 131        struct iwl_mvm *mvm = mvmvif->mvm;
 132        enum iwl_dbgfs_pm_mask param;
 133        int val, ret;
 134
 135        if (!strncmp("keep_alive=", buf, 11)) {
 136                if (sscanf(buf + 11, "%d", &val) != 1)
 137                        return -EINVAL;
 138                param = MVM_DEBUGFS_PM_KEEP_ALIVE;
 139        } else if (!strncmp("skip_over_dtim=", buf, 15)) {
 140                if (sscanf(buf + 15, "%d", &val) != 1)
 141                        return -EINVAL;
 142                param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
 143        } else if (!strncmp("skip_dtim_periods=", buf, 18)) {
 144                if (sscanf(buf + 18, "%d", &val) != 1)
 145                        return -EINVAL;
 146                param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
 147        } else if (!strncmp("rx_data_timeout=", buf, 16)) {
 148                if (sscanf(buf + 16, "%d", &val) != 1)
 149                        return -EINVAL;
 150                param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
 151        } else if (!strncmp("tx_data_timeout=", buf, 16)) {
 152                if (sscanf(buf + 16, "%d", &val) != 1)
 153                        return -EINVAL;
 154                param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
 155        } else if (!strncmp("lprx=", buf, 5)) {
 156                if (sscanf(buf + 5, "%d", &val) != 1)
 157                        return -EINVAL;
 158                param = MVM_DEBUGFS_PM_LPRX_ENA;
 159        } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
 160                if (sscanf(buf + 20, "%d", &val) != 1)
 161                        return -EINVAL;
 162                if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
 163                    POWER_LPRX_RSSI_THRESHOLD_MIN)
 164                        return -EINVAL;
 165                param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
 166        } else if (!strncmp("snooze_enable=", buf, 14)) {
 167                if (sscanf(buf + 14, "%d", &val) != 1)
 168                        return -EINVAL;
 169                param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
 170        } else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
 171                if (sscanf(buf + 18, "%d", &val) != 1)
 172                        return -EINVAL;
 173                param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
 174        } else if (!strncmp("use_ps_poll=", buf, 12)) {
 175                if (sscanf(buf + 12, "%d", &val) != 1)
 176                        return -EINVAL;
 177                param = MVM_DEBUGFS_PM_USE_PS_POLL;
 178        } else {
 179                return -EINVAL;
 180        }
 181
 182        mutex_lock(&mvm->mutex);
 183        iwl_dbgfs_update_pm(mvm, vif, param, val);
 184        ret = iwl_mvm_power_update_mac(mvm);
 185        mutex_unlock(&mvm->mutex);
 186
 187        return ret ?: count;
 188}
 189
 190static ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file,
 191                                         char __user *user_buf,
 192                                         size_t count, loff_t *ppos)
 193{
 194        struct ieee80211_vif *vif = file->private_data;
 195        char buf[64];
 196        int bufsz = sizeof(buf);
 197        int pos;
 198
 199        pos = scnprintf(buf, bufsz, "bss limit = %d\n",
 200                        vif->bss_conf.txpower);
 201
 202        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 203}
 204
 205static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
 206                                        char __user *user_buf,
 207                                        size_t count, loff_t *ppos)
 208{
 209        struct ieee80211_vif *vif = file->private_data;
 210        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 211        struct iwl_mvm *mvm = mvmvif->mvm;
 212        char buf[512];
 213        int bufsz = sizeof(buf);
 214        int pos;
 215
 216        pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz);
 217
 218        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 219}
 220
 221static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
 222                                         char __user *user_buf,
 223                                         size_t count, loff_t *ppos)
 224{
 225        struct ieee80211_vif *vif = file->private_data;
 226        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 227        struct iwl_mvm *mvm = mvmvif->mvm;
 228        u8 ap_sta_id;
 229        struct ieee80211_chanctx_conf *chanctx_conf;
 230        char buf[512];
 231        int bufsz = sizeof(buf);
 232        int pos = 0;
 233        int i;
 234
 235        mutex_lock(&mvm->mutex);
 236
 237        ap_sta_id = mvmvif->ap_sta_id;
 238
 239        switch (ieee80211_vif_type_p2p(vif)) {
 240        case NL80211_IFTYPE_ADHOC:
 241                pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n");
 242                break;
 243        case NL80211_IFTYPE_STATION:
 244                pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n");
 245                break;
 246        case NL80211_IFTYPE_AP:
 247                pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n");
 248                break;
 249        case NL80211_IFTYPE_P2P_CLIENT:
 250                pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n");
 251                break;
 252        case NL80211_IFTYPE_P2P_GO:
 253                pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n");
 254                break;
 255        case NL80211_IFTYPE_P2P_DEVICE:
 256                pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n");
 257                break;
 258        default:
 259                break;
 260        }
 261
 262        pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
 263                         mvmvif->id, mvmvif->color);
 264        pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
 265                         vif->bss_conf.bssid);
 266        pos += scnprintf(buf+pos, bufsz-pos, "Load: %d\n",
 267                         mvm->tcm.result.load[mvmvif->id]);
 268        pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
 269        for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++)
 270                pos += scnprintf(buf+pos, bufsz-pos,
 271                                 "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
 272                                 i, mvmvif->queue_params[i].txop,
 273                                 mvmvif->queue_params[i].cw_min,
 274                                 mvmvif->queue_params[i].cw_max,
 275                                 mvmvif->queue_params[i].aifs,
 276                                 mvmvif->queue_params[i].uapsd);
 277
 278        if (vif->type == NL80211_IFTYPE_STATION &&
 279            ap_sta_id != IWL_MVM_INVALID_STA) {
 280                struct iwl_mvm_sta *mvm_sta;
 281
 282                mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id);
 283                if (mvm_sta) {
 284                        pos += scnprintf(buf+pos, bufsz-pos,
 285                                         "ap_sta_id %d - reduced Tx power %d\n",
 286                                         ap_sta_id,
 287                                         mvm_sta->bt_reduced_txpower);
 288                }
 289        }
 290
 291        rcu_read_lock();
 292        chanctx_conf = rcu_dereference(vif->chanctx_conf);
 293        if (chanctx_conf)
 294                pos += scnprintf(buf+pos, bufsz-pos,
 295                                 "idle rx chains %d, active rx chains: %d\n",
 296                                 chanctx_conf->rx_chains_static,
 297                                 chanctx_conf->rx_chains_dynamic);
 298        rcu_read_unlock();
 299
 300        mutex_unlock(&mvm->mutex);
 301
 302        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 303}
 304
 305static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
 306                                enum iwl_dbgfs_bf_mask param, int value)
 307{
 308        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 309        struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
 310
 311        dbgfs_bf->mask |= param;
 312
 313        switch (param) {
 314        case MVM_DEBUGFS_BF_ENERGY_DELTA:
 315                dbgfs_bf->bf_energy_delta = value;
 316                break;
 317        case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
 318                dbgfs_bf->bf_roaming_energy_delta = value;
 319                break;
 320        case MVM_DEBUGFS_BF_ROAMING_STATE:
 321                dbgfs_bf->bf_roaming_state = value;
 322                break;
 323        case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
 324                dbgfs_bf->bf_temp_threshold = value;
 325                break;
 326        case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
 327                dbgfs_bf->bf_temp_fast_filter = value;
 328                break;
 329        case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
 330                dbgfs_bf->bf_temp_slow_filter = value;
 331                break;
 332        case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
 333                dbgfs_bf->bf_enable_beacon_filter = value;
 334                break;
 335        case MVM_DEBUGFS_BF_DEBUG_FLAG:
 336                dbgfs_bf->bf_debug_flag = value;
 337                break;
 338        case MVM_DEBUGFS_BF_ESCAPE_TIMER:
 339                dbgfs_bf->bf_escape_timer = value;
 340                break;
 341        case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
 342                dbgfs_bf->ba_enable_beacon_abort = value;
 343                break;
 344        case MVM_DEBUGFS_BA_ESCAPE_TIMER:
 345                dbgfs_bf->ba_escape_timer = value;
 346                break;
 347        }
 348}
 349
 350static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
 351                                         size_t count, loff_t *ppos)
 352{
 353        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 354        struct iwl_mvm *mvm = mvmvif->mvm;
 355        enum iwl_dbgfs_bf_mask param;
 356        int value, ret = 0;
 357
 358        if (!strncmp("bf_energy_delta=", buf, 16)) {
 359                if (sscanf(buf+16, "%d", &value) != 1)
 360                        return -EINVAL;
 361                if (value < IWL_BF_ENERGY_DELTA_MIN ||
 362                    value > IWL_BF_ENERGY_DELTA_MAX)
 363                        return -EINVAL;
 364                param = MVM_DEBUGFS_BF_ENERGY_DELTA;
 365        } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
 366                if (sscanf(buf+24, "%d", &value) != 1)
 367                        return -EINVAL;
 368                if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
 369                    value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
 370                        return -EINVAL;
 371                param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
 372        } else if (!strncmp("bf_roaming_state=", buf, 17)) {
 373                if (sscanf(buf+17, "%d", &value) != 1)
 374                        return -EINVAL;
 375                if (value < IWL_BF_ROAMING_STATE_MIN ||
 376                    value > IWL_BF_ROAMING_STATE_MAX)
 377                        return -EINVAL;
 378                param = MVM_DEBUGFS_BF_ROAMING_STATE;
 379        } else if (!strncmp("bf_temp_threshold=", buf, 18)) {
 380                if (sscanf(buf+18, "%d", &value) != 1)
 381                        return -EINVAL;
 382                if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
 383                    value > IWL_BF_TEMP_THRESHOLD_MAX)
 384                        return -EINVAL;
 385                param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
 386        } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
 387                if (sscanf(buf+20, "%d", &value) != 1)
 388                        return -EINVAL;
 389                if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
 390                    value > IWL_BF_TEMP_FAST_FILTER_MAX)
 391                        return -EINVAL;
 392                param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
 393        } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
 394                if (sscanf(buf+20, "%d", &value) != 1)
 395                        return -EINVAL;
 396                if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
 397                    value > IWL_BF_TEMP_SLOW_FILTER_MAX)
 398                        return -EINVAL;
 399                param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
 400        } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
 401                if (sscanf(buf+24, "%d", &value) != 1)
 402                        return -EINVAL;
 403                if (value < 0 || value > 1)
 404                        return -EINVAL;
 405                param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
 406        } else if (!strncmp("bf_debug_flag=", buf, 14)) {
 407                if (sscanf(buf+14, "%d", &value) != 1)
 408                        return -EINVAL;
 409                if (value < 0 || value > 1)
 410                        return -EINVAL;
 411                param = MVM_DEBUGFS_BF_DEBUG_FLAG;
 412        } else if (!strncmp("bf_escape_timer=", buf, 16)) {
 413                if (sscanf(buf+16, "%d", &value) != 1)
 414                        return -EINVAL;
 415                if (value < IWL_BF_ESCAPE_TIMER_MIN ||
 416                    value > IWL_BF_ESCAPE_TIMER_MAX)
 417                        return -EINVAL;
 418                param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
 419        } else if (!strncmp("ba_escape_timer=", buf, 16)) {
 420                if (sscanf(buf+16, "%d", &value) != 1)
 421                        return -EINVAL;
 422                if (value < IWL_BA_ESCAPE_TIMER_MIN ||
 423                    value > IWL_BA_ESCAPE_TIMER_MAX)
 424                        return -EINVAL;
 425                param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
 426        } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
 427                if (sscanf(buf+23, "%d", &value) != 1)
 428                        return -EINVAL;
 429                if (value < 0 || value > 1)
 430                        return -EINVAL;
 431                param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
 432        } else {
 433                return -EINVAL;
 434        }
 435
 436        mutex_lock(&mvm->mutex);
 437        iwl_dbgfs_update_bf(vif, param, value);
 438        if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
 439                ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
 440        else
 441                ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0);
 442        mutex_unlock(&mvm->mutex);
 443
 444        return ret ?: count;
 445}
 446
 447static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
 448                                        char __user *user_buf,
 449                                        size_t count, loff_t *ppos)
 450{
 451        struct ieee80211_vif *vif = file->private_data;
 452        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 453        char buf[256];
 454        int pos = 0;
 455        const size_t bufsz = sizeof(buf);
 456        struct iwl_beacon_filter_cmd cmd = {
 457                IWL_BF_CMD_CONFIG_DEFAULTS,
 458                .bf_enable_beacon_filter =
 459                        cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
 460                .ba_enable_beacon_abort =
 461                        cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
 462        };
 463
 464        iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
 465        if (mvmvif->bf_data.bf_enabled)
 466                cmd.bf_enable_beacon_filter = cpu_to_le32(1);
 467        else
 468                cmd.bf_enable_beacon_filter = 0;
 469
 470        pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
 471                         le32_to_cpu(cmd.bf_energy_delta));
 472        pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
 473                         le32_to_cpu(cmd.bf_roaming_energy_delta));
 474        pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
 475                         le32_to_cpu(cmd.bf_roaming_state));
 476        pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
 477                         le32_to_cpu(cmd.bf_temp_threshold));
 478        pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
 479                         le32_to_cpu(cmd.bf_temp_fast_filter));
 480        pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
 481                         le32_to_cpu(cmd.bf_temp_slow_filter));
 482        pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
 483                         le32_to_cpu(cmd.bf_enable_beacon_filter));
 484        pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
 485                         le32_to_cpu(cmd.bf_debug_flag));
 486        pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
 487                         le32_to_cpu(cmd.bf_escape_timer));
 488        pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
 489                         le32_to_cpu(cmd.ba_escape_timer));
 490        pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
 491                         le32_to_cpu(cmd.ba_enable_beacon_abort));
 492
 493        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 494}
 495
 496static inline char *iwl_dbgfs_is_match(char *name, char *buf)
 497{
 498        int len = strlen(name);
 499
 500        return !strncmp(name, buf, len) ? buf + len : NULL;
 501}
 502
 503static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,
 504                                                 char __user *user_buf,
 505                                                 size_t count, loff_t *ppos)
 506{
 507        struct ieee80211_vif *vif = file->private_data;
 508        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 509        struct iwl_mvm *mvm = mvmvif->mvm;
 510        u32 curr_gp2;
 511        u64 curr_os;
 512        s64 diff;
 513        char buf[64];
 514        const size_t bufsz = sizeof(buf);
 515        int pos = 0;
 516
 517        iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os);
 518        do_div(curr_os, NSEC_PER_USEC);
 519        diff = curr_os - curr_gp2;
 520        pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff);
 521
 522        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 523}
 524
 525static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
 526                                           size_t count, loff_t *ppos)
 527{
 528        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 529        struct iwl_mvm *mvm = mvmvif->mvm;
 530        u8 value;
 531        int ret;
 532
 533        ret = kstrtou8(buf, 0, &value);
 534        if (ret)
 535                return ret;
 536        if (value > 1)
 537                return -EINVAL;
 538
 539        mutex_lock(&mvm->mutex);
 540        iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS);
 541        mutex_unlock(&mvm->mutex);
 542
 543        return count;
 544}
 545
 546static ssize_t
 547iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf,
 548                                  size_t count, loff_t *ppos)
 549{
 550        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 551        struct iwl_mvm *mvm = mvmvif->mvm;
 552        u8 value;
 553        int ret;
 554
 555        ret = kstrtou8(buf, 0, &value);
 556        if (ret)
 557                return ret;
 558
 559        if (value > NUM_LOW_LATENCY_FORCE)
 560                return -EINVAL;
 561
 562        mutex_lock(&mvm->mutex);
 563        if (value == LOW_LATENCY_FORCE_UNSET) {
 564                iwl_mvm_update_low_latency(mvm, vif, false,
 565                                           LOW_LATENCY_DEBUGFS_FORCE);
 566                iwl_mvm_update_low_latency(mvm, vif, false,
 567                                           LOW_LATENCY_DEBUGFS_FORCE_ENABLE);
 568        } else {
 569                iwl_mvm_update_low_latency(mvm, vif,
 570                                           value == LOW_LATENCY_FORCE_ON,
 571                                           LOW_LATENCY_DEBUGFS_FORCE);
 572                iwl_mvm_update_low_latency(mvm, vif, true,
 573                                           LOW_LATENCY_DEBUGFS_FORCE_ENABLE);
 574        }
 575        mutex_unlock(&mvm->mutex);
 576        return count;
 577}
 578
 579static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
 580                                          char __user *user_buf,
 581                                          size_t count, loff_t *ppos)
 582{
 583        struct ieee80211_vif *vif = file->private_data;
 584        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 585        char format[] = "traffic=%d\ndbgfs=%d\nvcmd=%d\nvif_type=%d\n"
 586                        "dbgfs_force_enable=%d\ndbgfs_force=%d\nactual=%d\n";
 587
 588        /*
 589         * all values in format are boolean so the size of format is enough
 590         * for holding the result string
 591         */
 592        char buf[sizeof(format) + 1] = {};
 593        int len;
 594
 595        len = scnprintf(buf, sizeof(buf) - 1, format,
 596                        !!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC),
 597                        !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS),
 598                        !!(mvmvif->low_latency & LOW_LATENCY_VCMD),
 599                        !!(mvmvif->low_latency & LOW_LATENCY_VIF_TYPE),
 600                        !!(mvmvif->low_latency &
 601                           LOW_LATENCY_DEBUGFS_FORCE_ENABLE),
 602                        !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS_FORCE),
 603                        !!(mvmvif->low_latency_actual));
 604        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 605}
 606
 607static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
 608                                                char __user *user_buf,
 609                                                size_t count, loff_t *ppos)
 610{
 611        struct ieee80211_vif *vif = file->private_data;
 612        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 613        char buf[20];
 614        int len;
 615
 616        len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
 617        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 618}
 619
 620static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
 621                                                 char *buf, size_t count,
 622                                                 loff_t *ppos)
 623{
 624        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 625        struct iwl_mvm *mvm = mvmvif->mvm;
 626        bool ret;
 627
 628        mutex_lock(&mvm->mutex);
 629        ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
 630        mutex_unlock(&mvm->mutex);
 631
 632        return ret ? count : -EINVAL;
 633}
 634
 635static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
 636                                          size_t count, loff_t *ppos)
 637{
 638        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 639        struct iwl_mvm *mvm = mvmvif->mvm;
 640        struct ieee80211_chanctx_conf *chanctx_conf;
 641        struct iwl_mvm_phy_ctxt *phy_ctxt;
 642        u16 value;
 643        int ret;
 644
 645        ret = kstrtou16(buf, 0, &value);
 646        if (ret)
 647                return ret;
 648
 649        mutex_lock(&mvm->mutex);
 650        rcu_read_lock();
 651
 652        chanctx_conf = rcu_dereference(vif->chanctx_conf);
 653        /* make sure the channel context is assigned */
 654        if (!chanctx_conf) {
 655                rcu_read_unlock();
 656                mutex_unlock(&mvm->mutex);
 657                return -EINVAL;
 658        }
 659
 660        phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
 661        rcu_read_unlock();
 662
 663        mvm->dbgfs_rx_phyinfo = value;
 664
 665        ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
 666                                       chanctx_conf->rx_chains_static,
 667                                       chanctx_conf->rx_chains_dynamic);
 668        mutex_unlock(&mvm->mutex);
 669
 670        return ret ?: count;
 671}
 672
 673static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
 674                                         char __user *user_buf,
 675                                         size_t count, loff_t *ppos)
 676{
 677        struct ieee80211_vif *vif = file->private_data;
 678        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 679        char buf[8];
 680        int len;
 681
 682        len = scnprintf(buf, sizeof(buf), "0x%04x\n",
 683                        mvmvif->mvm->dbgfs_rx_phyinfo);
 684
 685        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 686}
 687
 688static void iwl_dbgfs_quota_check(void *data, u8 *mac,
 689                                  struct ieee80211_vif *vif)
 690{
 691        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 692        int *ret = data;
 693
 694        if (mvmvif->dbgfs_quota_min)
 695                *ret = -EINVAL;
 696}
 697
 698static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
 699                                         size_t count, loff_t *ppos)
 700{
 701        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 702        struct iwl_mvm *mvm = mvmvif->mvm;
 703        u16 value;
 704        int ret;
 705
 706        ret = kstrtou16(buf, 0, &value);
 707        if (ret)
 708                return ret;
 709
 710        if (value > 95)
 711                return -EINVAL;
 712
 713        mutex_lock(&mvm->mutex);
 714
 715        mvmvif->dbgfs_quota_min = 0;
 716        ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
 717                                     iwl_dbgfs_quota_check, &ret);
 718        if (ret == 0) {
 719                mvmvif->dbgfs_quota_min = value;
 720                iwl_mvm_update_quotas(mvm, false, NULL);
 721        }
 722        mutex_unlock(&mvm->mutex);
 723
 724        return ret ?: count;
 725}
 726
 727static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
 728                                        char __user *user_buf,
 729                                        size_t count, loff_t *ppos)
 730{
 731        struct ieee80211_vif *vif = file->private_data;
 732        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 733        char buf[10];
 734        int len;
 735
 736        len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
 737
 738        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 739}
 740
 741#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
 742        _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
 743#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
 744        _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
 745#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {               \
 746                debugfs_create_file(#name, mode, parent, vif,           \
 747                                    &iwl_dbgfs_##name##_ops);           \
 748        } while (0)
 749
 750MVM_DEBUGFS_READ_FILE_OPS(mac_params);
 751MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
 752MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
 753MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
 754MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
 755MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10);
 756MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
 757MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
 758MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
 759MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
 760
 761
 762void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 763{
 764        struct dentry *dbgfs_dir = vif->debugfs_dir;
 765        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 766        char buf[100];
 767
 768        /*
 769         * Check if debugfs directory already exist before creating it.
 770         * This may happen when, for example, resetting hw or suspend-resume
 771         */
 772        if (!dbgfs_dir || mvmvif->dbgfs_dir)
 773                return;
 774
 775        mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
 776        if (IS_ERR_OR_NULL(mvmvif->dbgfs_dir)) {
 777                IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
 778                        dbgfs_dir);
 779                return;
 780        }
 781
 782        if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
 783            ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
 784             (vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
 785                MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600);
 786
 787        MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400);
 788        MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400);
 789        MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600);
 790        MVM_DEBUGFS_ADD_FILE_VIF(low_latency_force, mvmvif->dbgfs_dir, 0600);
 791        MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600);
 792        MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600);
 793        MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600);
 794        MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400);
 795
 796        if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
 797            mvmvif == mvm->bf_allowed_vif)
 798                MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600);
 799
 800        /*
 801         * Create symlink for convenience pointing to interface specific
 802         * debugfs entries for the driver. For example, under
 803         * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
 804         * find
 805         * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
 806         */
 807        snprintf(buf, 100, "../../../%pd3/%pd",
 808                 dbgfs_dir,
 809                 mvmvif->dbgfs_dir);
 810
 811        mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
 812                                                     mvm->debugfs_dir, buf);
 813}
 814
 815void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 816{
 817        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 818
 819        debugfs_remove(mvmvif->dbgfs_slink);
 820        mvmvif->dbgfs_slink = NULL;
 821
 822        debugfs_remove_recursive(mvmvif->dbgfs_dir);
 823        mvmvif->dbgfs_dir = NULL;
 824}
 825