linux/net/mac80211/debugfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * mac80211 debugfs for wireless PHYs
   4 *
   5 * Copyright 2007       Johannes Berg <johannes@sipsolutions.net>
   6 * Copyright 2013-2014  Intel Mobile Communications GmbH
   7 * Copyright (C) 2018 - 2019, 2021 Intel Corporation
   8 */
   9
  10#include <linux/debugfs.h>
  11#include <linux/rtnetlink.h>
  12#include <linux/vmalloc.h>
  13#include "ieee80211_i.h"
  14#include "driver-ops.h"
  15#include "rate.h"
  16#include "debugfs.h"
  17
  18#define DEBUGFS_FORMAT_BUFFER_SIZE 100
  19
  20int mac80211_format_buffer(char __user *userbuf, size_t count,
  21                                  loff_t *ppos, char *fmt, ...)
  22{
  23        va_list args;
  24        char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
  25        int res;
  26
  27        va_start(args, fmt);
  28        res = vscnprintf(buf, sizeof(buf), fmt, args);
  29        va_end(args);
  30
  31        return simple_read_from_buffer(userbuf, count, ppos, buf, res);
  32}
  33
  34#define DEBUGFS_READONLY_FILE_FN(name, fmt, value...)                   \
  35static ssize_t name## _read(struct file *file, char __user *userbuf,    \
  36                            size_t count, loff_t *ppos)                 \
  37{                                                                       \
  38        struct ieee80211_local *local = file->private_data;             \
  39                                                                        \
  40        return mac80211_format_buffer(userbuf, count, ppos,             \
  41                                      fmt "\n", ##value);               \
  42}
  43
  44#define DEBUGFS_READONLY_FILE_OPS(name)                 \
  45static const struct file_operations name## _ops = {                     \
  46        .read = name## _read,                                           \
  47        .open = simple_open,                                            \
  48        .llseek = generic_file_llseek,                                  \
  49};
  50
  51#define DEBUGFS_READONLY_FILE(name, fmt, value...)              \
  52        DEBUGFS_READONLY_FILE_FN(name, fmt, value)              \
  53        DEBUGFS_READONLY_FILE_OPS(name)
  54
  55#define DEBUGFS_ADD(name)                                               \
  56        debugfs_create_file(#name, 0400, phyd, local, &name## _ops)
  57
  58#define DEBUGFS_ADD_MODE(name, mode)                                    \
  59        debugfs_create_file(#name, mode, phyd, local, &name## _ops);
  60
  61
  62DEBUGFS_READONLY_FILE(hw_conf, "%x",
  63                      local->hw.conf.flags);
  64DEBUGFS_READONLY_FILE(user_power, "%d",
  65                      local->user_power_level);
  66DEBUGFS_READONLY_FILE(power, "%d",
  67                      local->hw.conf.power_level);
  68DEBUGFS_READONLY_FILE(total_ps_buffered, "%d",
  69                      local->total_ps_buffered);
  70DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
  71                      local->wep_iv & 0xffffff);
  72DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
  73        local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
  74
  75static ssize_t aqm_read(struct file *file,
  76                        char __user *user_buf,
  77                        size_t count,
  78                        loff_t *ppos)
  79{
  80        struct ieee80211_local *local = file->private_data;
  81        struct fq *fq = &local->fq;
  82        char buf[200];
  83        int len = 0;
  84
  85        spin_lock_bh(&local->fq.lock);
  86        rcu_read_lock();
  87
  88        len = scnprintf(buf, sizeof(buf),
  89                        "access name value\n"
  90                        "R fq_flows_cnt %u\n"
  91                        "R fq_backlog %u\n"
  92                        "R fq_overlimit %u\n"
  93                        "R fq_overmemory %u\n"
  94                        "R fq_collisions %u\n"
  95                        "R fq_memory_usage %u\n"
  96                        "RW fq_memory_limit %u\n"
  97                        "RW fq_limit %u\n"
  98                        "RW fq_quantum %u\n",
  99                        fq->flows_cnt,
 100                        fq->backlog,
 101                        fq->overmemory,
 102                        fq->overlimit,
 103                        fq->collisions,
 104                        fq->memory_usage,
 105                        fq->memory_limit,
 106                        fq->limit,
 107                        fq->quantum);
 108
 109        rcu_read_unlock();
 110        spin_unlock_bh(&local->fq.lock);
 111
 112        return simple_read_from_buffer(user_buf, count, ppos,
 113                                       buf, len);
 114}
 115
 116static ssize_t aqm_write(struct file *file,
 117                         const char __user *user_buf,
 118                         size_t count,
 119                         loff_t *ppos)
 120{
 121        struct ieee80211_local *local = file->private_data;
 122        char buf[100];
 123
 124        if (count >= sizeof(buf))
 125                return -EINVAL;
 126
 127        if (copy_from_user(buf, user_buf, count))
 128                return -EFAULT;
 129
 130        if (count && buf[count - 1] == '\n')
 131                buf[count - 1] = '\0';
 132        else
 133                buf[count] = '\0';
 134
 135        if (sscanf(buf, "fq_limit %u", &local->fq.limit) == 1)
 136                return count;
 137        else if (sscanf(buf, "fq_memory_limit %u", &local->fq.memory_limit) == 1)
 138                return count;
 139        else if (sscanf(buf, "fq_quantum %u", &local->fq.quantum) == 1)
 140                return count;
 141
 142        return -EINVAL;
 143}
 144
 145static const struct file_operations aqm_ops = {
 146        .write = aqm_write,
 147        .read = aqm_read,
 148        .open = simple_open,
 149        .llseek = default_llseek,
 150};
 151
 152static ssize_t airtime_flags_read(struct file *file,
 153                                  char __user *user_buf,
 154                                  size_t count, loff_t *ppos)
 155{
 156        struct ieee80211_local *local = file->private_data;
 157        char buf[128] = {}, *pos, *end;
 158
 159        pos = buf;
 160        end = pos + sizeof(buf) - 1;
 161
 162        if (local->airtime_flags & AIRTIME_USE_TX)
 163                pos += scnprintf(pos, end - pos, "AIRTIME_TX\t(%lx)\n",
 164                                 AIRTIME_USE_TX);
 165        if (local->airtime_flags & AIRTIME_USE_RX)
 166                pos += scnprintf(pos, end - pos, "AIRTIME_RX\t(%lx)\n",
 167                                 AIRTIME_USE_RX);
 168
 169        return simple_read_from_buffer(user_buf, count, ppos, buf,
 170                                       strlen(buf));
 171}
 172
 173static ssize_t airtime_flags_write(struct file *file,
 174                                   const char __user *user_buf,
 175                                   size_t count, loff_t *ppos)
 176{
 177        struct ieee80211_local *local = file->private_data;
 178        char buf[16];
 179
 180        if (count >= sizeof(buf))
 181                return -EINVAL;
 182
 183        if (copy_from_user(buf, user_buf, count))
 184                return -EFAULT;
 185
 186        if (count && buf[count - 1] == '\n')
 187                buf[count - 1] = '\0';
 188        else
 189                buf[count] = '\0';
 190
 191        if (kstrtou16(buf, 0, &local->airtime_flags))
 192                return -EINVAL;
 193
 194        return count;
 195}
 196
 197static const struct file_operations airtime_flags_ops = {
 198        .write = airtime_flags_write,
 199        .read = airtime_flags_read,
 200        .open = simple_open,
 201        .llseek = default_llseek,
 202};
 203
 204static ssize_t aql_txq_limit_read(struct file *file,
 205                                  char __user *user_buf,
 206                                  size_t count,
 207                                  loff_t *ppos)
 208{
 209        struct ieee80211_local *local = file->private_data;
 210        char buf[400];
 211        int len = 0;
 212
 213        len = scnprintf(buf, sizeof(buf),
 214                        "AC     AQL limit low   AQL limit high\n"
 215                        "VO     %u              %u\n"
 216                        "VI     %u              %u\n"
 217                        "BE     %u              %u\n"
 218                        "BK     %u              %u\n",
 219                        local->airtime[IEEE80211_AC_VO].aql_txq_limit_low,
 220                        local->airtime[IEEE80211_AC_VO].aql_txq_limit_high,
 221                        local->airtime[IEEE80211_AC_VI].aql_txq_limit_low,
 222                        local->airtime[IEEE80211_AC_VI].aql_txq_limit_high,
 223                        local->airtime[IEEE80211_AC_BE].aql_txq_limit_low,
 224                        local->airtime[IEEE80211_AC_BE].aql_txq_limit_high,
 225                        local->airtime[IEEE80211_AC_BK].aql_txq_limit_low,
 226                        local->airtime[IEEE80211_AC_BK].aql_txq_limit_high);
 227        return simple_read_from_buffer(user_buf, count, ppos,
 228                                       buf, len);
 229}
 230
 231static ssize_t aql_txq_limit_write(struct file *file,
 232                                   const char __user *user_buf,
 233                                   size_t count,
 234                                   loff_t *ppos)
 235{
 236        struct ieee80211_local *local = file->private_data;
 237        char buf[100];
 238        u32 ac, q_limit_low, q_limit_high, q_limit_low_old, q_limit_high_old;
 239        struct sta_info *sta;
 240
 241        if (count >= sizeof(buf))
 242                return -EINVAL;
 243
 244        if (copy_from_user(buf, user_buf, count))
 245                return -EFAULT;
 246
 247        if (count && buf[count - 1] == '\n')
 248                buf[count - 1] = '\0';
 249        else
 250                buf[count] = '\0';
 251
 252        if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3)
 253                return -EINVAL;
 254
 255        if (ac >= IEEE80211_NUM_ACS)
 256                return -EINVAL;
 257
 258        q_limit_low_old = local->airtime[ac].aql_txq_limit_low;
 259        q_limit_high_old = local->airtime[ac].aql_txq_limit_high;
 260
 261        local->airtime[ac].aql_txq_limit_low = q_limit_low;
 262        local->airtime[ac].aql_txq_limit_high = q_limit_high;
 263
 264        mutex_lock(&local->sta_mtx);
 265        list_for_each_entry(sta, &local->sta_list, list) {
 266                /* If a sta has customized queue limits, keep it */
 267                if (sta->airtime[ac].aql_limit_low == q_limit_low_old &&
 268                    sta->airtime[ac].aql_limit_high == q_limit_high_old) {
 269                        sta->airtime[ac].aql_limit_low = q_limit_low;
 270                        sta->airtime[ac].aql_limit_high = q_limit_high;
 271                }
 272        }
 273        mutex_unlock(&local->sta_mtx);
 274        return count;
 275}
 276
 277static const struct file_operations aql_txq_limit_ops = {
 278        .write = aql_txq_limit_write,
 279        .read = aql_txq_limit_read,
 280        .open = simple_open,
 281        .llseek = default_llseek,
 282};
 283
 284static ssize_t aql_enable_read(struct file *file, char __user *user_buf,
 285                               size_t count, loff_t *ppos)
 286{
 287        char buf[3];
 288        int len;
 289
 290        len = scnprintf(buf, sizeof(buf), "%d\n",
 291                        !static_key_false(&aql_disable.key));
 292
 293        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 294}
 295
 296static ssize_t aql_enable_write(struct file *file, const char __user *user_buf,
 297                                size_t count, loff_t *ppos)
 298{
 299        bool aql_disabled = static_key_false(&aql_disable.key);
 300        char buf[3];
 301        size_t len;
 302
 303        if (count > sizeof(buf))
 304                return -EINVAL;
 305
 306        if (copy_from_user(buf, user_buf, count))
 307                return -EFAULT;
 308
 309        buf[sizeof(buf) - 1] = '\0';
 310        len = strlen(buf);
 311        if (len > 0 && buf[len - 1] == '\n')
 312                buf[len - 1] = 0;
 313
 314        if (buf[0] == '0' && buf[1] == '\0') {
 315                if (!aql_disabled)
 316                        static_branch_inc(&aql_disable);
 317        } else if (buf[0] == '1' && buf[1] == '\0') {
 318                if (aql_disabled)
 319                        static_branch_dec(&aql_disable);
 320        } else {
 321                return -EINVAL;
 322        }
 323
 324        return count;
 325}
 326
 327static const struct file_operations aql_enable_ops = {
 328        .write = aql_enable_write,
 329        .read = aql_enable_read,
 330        .open = simple_open,
 331        .llseek = default_llseek,
 332};
 333
 334static ssize_t force_tx_status_read(struct file *file,
 335                                    char __user *user_buf,
 336                                    size_t count,
 337                                    loff_t *ppos)
 338{
 339        struct ieee80211_local *local = file->private_data;
 340        char buf[3];
 341        int len = 0;
 342
 343        len = scnprintf(buf, sizeof(buf), "%d\n", (int)local->force_tx_status);
 344
 345        return simple_read_from_buffer(user_buf, count, ppos,
 346                                       buf, len);
 347}
 348
 349static ssize_t force_tx_status_write(struct file *file,
 350                                     const char __user *user_buf,
 351                                     size_t count,
 352                                     loff_t *ppos)
 353{
 354        struct ieee80211_local *local = file->private_data;
 355        char buf[3];
 356
 357        if (count >= sizeof(buf))
 358                return -EINVAL;
 359
 360        if (copy_from_user(buf, user_buf, count))
 361                return -EFAULT;
 362
 363        if (count && buf[count - 1] == '\n')
 364                buf[count - 1] = '\0';
 365        else
 366                buf[count] = '\0';
 367
 368        if (buf[0] == '0' && buf[1] == '\0')
 369                local->force_tx_status = 0;
 370        else if (buf[0] == '1' && buf[1] == '\0')
 371                local->force_tx_status = 1;
 372        else
 373                return -EINVAL;
 374
 375        return count;
 376}
 377
 378static const struct file_operations force_tx_status_ops = {
 379        .write = force_tx_status_write,
 380        .read = force_tx_status_read,
 381        .open = simple_open,
 382        .llseek = default_llseek,
 383};
 384
 385static ssize_t airtime_read(struct file *file,
 386                            char __user *user_buf,
 387                            size_t count,
 388                            loff_t *ppos)
 389{
 390        struct ieee80211_local *local = file->private_data;
 391        char buf[200];
 392        u64 v_t[IEEE80211_NUM_ACS];
 393        u64 wt[IEEE80211_NUM_ACS];
 394        int len = 0, ac;
 395
 396        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
 397                spin_lock_bh(&local->airtime[ac].lock);
 398                v_t[ac] = local->airtime[ac].v_t;
 399                wt[ac] = local->airtime[ac].weight_sum;
 400                spin_unlock_bh(&local->airtime[ac].lock);
 401        }
 402        len = scnprintf(buf, sizeof(buf),
 403                        "\tVO         VI         BE         BK\n"
 404                        "Virt-t\t%-10llu %-10llu %-10llu %-10llu\n"
 405                        "Weight\t%-10llu %-10llu %-10llu %-10llu\n",
 406                        v_t[0],
 407                        v_t[1],
 408                        v_t[2],
 409                        v_t[3],
 410                        wt[0],
 411                        wt[1],
 412                        wt[2],
 413                        wt[3]);
 414
 415        return simple_read_from_buffer(user_buf, count, ppos,
 416                                       buf, len);
 417}
 418
 419static const struct file_operations airtime_ops = {
 420        .read = airtime_read,
 421        .open = simple_open,
 422        .llseek = default_llseek,
 423};
 424
 425#ifdef CONFIG_PM
 426static ssize_t reset_write(struct file *file, const char __user *user_buf,
 427                           size_t count, loff_t *ppos)
 428{
 429        struct ieee80211_local *local = file->private_data;
 430        int ret;
 431
 432        rtnl_lock();
 433        wiphy_lock(local->hw.wiphy);
 434        __ieee80211_suspend(&local->hw, NULL);
 435        ret = __ieee80211_resume(&local->hw);
 436        wiphy_unlock(local->hw.wiphy);
 437
 438        if (ret)
 439                cfg80211_shutdown_all_interfaces(local->hw.wiphy);
 440
 441        rtnl_unlock();
 442
 443        return count;
 444}
 445
 446static const struct file_operations reset_ops = {
 447        .write = reset_write,
 448        .open = simple_open,
 449        .llseek = noop_llseek,
 450};
 451#endif
 452
 453static const char *hw_flag_names[] = {
 454#define FLAG(F) [IEEE80211_HW_##F] = #F
 455        FLAG(HAS_RATE_CONTROL),
 456        FLAG(RX_INCLUDES_FCS),
 457        FLAG(HOST_BROADCAST_PS_BUFFERING),
 458        FLAG(SIGNAL_UNSPEC),
 459        FLAG(SIGNAL_DBM),
 460        FLAG(NEED_DTIM_BEFORE_ASSOC),
 461        FLAG(SPECTRUM_MGMT),
 462        FLAG(AMPDU_AGGREGATION),
 463        FLAG(SUPPORTS_PS),
 464        FLAG(PS_NULLFUNC_STACK),
 465        FLAG(SUPPORTS_DYNAMIC_PS),
 466        FLAG(MFP_CAPABLE),
 467        FLAG(WANT_MONITOR_VIF),
 468        FLAG(NO_AUTO_VIF),
 469        FLAG(SW_CRYPTO_CONTROL),
 470        FLAG(SUPPORT_FAST_XMIT),
 471        FLAG(REPORTS_TX_ACK_STATUS),
 472        FLAG(CONNECTION_MONITOR),
 473        FLAG(QUEUE_CONTROL),
 474        FLAG(SUPPORTS_PER_STA_GTK),
 475        FLAG(AP_LINK_PS),
 476        FLAG(TX_AMPDU_SETUP_IN_HW),
 477        FLAG(SUPPORTS_RC_TABLE),
 478        FLAG(P2P_DEV_ADDR_FOR_INTF),
 479        FLAG(TIMING_BEACON_ONLY),
 480        FLAG(SUPPORTS_HT_CCK_RATES),
 481        FLAG(CHANCTX_STA_CSA),
 482        FLAG(SUPPORTS_CLONED_SKBS),
 483        FLAG(SINGLE_SCAN_ON_ALL_BANDS),
 484        FLAG(TDLS_WIDER_BW),
 485        FLAG(SUPPORTS_AMSDU_IN_AMPDU),
 486        FLAG(BEACON_TX_STATUS),
 487        FLAG(NEEDS_UNIQUE_STA_ADDR),
 488        FLAG(SUPPORTS_REORDERING_BUFFER),
 489        FLAG(USES_RSS),
 490        FLAG(TX_AMSDU),
 491        FLAG(TX_FRAG_LIST),
 492        FLAG(REPORTS_LOW_ACK),
 493        FLAG(SUPPORTS_TX_FRAG),
 494        FLAG(SUPPORTS_TDLS_BUFFER_STA),
 495        FLAG(DEAUTH_NEED_MGD_TX_PREP),
 496        FLAG(DOESNT_SUPPORT_QOS_NDP),
 497        FLAG(BUFF_MMPDU_TXQ),
 498        FLAG(SUPPORTS_VHT_EXT_NSS_BW),
 499        FLAG(STA_MMPDU_TXQ),
 500        FLAG(TX_STATUS_NO_AMPDU_LEN),
 501        FLAG(SUPPORTS_MULTI_BSSID),
 502        FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
 503        FLAG(AMPDU_KEYBORDER_SUPPORT),
 504        FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
 505        FLAG(SUPPORTS_RX_DECAP_OFFLOAD),
 506        FLAG(SUPPORTS_CONC_MON_RX_DECAP),
 507#undef FLAG
 508};
 509
 510static ssize_t hwflags_read(struct file *file, char __user *user_buf,
 511                            size_t count, loff_t *ppos)
 512{
 513        struct ieee80211_local *local = file->private_data;
 514        size_t bufsz = 30 * NUM_IEEE80211_HW_FLAGS;
 515        char *buf = kzalloc(bufsz, GFP_KERNEL);
 516        char *pos = buf, *end = buf + bufsz - 1;
 517        ssize_t rv;
 518        int i;
 519
 520        if (!buf)
 521                return -ENOMEM;
 522
 523        /* fail compilation if somebody adds or removes
 524         * a flag without updating the name array above
 525         */
 526        BUILD_BUG_ON(ARRAY_SIZE(hw_flag_names) != NUM_IEEE80211_HW_FLAGS);
 527
 528        for (i = 0; i < NUM_IEEE80211_HW_FLAGS; i++) {
 529                if (test_bit(i, local->hw.flags))
 530                        pos += scnprintf(pos, end - pos, "%s\n",
 531                                         hw_flag_names[i]);
 532        }
 533
 534        rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
 535        kfree(buf);
 536        return rv;
 537}
 538
 539static ssize_t misc_read(struct file *file, char __user *user_buf,
 540                         size_t count, loff_t *ppos)
 541{
 542        struct ieee80211_local *local = file->private_data;
 543        /* Max len of each line is 16 characters, plus 9 for 'pending:\n' */
 544        size_t bufsz = IEEE80211_MAX_QUEUES * 16 + 9;
 545        char *buf;
 546        char *pos, *end;
 547        ssize_t rv;
 548        int i;
 549        int ln;
 550
 551        buf = kzalloc(bufsz, GFP_KERNEL);
 552        if (!buf)
 553                return -ENOMEM;
 554
 555        pos = buf;
 556        end = buf + bufsz - 1;
 557
 558        pos += scnprintf(pos, end - pos, "pending:\n");
 559
 560        for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
 561                ln = skb_queue_len(&local->pending[i]);
 562                pos += scnprintf(pos, end - pos, "[%i] %d\n",
 563                                 i, ln);
 564        }
 565
 566        rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
 567        kfree(buf);
 568        return rv;
 569}
 570
 571static ssize_t queues_read(struct file *file, char __user *user_buf,
 572                           size_t count, loff_t *ppos)
 573{
 574        struct ieee80211_local *local = file->private_data;
 575        unsigned long flags;
 576        char buf[IEEE80211_MAX_QUEUES * 20];
 577        int q, res = 0;
 578
 579        spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
 580        for (q = 0; q < local->hw.queues; q++)
 581                res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
 582                                local->queue_stop_reasons[q],
 583                                skb_queue_len(&local->pending[q]));
 584        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 585
 586        return simple_read_from_buffer(user_buf, count, ppos, buf, res);
 587}
 588
 589DEBUGFS_READONLY_FILE_OPS(hwflags);
 590DEBUGFS_READONLY_FILE_OPS(queues);
 591DEBUGFS_READONLY_FILE_OPS(misc);
 592
 593/* statistics stuff */
 594
 595static ssize_t format_devstat_counter(struct ieee80211_local *local,
 596        char __user *userbuf,
 597        size_t count, loff_t *ppos,
 598        int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf,
 599                          int buflen))
 600{
 601        struct ieee80211_low_level_stats stats;
 602        char buf[20];
 603        int res;
 604
 605        rtnl_lock();
 606        res = drv_get_stats(local, &stats);
 607        rtnl_unlock();
 608        if (res)
 609                return res;
 610        res = printvalue(&stats, buf, sizeof(buf));
 611        return simple_read_from_buffer(userbuf, count, ppos, buf, res);
 612}
 613
 614#define DEBUGFS_DEVSTATS_FILE(name)                                     \
 615static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\
 616                                 char *buf, int buflen)                 \
 617{                                                                       \
 618        return scnprintf(buf, buflen, "%u\n", stats->name);             \
 619}                                                                       \
 620static ssize_t stats_ ##name## _read(struct file *file,                 \
 621                                     char __user *userbuf,              \
 622                                     size_t count, loff_t *ppos)        \
 623{                                                                       \
 624        return format_devstat_counter(file->private_data,               \
 625                                      userbuf,                          \
 626                                      count,                            \
 627                                      ppos,                             \
 628                                      print_devstats_##name);           \
 629}                                                                       \
 630                                                                        \
 631static const struct file_operations stats_ ##name## _ops = {            \
 632        .read = stats_ ##name## _read,                                  \
 633        .open = simple_open,                                            \
 634        .llseek = generic_file_llseek,                                  \
 635};
 636
 637#define DEBUGFS_STATS_ADD(name)                                 \
 638        debugfs_create_u32(#name, 0400, statsd, &local->name);
 639#define DEBUGFS_DEVSTATS_ADD(name)                                      \
 640        debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
 641
 642DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
 643DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
 644DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
 645DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
 646
 647void debugfs_hw_add(struct ieee80211_local *local)
 648{
 649        struct dentry *phyd = local->hw.wiphy->debugfsdir;
 650        struct dentry *statsd;
 651
 652        if (!phyd)
 653                return;
 654
 655        local->debugfs.keys = debugfs_create_dir("keys", phyd);
 656
 657        DEBUGFS_ADD(total_ps_buffered);
 658        DEBUGFS_ADD(wep_iv);
 659        DEBUGFS_ADD(rate_ctrl_alg);
 660        DEBUGFS_ADD(queues);
 661        DEBUGFS_ADD(misc);
 662#ifdef CONFIG_PM
 663        DEBUGFS_ADD_MODE(reset, 0200);
 664#endif
 665        DEBUGFS_ADD(hwflags);
 666        DEBUGFS_ADD(user_power);
 667        DEBUGFS_ADD(power);
 668        DEBUGFS_ADD(hw_conf);
 669        DEBUGFS_ADD_MODE(force_tx_status, 0600);
 670        DEBUGFS_ADD_MODE(aql_enable, 0600);
 671
 672        if (local->ops->wake_tx_queue)
 673                DEBUGFS_ADD_MODE(aqm, 0600);
 674
 675        if (wiphy_ext_feature_isset(local->hw.wiphy,
 676                                    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
 677                DEBUGFS_ADD_MODE(airtime, 0600);
 678                DEBUGFS_ADD_MODE(airtime_flags, 0600);
 679        }
 680
 681        DEBUGFS_ADD(aql_txq_limit);
 682        debugfs_create_u32("aql_threshold", 0600,
 683                           phyd, &local->aql_threshold);
 684
 685        statsd = debugfs_create_dir("statistics", phyd);
 686
 687        /* if the dir failed, don't put all the other things into the root! */
 688        if (!statsd)
 689                return;
 690
 691#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
 692        DEBUGFS_STATS_ADD(dot11TransmittedFragmentCount);
 693        DEBUGFS_STATS_ADD(dot11MulticastTransmittedFrameCount);
 694        DEBUGFS_STATS_ADD(dot11FailedCount);
 695        DEBUGFS_STATS_ADD(dot11RetryCount);
 696        DEBUGFS_STATS_ADD(dot11MultipleRetryCount);
 697        DEBUGFS_STATS_ADD(dot11FrameDuplicateCount);
 698        DEBUGFS_STATS_ADD(dot11ReceivedFragmentCount);
 699        DEBUGFS_STATS_ADD(dot11MulticastReceivedFrameCount);
 700        DEBUGFS_STATS_ADD(dot11TransmittedFrameCount);
 701        DEBUGFS_STATS_ADD(tx_handlers_drop);
 702        DEBUGFS_STATS_ADD(tx_handlers_queued);
 703        DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
 704        DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
 705        DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
 706        DEBUGFS_STATS_ADD(rx_handlers_drop);
 707        DEBUGFS_STATS_ADD(rx_handlers_queued);
 708        DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
 709        DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
 710        DEBUGFS_STATS_ADD(tx_expand_skb_head);
 711        DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
 712        DEBUGFS_STATS_ADD(rx_expand_skb_head_defrag);
 713        DEBUGFS_STATS_ADD(rx_handlers_fragments);
 714        DEBUGFS_STATS_ADD(tx_status_drop);
 715#endif
 716        DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
 717        DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
 718        DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
 719        DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
 720}
 721