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        /* default is to dump the entire data segment */
 149        if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) {
 150                mvm->dbgfs_sram_offset = 0x800000;
 151                if (!mvm->ucode_loaded)
 152                        return -EINVAL;
 153                img = &mvm->fw->img[mvm->cur_ucode];
 154                mvm->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
 155        }
 156        len = mvm->dbgfs_sram_len;
 157
 158        bufsz = len * 4 + 256;
 159        buf = kzalloc(bufsz, GFP_KERNEL);
 160        if (!buf)
 161                return -ENOMEM;
 162
 163        ptr = kzalloc(len, GFP_KERNEL);
 164        if (!ptr) {
 165                kfree(buf);
 166                return -ENOMEM;
 167        }
 168
 169        pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len);
 170        pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
 171                         mvm->dbgfs_sram_offset);
 172
 173        iwl_trans_read_mem_bytes(mvm->trans,
 174                                 mvm->dbgfs_sram_offset,
 175                                 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 ssize_t iwl_dbgfs_mac_params_read(struct file *file,
 304                                         char __user *user_buf,
 305                                         size_t count, loff_t *ppos)
 306{
 307        struct ieee80211_vif *vif = file->private_data;
 308        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 309        struct iwl_mvm *mvm = mvmvif->dbgfs_data;
 310        u8 ap_sta_id;
 311        struct ieee80211_chanctx_conf *chanctx_conf;
 312        char buf[512];
 313        int bufsz = sizeof(buf);
 314        int pos = 0;
 315        int i;
 316
 317        mutex_lock(&mvm->mutex);
 318
 319        ap_sta_id = mvmvif->ap_sta_id;
 320
 321        pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
 322                         mvmvif->id, mvmvif->color);
 323        pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
 324                         vif->bss_conf.bssid);
 325        pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
 326        for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) {
 327                pos += scnprintf(buf+pos, bufsz-pos,
 328                                 "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
 329                                 i, mvmvif->queue_params[i].txop,
 330                                 mvmvif->queue_params[i].cw_min,
 331                                 mvmvif->queue_params[i].cw_max,
 332                                 mvmvif->queue_params[i].aifs,
 333                                 mvmvif->queue_params[i].uapsd);
 334        }
 335
 336        if (vif->type == NL80211_IFTYPE_STATION &&
 337            ap_sta_id != IWL_MVM_STATION_COUNT) {
 338                struct ieee80211_sta *sta;
 339                struct iwl_mvm_sta *mvm_sta;
 340
 341                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
 342                                                lockdep_is_held(&mvm->mutex));
 343                mvm_sta = (void *)sta->drv_priv;
 344                pos += scnprintf(buf+pos, bufsz-pos,
 345                                 "ap_sta_id %d - reduced Tx power %d\n",
 346                                 ap_sta_id, mvm_sta->bt_reduced_txpower);
 347        }
 348
 349        rcu_read_lock();
 350        chanctx_conf = rcu_dereference(vif->chanctx_conf);
 351        if (chanctx_conf) {
 352                pos += scnprintf(buf+pos, bufsz-pos,
 353                                 "idle rx chains %d, active rx chains: %d\n",
 354                                 chanctx_conf->rx_chains_static,
 355                                 chanctx_conf->rx_chains_dynamic);
 356        }
 357        rcu_read_unlock();
 358
 359        mutex_unlock(&mvm->mutex);
 360
 361        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 362}
 363
 364#define BT_MBOX_MSG(_notif, _num, _field)                                    \
 365        ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
 366        >> BT_MBOX##_num##_##_field##_POS)
 367
 368
 369#define BT_MBOX_PRINT(_num, _field, _end)                                   \
 370                        pos += scnprintf(buf + pos, bufsz - pos,            \
 371                                         "\t%s: %d%s",                      \
 372                                         #_field,                           \
 373                                         BT_MBOX_MSG(notif, _num, _field),  \
 374                                         true ? "\n" : ", ");
 375
 376static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
 377                                       size_t count, loff_t *ppos)
 378{
 379        struct iwl_mvm *mvm = file->private_data;
 380        struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
 381        char *buf;
 382        int ret, pos = 0, bufsz = sizeof(char) * 1024;
 383
 384        buf = kmalloc(bufsz, GFP_KERNEL);
 385        if (!buf)
 386                return -ENOMEM;
 387
 388        mutex_lock(&mvm->mutex);
 389
 390        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
 391
 392        BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
 393        BT_MBOX_PRINT(0, LE_PROF1, false);
 394        BT_MBOX_PRINT(0, LE_PROF2, false);
 395        BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
 396        BT_MBOX_PRINT(0, CHL_SEQ_N, false);
 397        BT_MBOX_PRINT(0, INBAND_S, false);
 398        BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
 399        BT_MBOX_PRINT(0, LE_SCAN, false);
 400        BT_MBOX_PRINT(0, LE_ADV, false);
 401        BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
 402        BT_MBOX_PRINT(0, OPEN_CON_1, true);
 403
 404        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
 405
 406        BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
 407        BT_MBOX_PRINT(1, IP_SR, false);
 408        BT_MBOX_PRINT(1, LE_MSTR, false);
 409        BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
 410        BT_MBOX_PRINT(1, MSG_TYPE, false);
 411        BT_MBOX_PRINT(1, SSN, true);
 412
 413        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
 414
 415        BT_MBOX_PRINT(2, SNIFF_ACT, false);
 416        BT_MBOX_PRINT(2, PAG, false);
 417        BT_MBOX_PRINT(2, INQUIRY, false);
 418        BT_MBOX_PRINT(2, CONN, false);
 419        BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
 420        BT_MBOX_PRINT(2, DISC, false);
 421        BT_MBOX_PRINT(2, SCO_TX_ACT, false);
 422        BT_MBOX_PRINT(2, SCO_RX_ACT, false);
 423        BT_MBOX_PRINT(2, ESCO_RE_TX, false);
 424        BT_MBOX_PRINT(2, SCO_DURATION, true);
 425
 426        pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
 427
 428        BT_MBOX_PRINT(3, SCO_STATE, false);
 429        BT_MBOX_PRINT(3, SNIFF_STATE, false);
 430        BT_MBOX_PRINT(3, A2DP_STATE, false);
 431        BT_MBOX_PRINT(3, ACL_STATE, false);
 432        BT_MBOX_PRINT(3, MSTR_STATE, false);
 433        BT_MBOX_PRINT(3, OBX_STATE, false);
 434        BT_MBOX_PRINT(3, OPEN_CON_2, false);
 435        BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
 436        BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
 437        BT_MBOX_PRINT(3, INBAND_P, false);
 438        BT_MBOX_PRINT(3, MSG_TYPE_2, false);
 439        BT_MBOX_PRINT(3, SSN_2, false);
 440        BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
 441
 442        pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n",
 443                                         notif->bt_status);
 444        pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n",
 445                                         notif->bt_open_conn);
 446        pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n",
 447                                         notif->bt_traffic_load);
 448        pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n",
 449                                         notif->bt_agg_traffic_load);
 450        pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
 451                                         notif->bt_ci_compliance);
 452
 453        mutex_unlock(&mvm->mutex);
 454
 455        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 456        kfree(buf);
 457
 458        return ret;
 459}
 460#undef BT_MBOX_PRINT
 461
 462static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
 463                                          const char __user *user_buf,
 464                                          size_t count, loff_t *ppos)
 465{
 466        struct iwl_mvm *mvm = file->private_data;
 467        bool restart_fw = iwlwifi_mod_params.restart_fw;
 468        int ret;
 469
 470        iwlwifi_mod_params.restart_fw = true;
 471
 472        mutex_lock(&mvm->mutex);
 473
 474        /* take the return value to make compiler happy - it will fail anyway */
 475        ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL);
 476
 477        mutex_unlock(&mvm->mutex);
 478
 479        iwlwifi_mod_params.restart_fw = restart_fw;
 480
 481        return count;
 482}
 483
 484#define MVM_DEBUGFS_READ_FILE_OPS(name)                                 \
 485static const struct file_operations iwl_dbgfs_##name##_ops = {  \
 486        .read = iwl_dbgfs_##name##_read,                                \
 487        .open = simple_open,                                            \
 488        .llseek = generic_file_llseek,                                  \
 489}
 490
 491#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name)                           \
 492static const struct file_operations iwl_dbgfs_##name##_ops = {  \
 493        .write = iwl_dbgfs_##name##_write,                              \
 494        .read = iwl_dbgfs_##name##_read,                                \
 495        .open = simple_open,                                            \
 496        .llseek = generic_file_llseek,                                  \
 497};
 498
 499#define MVM_DEBUGFS_WRITE_FILE_OPS(name)                                \
 500static const struct file_operations iwl_dbgfs_##name##_ops = {  \
 501        .write = iwl_dbgfs_##name##_write,                              \
 502        .open = simple_open,                                            \
 503        .llseek = generic_file_llseek,                                  \
 504};
 505
 506#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do {                   \
 507                if (!debugfs_create_file(#name, mode, parent, mvm,      \
 508                                         &iwl_dbgfs_##name##_ops))      \
 509                        goto err;                                       \
 510        } while (0)
 511
 512#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {               \
 513                if (!debugfs_create_file(#name, mode, parent, vif,      \
 514                                         &iwl_dbgfs_##name##_ops))      \
 515                        goto err;                                       \
 516        } while (0)
 517
 518/* Device wide debugfs entries */
 519MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush);
 520MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
 521MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
 522MVM_DEBUGFS_READ_FILE_OPS(stations);
 523MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
 524MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
 525MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
 526MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
 527
 528/* Interface specific debugfs entries */
 529MVM_DEBUGFS_READ_FILE_OPS(mac_params);
 530
 531int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
 532{
 533        char buf[100];
 534
 535        mvm->debugfs_dir = dbgfs_dir;
 536
 537        MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
 538        MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
 539        MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
 540        MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
 541        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
 542        MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
 543        MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
 544        MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
 545
 546        /*
 547         * Create a symlink with mac80211. It will be removed when mac80211
 548         * exists (before the opmode exists which removes the target.)
 549         */
 550        snprintf(buf, 100, "../../%s/%s",
 551                 dbgfs_dir->d_parent->d_parent->d_name.name,
 552                 dbgfs_dir->d_parent->d_name.name);
 553        if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
 554                goto err;
 555
 556        return 0;
 557err:
 558        IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
 559        return -ENOMEM;
 560}
 561
 562void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 563{
 564        struct dentry *dbgfs_dir = vif->debugfs_dir;
 565        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 566        char buf[100];
 567
 568        if (!dbgfs_dir)
 569                return;
 570
 571        mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
 572        mvmvif->dbgfs_data = mvm;
 573
 574        if (!mvmvif->dbgfs_dir) {
 575                IWL_ERR(mvm, "Failed to create debugfs directory under %s\n",
 576                        dbgfs_dir->d_name.name);
 577                return;
 578        }
 579
 580        MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
 581                                 S_IRUSR);
 582
 583        /*
 584         * Create symlink for convenience pointing to interface specific
 585         * debugfs entries for the driver. For example, under
 586         * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
 587         * find
 588         * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
 589         */
 590        snprintf(buf, 100, "../../../%s/%s/%s/%s",
 591                 dbgfs_dir->d_parent->d_parent->d_name.name,
 592                 dbgfs_dir->d_parent->d_name.name,
 593                 dbgfs_dir->d_name.name,
 594                 mvmvif->dbgfs_dir->d_name.name);
 595
 596        mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
 597                                                     mvm->debugfs_dir, buf);
 598        if (!mvmvif->dbgfs_slink)
 599                IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n",
 600                        dbgfs_dir->d_name.name);
 601        return;
 602err:
 603        IWL_ERR(mvm, "Can't create debugfs entity\n");
 604}
 605
 606void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 607{
 608        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 609
 610        debugfs_remove(mvmvif->dbgfs_slink);
 611        mvmvif->dbgfs_slink = NULL;
 612
 613        debugfs_remove_recursive(mvmvif->dbgfs_dir);
 614        mvmvif->dbgfs_dir = NULL;
 615}
 616