linux/drivers/net/wireless/iwlwifi/mvm/debugfs.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * This file is provided under a dual BSD/GPLv2 license.  When using or
   4 * redistributing this file, you may do so under either license.
   5 *
   6 * GPL LICENSE SUMMARY
   7 *
   8 * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of version 2 of the GNU General Public License as
  12 * published by the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but
  15 * WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  22 * USA
  23 *
  24 * The full GNU General Public License is included in this distribution
  25 * in the file called COPYING.
  26 *
  27 * Contact Information:
  28 *  Intel Linux Wireless <ilw@linux.intel.com>
  29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  30 *
  31 * BSD LICENSE
  32 *
  33 * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
  34 * All rights reserved.
  35 *
  36 * Redistribution and use in source and binary forms, with or without
  37 * modification, are permitted provided that the following conditions
  38 * are met:
  39 *
  40 *  * Redistributions of source code must retain the above copyright
  41 *    notice, this list of conditions and the following disclaimer.
  42 *  * Redistributions in binary form must reproduce the above copyright
  43 *    notice, this list of conditions and the following disclaimer in
  44 *    the documentation and/or other materials provided with the
  45 *    distribution.
  46 *  * Neither the name Intel Corporation nor the names of its
  47 *    contributors may be used to endorse or promote products derived
  48 *    from this software without specific prior written permission.
  49 *
  50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61 *
  62 *****************************************************************************/
  63#include "mvm.h"
  64#include "sta.h"
  65#include "iwl-io.h"
  66
  67struct iwl_dbgfs_mvm_ctx {
  68        struct iwl_mvm *mvm;
  69        struct ieee80211_vif *vif;
  70};
  71
  72static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
  73                                        const char __user *user_buf,
  74                                        size_t count, loff_t *ppos)
  75{
  76        struct iwl_mvm *mvm = file->private_data;
  77
  78        char buf[16];
  79        int buf_size, ret;
  80        u32 scd_q_msk;
  81
  82        if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
  83                return -EIO;
  84
  85        memset(buf, 0, sizeof(buf));
  86        buf_size = min(count, sizeof(buf) - 1);
  87        if (copy_from_user(buf, user_buf, buf_size))
  88                return -EFAULT;
  89
  90        if (sscanf(buf, "%x", &scd_q_msk) != 1)
  91                return -EINVAL;
  92
  93        IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk);
  94
  95        mutex_lock(&mvm->mutex);
  96        ret =  iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count;
  97        mutex_unlock(&mvm->mutex);
  98
  99        return ret;
 100}
 101
 102static ssize_t iwl_dbgfs_sta_drain_write(struct file *file,
 103                                         const char __user *user_buf,
 104                                         size_t count, loff_t *ppos)
 105{
 106        struct iwl_mvm *mvm = file->private_data;
 107        struct ieee80211_sta *sta;
 108
 109        char buf[8];
 110        int buf_size, sta_id, drain, ret;
 111
 112        if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
 113                return -EIO;
 114
 115        memset(buf, 0, sizeof(buf));
 116        buf_size = min(count, sizeof(buf) - 1);
 117        if (copy_from_user(buf, user_buf, buf_size))
 118                return -EFAULT;
 119
 120        if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
 121                return -EINVAL;
 122
 123        mutex_lock(&mvm->mutex);
 124
 125        sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
 126                                        lockdep_is_held(&mvm->mutex));
 127        if (IS_ERR_OR_NULL(sta))
 128                ret = -ENOENT;
 129        else
 130                ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? :
 131                        count;
 132
 133        mutex_unlock(&mvm->mutex);
 134
 135        return ret;
 136}
 137
 138static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
 139                                   size_t count, loff_t *ppos)
 140{
 141        struct iwl_mvm *mvm = file->private_data;
 142        const struct fw_img *img;
 143        int ofs, len, pos = 0;
 144        size_t bufsz, ret;
 145        char *buf;
 146        u8 *ptr;
 147
 148        if (!mvm->ucode_loaded)
 149                return -EINVAL;
 150
 151        /* default is to dump the entire data segment */
 152        if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) {
 153                img = &mvm->fw->img[mvm->cur_ucode];
 154                ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
 155                len = img->sec[IWL_UCODE_SECTION_DATA].len;
 156        } else {
 157                ofs = mvm->dbgfs_sram_offset;
 158                len = mvm->dbgfs_sram_len;
 159        }
 160
 161        bufsz = len * 4 + 256;
 162        buf = kzalloc(bufsz, GFP_KERNEL);
 163        if (!buf)
 164                return -ENOMEM;
 165
 166        ptr = kzalloc(len, GFP_KERNEL);
 167        if (!ptr) {
 168                kfree(buf);
 169                return -ENOMEM;
 170        }
 171
 172        pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len);
 173        pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", ofs);
 174
 175        iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len);
 176        for (ofs = 0; ofs < len; ofs += 16) {
 177                pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs);
 178                hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
 179                                   bufsz - pos, false);
 180                pos += strlen(buf + pos);
 181                if (bufsz - pos > 0)
 182                        buf[pos++] = '\n';
 183        }
 184
 185        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 186
 187        kfree(buf);
 188        kfree(ptr);
 189
 190        return ret;
 191}
 192
 193static ssize_t iwl_dbgfs_sram_write(struct file *file,
 194                                    const char __user *user_buf, size_t count,
 195                                    loff_t *ppos)
 196{
 197        struct iwl_mvm *mvm = file->private_data;
 198        char buf[64];
 199        int buf_size;
 200        u32 offset, len;
 201
 202        memset(buf, 0, sizeof(buf));
 203        buf_size = min(count, sizeof(buf) -  1);
 204        if (copy_from_user(buf, user_buf, buf_size))
 205                return -EFAULT;
 206
 207        if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
 208                if ((offset & 0x3) || (len & 0x3))
 209                        return -EINVAL;
 210                mvm->dbgfs_sram_offset = offset;
 211                mvm->dbgfs_sram_len = len;
 212        } else {
 213                mvm->dbgfs_sram_offset = 0;
 214                mvm->dbgfs_sram_len = 0;
 215        }
 216
 217        return count;
 218}
 219
 220static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
 221                                       size_t count, loff_t *ppos)
 222{
 223        struct iwl_mvm *mvm = file->private_data;
 224        struct ieee80211_sta *sta;
 225        char buf[400];
 226        int i, pos = 0, bufsz = sizeof(buf);
 227
 228        mutex_lock(&mvm->mutex);
 229
 230        for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
 231                pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
 232                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
 233                                                lockdep_is_held(&mvm->mutex));
 234                if (!sta)
 235                        pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
 236                else if (IS_ERR(sta))
 237                        pos += scnprintf(buf + pos, bufsz - pos, "%ld\n",
 238                                         PTR_ERR(sta));
 239                else
 240                        pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
 241                                         sta->addr);
 242        }
 243
 244        mutex_unlock(&mvm->mutex);
 245
 246        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 247}
 248
 249static ssize_t iwl_dbgfs_power_down_allow_write(struct file *file,
 250                                                const char __user *user_buf,
 251                                                size_t count, loff_t *ppos)
 252{
 253        struct iwl_mvm *mvm = file->private_data;
 254        char buf[8] = {};
 255        int allow;
 256
 257        if (!mvm->ucode_loaded)
 258                return -EIO;
 259
 260        if (copy_from_user(buf, user_buf, sizeof(buf)))
 261                return -EFAULT;
 262
 263        if (sscanf(buf, "%d", &allow) != 1)
 264                return -EINVAL;
 265
 266        IWL_DEBUG_POWER(mvm, "%s device power down\n",
 267                        allow ? "allow" : "prevent");
 268
 269        /*
 270         * TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it
 271         */
 272
 273        return count;
 274}
 275
 276static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
 277                                                   const char __user *user_buf,
 278                                                   size_t count, loff_t *ppos)
 279{
 280        struct iwl_mvm *mvm = file->private_data;
 281        char buf[8] = {};
 282        int allow;
 283
 284        if (copy_from_user(buf, user_buf, sizeof(buf)))
 285                return -EFAULT;
 286
 287        if (sscanf(buf, "%d", &allow) != 1)
 288                return -EINVAL;
 289
 290        IWL_DEBUG_POWER(mvm, "%s device power down in d3\n",
 291                        allow ? "allow" : "prevent");
 292
 293        /*
 294         * TODO: When WoWLAN FW alive notification happens, driver will send
 295         * REPLY_DEBUG_CMD setting power_down_allow flag according to
 296         * mvm->prevent_power_down_d3
 297         */
 298        mvm->prevent_power_down_d3 = !allow;
 299
 300        return count;
 301}
 302
 303static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
 304                                 struct ieee80211_vif *vif,
 305                                 enum iwl_dbgfs_pm_mask param, int val)
 306{
 307        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 308        struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
 309
 310        dbgfs_pm->mask |= param;
 311
 312        switch (param) {
 313        case MVM_DEBUGFS_PM_KEEP_ALIVE: {
 314                struct ieee80211_hw *hw = mvm->hw;
 315                int dtimper = hw->conf.ps_dtim_period ?: 1;
 316                int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
 317
 318                IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
 319                if (val * MSEC_PER_SEC < 3 * dtimper_msec) {
 320                        IWL_WARN(mvm,
 321                                 "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
 322                                 val * MSEC_PER_SEC, 3 * dtimper_msec);
 323                }
 324                dbgfs_pm->keep_alive_seconds = val;
 325                break;
 326        }
 327        case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
 328                IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
 329                                val ? "enabled" : "disabled");
 330                dbgfs_pm->skip_over_dtim = val;
 331                break;
 332        case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
 333                IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
 334                dbgfs_pm->skip_dtim_periods = val;
 335                break;
 336        case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
 337                IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
 338                dbgfs_pm->rx_data_timeout = val;
 339                break;
 340        case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
 341                IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
 342                dbgfs_pm->tx_data_timeout = val;
 343                break;
 344        case MVM_DEBUGFS_PM_DISABLE_POWER_OFF:
 345                IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val);
 346                dbgfs_pm->disable_power_off = val;
 347        case MVM_DEBUGFS_PM_LPRX_ENA:
 348                IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
 349                dbgfs_pm->lprx_ena = val;
 350                break;
 351        case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
 352                IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
 353                dbgfs_pm->lprx_rssi_threshold = val;
 354                break;
 355        }
 356}
 357
 358static ssize_t iwl_dbgfs_pm_params_write(struct file *file,
 359                                         const char __user *user_buf,
 360                                         size_t count, loff_t *ppos)
 361{
 362        struct ieee80211_vif *vif = file->private_data;
 363        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 364        struct iwl_mvm *mvm = mvmvif->dbgfs_data;
 365        enum iwl_dbgfs_pm_mask param;
 366        char buf[32] = {};
 367        int val;
 368        int ret;
 369
 370        if (copy_from_user(buf, user_buf, sizeof(buf)))
 371                return -EFAULT;
 372
 373        if (!strncmp("keep_alive=", buf, 11)) {
 374                if (sscanf(buf + 11, "%d", &val) != 1)
 375                        return -EINVAL;
 376                param = MVM_DEBUGFS_PM_KEEP_ALIVE;
 377        } else if (!strncmp("skip_over_dtim=", buf, 15)) {
 378                if (sscanf(buf + 15, "%d", &val) != 1)
 379                        return -EINVAL;
 380                param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
 381        } else if (!strncmp("skip_dtim_periods=", buf, 18)) {
 382                if (sscanf(buf + 18, "%d", &val) != 1)
 383                        return -EINVAL;
 384                param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
 385        } else if (!strncmp("rx_data_timeout=", buf, 16)) {
 386                if (sscanf(buf + 16, "%d", &val) != 1)
 387                        return -EINVAL;
 388                param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
 389        } else if (!strncmp("tx_data_timeout=", buf, 16)) {
 390                if (sscanf(buf + 16, "%d", &val) != 1)
 391                        return -EINVAL;
 392                param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
 393        } else if (!strncmp("disable_power_off=", buf, 18)) {
 394                if (sscanf(buf + 18, "%d", &val) != 1)
 395                        return -EINVAL;
 396                param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF;
 397        } else if (!strncmp("lprx=", buf, 5)) {
 398                if (sscanf(buf + 5, "%d", &val) != 1)
 399                        return -EINVAL;
 400                param = MVM_DEBUGFS_PM_LPRX_ENA;
 401        } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
 402                if (sscanf(buf + 20, "%d", &val) != 1)
 403                        return -EINVAL;
 404                if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
 405                    POWER_LPRX_RSSI_THRESHOLD_MIN)
 406                        return -EINVAL;
 407                param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
 408        } else {
 409                return -EINVAL;
 410        }
 411
 412        mutex_lock(&mvm->mutex);
 413        iwl_dbgfs_update_pm(mvm, vif, param, val);
 414        ret = iwl_mvm_power_update_mode(mvm, vif);
 415        mutex_unlock(&mvm->mutex);
 416
 417        return ret ?: count;
 418}
 419
 420static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
 421                                        char __user *user_buf,
 422                                        size_t count, loff_t *ppos)
 423{
 424        struct ieee80211_vif *vif = file->private_data;
 425        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 426        struct iwl_mvm *mvm = mvmvif->dbgfs_data;
 427        struct iwl_powertable_cmd cmd = {};
 428        char buf[256];
 429        int bufsz = sizeof(buf);
 430        int pos = 0;
 431
 432        iwl_mvm_power_build_cmd(mvm, vif, &cmd);
 433
 434        pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n",
 435                         (cmd.flags &
 436                         cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ?
 437                         0 : 1);
 438        pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
 439                         le32_to_cpu(cmd.skip_dtim_periods));
 440        pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n",
 441                         iwlmvm_mod_params.power_scheme);
 442        pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n",
 443                         le16_to_cpu(cmd.flags));
 444        pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
 445                         cmd.keep_alive_seconds);
 446
 447        if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
 448                pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
 449                                 (cmd.flags &
 450                                 cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ?
 451                                 1 : 0);
 452                pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",
 453                                 le32_to_cpu(cmd.rx_data_timeout));
 454                pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
 455                                 le32_to_cpu(cmd.tx_data_timeout));
 456                if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
 457                        pos += scnprintf(buf+pos, bufsz-pos,
 458                                         "lprx_rssi_threshold = %d\n",
 459                                         le32_to_cpu(cmd.lprx_rssi_threshold));
 460        }
 461
 462        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 463}
 464
 465static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
 466                                         char __user *user_buf,
 467                                         size_t count, loff_t *ppos)
 468{
 469        struct ieee80211_vif *vif = file->private_data;
 470        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 471        struct iwl_mvm *mvm = mvmvif->dbgfs_data;
 472        u8 ap_sta_id;
 473        struct ieee80211_chanctx_conf *chanctx_conf;
 474        char buf[512];
 475        int bufsz = sizeof(buf);
 476        int pos = 0;
 477        int i;
 478
 479        mutex_lock(&mvm->mutex);
 480
 481        ap_sta_id = mvmvif->ap_sta_id;
 482
 483        pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
 484                         mvmvif->id, mvmvif->color);
 485        pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
 486                         vif->bss_conf.bssid);
 487        pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
 488        for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) {
 489                pos += scnprintf(buf+pos, bufsz-pos,
 490                                 "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
 491                                 i, mvmvif->queue_params[i].txop,
 492                                 mvmvif->queue_params[i].cw_min,
 493                                 mvmvif->queue_params[i].cw_max,
 494                                 mvmvif->queue_params[i].aifs,
 495                                 mvmvif->queue_params[i].uapsd);
 496        }
 497
 498        if (vif->type == NL80211_IFTYPE_STATION &&
 499            ap_sta_id != IWL_MVM_STATION_COUNT) {
 500                struct ieee80211_sta *sta;
 501                struct iwl_mvm_sta *mvm_sta;
 502
 503                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
 504                                                lockdep_is_held(&mvm->mutex));
 505                mvm_sta = (void *)sta->drv_priv;
 506                pos += scnprintf(buf+pos, bufsz-pos,
 507                                 "ap_sta_id %d - reduced Tx power %d\n",
 508                                 ap_sta_id, mvm_sta->bt_reduced_txpower);
 509        }
 510
 511        rcu_read_lock();
 512        chanctx_conf = rcu_dereference(vif->chanctx_conf);
 513        if (chanctx_conf) {
 514                pos += scnprintf(buf+pos, bufsz-pos,
 515                                 "idle rx chains %d, active rx chains: %d\n",
 516                                 chanctx_conf->rx_chains_static,
 517                                 chanctx_conf->rx_chains_dynamic);
 518        }
 519        rcu_read_unlock();
 520
 521        mutex_unlock(&mvm->mutex);
 522
 523        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 524}
 525
 526#define BT_MBOX_MSG(_notif, _num, _field)                                    \
 527        ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
 528        >> BT_MBOX##_num##_##_field##_POS)
 529
 530
 531#define BT_MBOX_PRINT(_num, _field, _end)                                   \
 532                        pos += scnprintf(buf + pos, bufsz - pos,            \
 533                                         "\t%s: %d%s",                      \
 534                                         #_field,                           \
 535                                         BT_MBOX_MSG(notif, _num, _field),  \
 536                                         true ? "\n" : ", ");
 537
 538static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
 539                                       size_t count, loff_t *ppos)
 540{
 541        struct iwl_mvm *mvm = file->private_data;
 542        struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
 543        char *buf;
 544        int ret, pos = 0, bufsz = sizeof(char) * 1024;
 545
 546        buf = kmalloc(bufsz, GFP_KERNEL);
 547        if (!buf)
 548                return -ENOMEM;
 549
 550        mutex_lock(&mvm->mutex);
 551
 552        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
 553
 554        BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
 555        BT_MBOX_PRINT(0, LE_PROF1, false);
 556        BT_MBOX_PRINT(0, LE_PROF2, false);
 557        BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
 558        BT_MBOX_PRINT(0, CHL_SEQ_N, false);
 559        BT_MBOX_PRINT(0, INBAND_S, false);
 560        BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
 561        BT_MBOX_PRINT(0, LE_SCAN, false);
 562        BT_MBOX_PRINT(0, LE_ADV, false);
 563        BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
 564        BT_MBOX_PRINT(0, OPEN_CON_1, true);
 565
 566        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
 567
 568        BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
 569        BT_MBOX_PRINT(1, IP_SR, false);
 570        BT_MBOX_PRINT(1, LE_MSTR, false);
 571        BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
 572        BT_MBOX_PRINT(1, MSG_TYPE, false);
 573        BT_MBOX_PRINT(1, SSN, true);
 574
 575        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
 576
 577        BT_MBOX_PRINT(2, SNIFF_ACT, false);
 578        BT_MBOX_PRINT(2, PAG, false);
 579        BT_MBOX_PRINT(2, INQUIRY, false);
 580        BT_MBOX_PRINT(2, CONN, false);
 581        BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
 582        BT_MBOX_PRINT(2, DISC, false);
 583        BT_MBOX_PRINT(2, SCO_TX_ACT, false);
 584        BT_MBOX_PRINT(2, SCO_RX_ACT, false);
 585        BT_MBOX_PRINT(2, ESCO_RE_TX, false);
 586        BT_MBOX_PRINT(2, SCO_DURATION, true);
 587
 588        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
 589
 590        BT_MBOX_PRINT(3, SCO_STATE, false);
 591        BT_MBOX_PRINT(3, SNIFF_STATE, false);
 592        BT_MBOX_PRINT(3, A2DP_STATE, false);
 593        BT_MBOX_PRINT(3, ACL_STATE, false);
 594        BT_MBOX_PRINT(3, MSTR_STATE, false);
 595        BT_MBOX_PRINT(3, OBX_STATE, false);
 596        BT_MBOX_PRINT(3, OPEN_CON_2, false);
 597        BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
 598        BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
 599        BT_MBOX_PRINT(3, INBAND_P, false);
 600        BT_MBOX_PRINT(3, MSG_TYPE_2, false);
 601        BT_MBOX_PRINT(3, SSN_2, false);
 602        BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
 603
 604        pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n",
 605                                         notif->bt_status);
 606        pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n",
 607                                         notif->bt_open_conn);
 608        pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n",
 609                                         notif->bt_traffic_load);
 610        pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n",
 611                                         notif->bt_agg_traffic_load);
 612        pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
 613                                         notif->bt_ci_compliance);
 614
 615        mutex_unlock(&mvm->mutex);
 616
 617        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 618        kfree(buf);
 619
 620        return ret;
 621}
 622#undef BT_MBOX_PRINT
 623
 624static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
 625                                          const char __user *user_buf,
 626                                          size_t count, loff_t *ppos)
 627{
 628        struct iwl_mvm *mvm = file->private_data;
 629        bool restart_fw = iwlwifi_mod_params.restart_fw;
 630        int ret;
 631
 632        iwlwifi_mod_params.restart_fw = true;
 633
 634        mutex_lock(&mvm->mutex);
 635
 636        /* take the return value to make compiler happy - it will fail anyway */
 637        ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL);
 638
 639        mutex_unlock(&mvm->mutex);
 640
 641        iwlwifi_mod_params.restart_fw = restart_fw;
 642
 643        return count;
 644}
 645
 646static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
 647                                enum iwl_dbgfs_bf_mask param, int value)
 648{
 649        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 650        struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
 651
 652        dbgfs_bf->mask |= param;
 653
 654        switch (param) {
 655        case MVM_DEBUGFS_BF_ENERGY_DELTA:
 656                dbgfs_bf->bf_energy_delta = value;
 657                break;
 658        case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
 659                dbgfs_bf->bf_roaming_energy_delta = value;
 660                break;
 661        case MVM_DEBUGFS_BF_ROAMING_STATE:
 662                dbgfs_bf->bf_roaming_state = value;
 663                break;
 664        case MVM_DEBUGFS_BF_TEMPERATURE_DELTA:
 665                dbgfs_bf->bf_temperature_delta = value;
 666                break;
 667        case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
 668                dbgfs_bf->bf_enable_beacon_filter = value;
 669                break;
 670        case MVM_DEBUGFS_BF_DEBUG_FLAG:
 671                dbgfs_bf->bf_debug_flag = value;
 672                break;
 673        case MVM_DEBUGFS_BF_ESCAPE_TIMER:
 674                dbgfs_bf->bf_escape_timer = value;
 675                break;
 676        case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
 677                dbgfs_bf->ba_enable_beacon_abort = value;
 678                break;
 679        case MVM_DEBUGFS_BA_ESCAPE_TIMER:
 680                dbgfs_bf->ba_escape_timer = value;
 681                break;
 682        }
 683}
 684
 685static ssize_t iwl_dbgfs_bf_params_write(struct file *file,
 686                                         const char __user *user_buf,
 687                                         size_t count, loff_t *ppos)
 688{
 689        struct ieee80211_vif *vif = file->private_data;
 690        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 691        struct iwl_mvm *mvm = mvmvif->dbgfs_data;
 692        enum iwl_dbgfs_bf_mask param;
 693        char buf[256];
 694        int buf_size;
 695        int value;
 696        int ret = 0;
 697
 698        memset(buf, 0, sizeof(buf));
 699        buf_size = min(count, sizeof(buf) - 1);
 700        if (copy_from_user(buf, user_buf, buf_size))
 701                return -EFAULT;
 702
 703        if (!strncmp("bf_energy_delta=", buf, 16)) {
 704                if (sscanf(buf+16, "%d", &value) != 1)
 705                        return -EINVAL;
 706                if (value < IWL_BF_ENERGY_DELTA_MIN ||
 707                    value > IWL_BF_ENERGY_DELTA_MAX)
 708                        return -EINVAL;
 709                param = MVM_DEBUGFS_BF_ENERGY_DELTA;
 710        } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
 711                if (sscanf(buf+24, "%d", &value) != 1)
 712                        return -EINVAL;
 713                if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
 714                    value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
 715                        return -EINVAL;
 716                param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
 717        } else if (!strncmp("bf_roaming_state=", buf, 17)) {
 718                if (sscanf(buf+17, "%d", &value) != 1)
 719                        return -EINVAL;
 720                if (value < IWL_BF_ROAMING_STATE_MIN ||
 721                    value > IWL_BF_ROAMING_STATE_MAX)
 722                        return -EINVAL;
 723                param = MVM_DEBUGFS_BF_ROAMING_STATE;
 724        } else if (!strncmp("bf_temperature_delta=", buf, 21)) {
 725                if (sscanf(buf+21, "%d", &value) != 1)
 726                        return -EINVAL;
 727                if (value < IWL_BF_TEMPERATURE_DELTA_MIN ||
 728                    value > IWL_BF_TEMPERATURE_DELTA_MAX)
 729                        return -EINVAL;
 730                param = MVM_DEBUGFS_BF_TEMPERATURE_DELTA;
 731        } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
 732                if (sscanf(buf+24, "%d", &value) != 1)
 733                        return -EINVAL;
 734                if (value < 0 || value > 1)
 735                        return -EINVAL;
 736                param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
 737        } else if (!strncmp("bf_debug_flag=", buf, 14)) {
 738                if (sscanf(buf+14, "%d", &value) != 1)
 739                        return -EINVAL;
 740                if (value < 0 || value > 1)
 741                        return -EINVAL;
 742                param = MVM_DEBUGFS_BF_DEBUG_FLAG;
 743        } else if (!strncmp("bf_escape_timer=", buf, 16)) {
 744                if (sscanf(buf+16, "%d", &value) != 1)
 745                        return -EINVAL;
 746                if (value < IWL_BF_ESCAPE_TIMER_MIN ||
 747                    value > IWL_BF_ESCAPE_TIMER_MAX)
 748                        return -EINVAL;
 749                param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
 750        } else if (!strncmp("ba_escape_timer=", buf, 16)) {
 751                if (sscanf(buf+16, "%d", &value) != 1)
 752                        return -EINVAL;
 753                if (value < IWL_BA_ESCAPE_TIMER_MIN ||
 754                    value > IWL_BA_ESCAPE_TIMER_MAX)
 755                        return -EINVAL;
 756                param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
 757        } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
 758                if (sscanf(buf+23, "%d", &value) != 1)
 759                        return -EINVAL;
 760                if (value < 0 || value > 1)
 761                        return -EINVAL;
 762                param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
 763        } else {
 764                return -EINVAL;
 765        }
 766
 767        mutex_lock(&mvm->mutex);
 768        iwl_dbgfs_update_bf(vif, param, value);
 769        if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) {
 770                ret = iwl_mvm_disable_beacon_filter(mvm, vif);
 771        } else {
 772                if (mvmvif->bf_enabled)
 773                        ret = iwl_mvm_enable_beacon_filter(mvm, vif);
 774                else
 775                        ret = iwl_mvm_disable_beacon_filter(mvm, vif);
 776        }
 777        mutex_unlock(&mvm->mutex);
 778
 779        return ret ?: count;
 780}
 781
 782static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
 783                                        char __user *user_buf,
 784                                        size_t count, loff_t *ppos)
 785{
 786        struct ieee80211_vif *vif = file->private_data;
 787        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 788        char buf[256];
 789        int pos = 0;
 790        const size_t bufsz = sizeof(buf);
 791        struct iwl_beacon_filter_cmd cmd = {
 792                .bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT,
 793                .bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT,
 794                .bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT,
 795                .bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT,
 796                .bf_enable_beacon_filter = IWL_BF_ENABLE_BEACON_FILTER_DEFAULT,
 797                .bf_debug_flag = IWL_BF_DEBUG_FLAG_DEFAULT,
 798                .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT),
 799                .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT),
 800                .ba_enable_beacon_abort = IWL_BA_ENABLE_BEACON_ABORT_DEFAULT,
 801        };
 802
 803        iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
 804        if (mvmvif->bf_enabled)
 805                cmd.bf_enable_beacon_filter = 1;
 806        else
 807                cmd.bf_enable_beacon_filter = 0;
 808
 809        pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
 810                         cmd.bf_energy_delta);
 811        pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
 812                         cmd.bf_roaming_energy_delta);
 813        pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
 814                         cmd.bf_roaming_state);
 815        pos += scnprintf(buf+pos, bufsz-pos, "bf_temperature_delta = %d\n",
 816                         cmd.bf_temperature_delta);
 817        pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
 818                         cmd.bf_enable_beacon_filter);
 819        pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
 820                         cmd.bf_debug_flag);
 821        pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
 822                         cmd.bf_escape_timer);
 823        pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
 824                         cmd.ba_escape_timer);
 825        pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
 826                         cmd.ba_enable_beacon_abort);
 827
 828        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 829}
 830
 831#ifdef CONFIG_PM_SLEEP
 832static ssize_t iwl_dbgfs_d3_sram_write(struct file *file,
 833                                       const char __user *user_buf,
 834                                       size_t count, loff_t *ppos)
 835{
 836        struct iwl_mvm *mvm = file->private_data;
 837        char buf[8] = {};
 838        int store;
 839
 840        if (copy_from_user(buf, user_buf, sizeof(buf)))
 841                return -EFAULT;
 842
 843        if (sscanf(buf, "%d", &store) != 1)
 844                return -EINVAL;
 845
 846        mvm->store_d3_resume_sram = store;
 847
 848        return count;
 849}
 850
 851static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
 852                                      size_t count, loff_t *ppos)
 853{
 854        struct iwl_mvm *mvm = file->private_data;
 855        const struct fw_img *img;
 856        int ofs, len, pos = 0;
 857        size_t bufsz, ret;
 858        char *buf;
 859        u8 *ptr = mvm->d3_resume_sram;
 860
 861        img = &mvm->fw->img[IWL_UCODE_WOWLAN];
 862        len = img->sec[IWL_UCODE_SECTION_DATA].len;
 863
 864        bufsz = len * 4 + 256;
 865        buf = kzalloc(bufsz, GFP_KERNEL);
 866        if (!buf)
 867                return -ENOMEM;
 868
 869        pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n",
 870                         mvm->store_d3_resume_sram ? "en" : "dis");
 871
 872        if (ptr) {
 873                for (ofs = 0; ofs < len; ofs += 16) {
 874                        pos += scnprintf(buf + pos, bufsz - pos,
 875                                         "0x%.4x ", ofs);
 876                        hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
 877                                           bufsz - pos, false);
 878                        pos += strlen(buf + pos);
 879                        if (bufsz - pos > 0)
 880                                buf[pos++] = '\n';
 881                }
 882        } else {
 883                pos += scnprintf(buf + pos, bufsz - pos,
 884                                 "(no data captured)\n");
 885        }
 886
 887        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 888
 889        kfree(buf);
 890
 891        return ret;
 892}
 893#endif
 894
 895#define MVM_DEBUGFS_READ_FILE_OPS(name)                                 \
 896static const struct file_operations iwl_dbgfs_##name##_ops = {  \
 897        .read = iwl_dbgfs_##name##_read,                                \
 898        .open = simple_open,                                            \
 899        .llseek = generic_file_llseek,                                  \
 900}
 901
 902#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name)                           \
 903static const struct file_operations iwl_dbgfs_##name##_ops = {  \
 904        .write = iwl_dbgfs_##name##_write,                              \
 905        .read = iwl_dbgfs_##name##_read,                                \
 906        .open = simple_open,                                            \
 907        .llseek = generic_file_llseek,                                  \
 908};
 909
 910#define MVM_DEBUGFS_WRITE_FILE_OPS(name)                                \
 911static const struct file_operations iwl_dbgfs_##name##_ops = {  \
 912        .write = iwl_dbgfs_##name##_write,                              \
 913        .open = simple_open,                                            \
 914        .llseek = generic_file_llseek,                                  \
 915};
 916
 917#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do {                   \
 918                if (!debugfs_create_file(#name, mode, parent, mvm,      \
 919                                         &iwl_dbgfs_##name##_ops))      \
 920                        goto err;                                       \
 921        } while (0)
 922
 923#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {               \
 924                if (!debugfs_create_file(#name, mode, parent, vif,      \
 925                                         &iwl_dbgfs_##name##_ops))      \
 926                        goto err;                                       \
 927        } while (0)
 928
 929/* Device wide debugfs entries */
 930MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush);
 931MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
 932MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
 933MVM_DEBUGFS_READ_FILE_OPS(stations);
 934MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
 935MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
 936MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
 937MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
 938#ifdef CONFIG_PM_SLEEP
 939MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram);
 940#endif
 941
 942/* Interface specific debugfs entries */
 943MVM_DEBUGFS_READ_FILE_OPS(mac_params);
 944MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params);
 945MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params);
 946
 947int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
 948{
 949        char buf[100];
 950
 951        mvm->debugfs_dir = dbgfs_dir;
 952
 953        MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
 954        MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
 955        MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
 956        MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
 957        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
 958        MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
 959        MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
 960        MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
 961#ifdef CONFIG_PM_SLEEP
 962        MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
 963        MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
 964        if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
 965                                 mvm->debugfs_dir, &mvm->d3_wake_sysassert))
 966                goto err;
 967#endif
 968
 969        /*
 970         * Create a symlink with mac80211. It will be removed when mac80211
 971         * exists (before the opmode exists which removes the target.)
 972         */
 973        snprintf(buf, 100, "../../%s/%s",
 974                 dbgfs_dir->d_parent->d_parent->d_name.name,
 975                 dbgfs_dir->d_parent->d_name.name);
 976        if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
 977                goto err;
 978
 979        return 0;
 980err:
 981        IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
 982        return -ENOMEM;
 983}
 984
 985void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 986{
 987        struct dentry *dbgfs_dir = vif->debugfs_dir;
 988        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 989        char buf[100];
 990
 991        /*
 992         * Check if debugfs directory already exist before creating it.
 993         * This may happen when, for example, resetting hw or suspend-resume
 994         */
 995        if (!dbgfs_dir || mvmvif->dbgfs_dir)
 996                return;
 997
 998        mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
 999        mvmvif->dbgfs_data = mvm;
1000
1001        if (!mvmvif->dbgfs_dir) {
1002                IWL_ERR(mvm, "Failed to create debugfs directory under %s\n",
1003                        dbgfs_dir->d_name.name);
1004                return;
1005        }
1006
1007        if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
1008            vif->type == NL80211_IFTYPE_STATION && !vif->p2p)
1009                MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
1010                                         S_IRUSR);
1011
1012        MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
1013                                 S_IRUSR);
1014
1015        if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
1016            mvmvif == mvm->bf_allowed_vif)
1017                MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
1018                                         S_IRUSR | S_IWUSR);
1019
1020        /*
1021         * Create symlink for convenience pointing to interface specific
1022         * debugfs entries for the driver. For example, under
1023         * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
1024         * find
1025         * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
1026         */
1027        snprintf(buf, 100, "../../../%s/%s/%s/%s",
1028                 dbgfs_dir->d_parent->d_parent->d_name.name,
1029                 dbgfs_dir->d_parent->d_name.name,
1030                 dbgfs_dir->d_name.name,
1031                 mvmvif->dbgfs_dir->d_name.name);
1032
1033        mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
1034                                                     mvm->debugfs_dir, buf);
1035        if (!mvmvif->dbgfs_slink)
1036                IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n",
1037                        dbgfs_dir->d_name.name);
1038        return;
1039err:
1040        IWL_ERR(mvm, "Can't create debugfs entity\n");
1041}
1042
1043void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1044{
1045        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1046
1047        debugfs_remove(mvmvif->dbgfs_slink);
1048        mvmvif->dbgfs_slink = NULL;
1049
1050        debugfs_remove_recursive(mvmvif->dbgfs_dir);
1051        mvmvif->dbgfs_dir = NULL;
1052}
1053