linux/drivers/net/wireless/intel/iwlegacy/debug.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/******************************************************************************
   3 *
   4 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
   5 *
   6 * Contact Information:
   7 *  Intel Linux Wireless <ilw@linux.intel.com>
   8 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
   9 *****************************************************************************/
  10#include <linux/ieee80211.h>
  11#include <linux/export.h>
  12#include <net/mac80211.h>
  13
  14#include "common.h"
  15
  16static void
  17il_clear_traffic_stats(struct il_priv *il)
  18{
  19        memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
  20        memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
  21}
  22
  23/*
  24 * il_update_stats function record all the MGMT, CTRL and DATA pkt for
  25 * both TX and Rx . Use debugfs to display the rx/rx_stats
  26 */
  27void
  28il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
  29{
  30        struct traffic_stats *stats;
  31
  32        if (is_tx)
  33                stats = &il->tx_stats;
  34        else
  35                stats = &il->rx_stats;
  36
  37        if (ieee80211_is_mgmt(fc)) {
  38                switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
  39                case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
  40                        stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
  41                        break;
  42                case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
  43                        stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
  44                        break;
  45                case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
  46                        stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
  47                        break;
  48                case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
  49                        stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
  50                        break;
  51                case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
  52                        stats->mgmt[MANAGEMENT_PROBE_REQ]++;
  53                        break;
  54                case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
  55                        stats->mgmt[MANAGEMENT_PROBE_RESP]++;
  56                        break;
  57                case cpu_to_le16(IEEE80211_STYPE_BEACON):
  58                        stats->mgmt[MANAGEMENT_BEACON]++;
  59                        break;
  60                case cpu_to_le16(IEEE80211_STYPE_ATIM):
  61                        stats->mgmt[MANAGEMENT_ATIM]++;
  62                        break;
  63                case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
  64                        stats->mgmt[MANAGEMENT_DISASSOC]++;
  65                        break;
  66                case cpu_to_le16(IEEE80211_STYPE_AUTH):
  67                        stats->mgmt[MANAGEMENT_AUTH]++;
  68                        break;
  69                case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
  70                        stats->mgmt[MANAGEMENT_DEAUTH]++;
  71                        break;
  72                case cpu_to_le16(IEEE80211_STYPE_ACTION):
  73                        stats->mgmt[MANAGEMENT_ACTION]++;
  74                        break;
  75                }
  76        } else if (ieee80211_is_ctl(fc)) {
  77                switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
  78                case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
  79                        stats->ctrl[CONTROL_BACK_REQ]++;
  80                        break;
  81                case cpu_to_le16(IEEE80211_STYPE_BACK):
  82                        stats->ctrl[CONTROL_BACK]++;
  83                        break;
  84                case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
  85                        stats->ctrl[CONTROL_PSPOLL]++;
  86                        break;
  87                case cpu_to_le16(IEEE80211_STYPE_RTS):
  88                        stats->ctrl[CONTROL_RTS]++;
  89                        break;
  90                case cpu_to_le16(IEEE80211_STYPE_CTS):
  91                        stats->ctrl[CONTROL_CTS]++;
  92                        break;
  93                case cpu_to_le16(IEEE80211_STYPE_ACK):
  94                        stats->ctrl[CONTROL_ACK]++;
  95                        break;
  96                case cpu_to_le16(IEEE80211_STYPE_CFEND):
  97                        stats->ctrl[CONTROL_CFEND]++;
  98                        break;
  99                case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
 100                        stats->ctrl[CONTROL_CFENDACK]++;
 101                        break;
 102                }
 103        } else {
 104                /* data */
 105                stats->data_cnt++;
 106                stats->data_bytes += len;
 107        }
 108}
 109EXPORT_SYMBOL(il_update_stats);
 110
 111/* create and remove of files */
 112#define DEBUGFS_ADD_FILE(name, parent, mode) do {                       \
 113        debugfs_create_file(#name, mode, parent, il,                    \
 114                            &il_dbgfs_##name##_ops);                    \
 115} while (0)
 116
 117#define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                        \
 118        debugfs_create_bool(#name, 0600, parent, ptr);                  \
 119} while (0)
 120
 121/* file operation */
 122#define DEBUGFS_READ_FUNC(name)                                         \
 123static ssize_t il_dbgfs_##name##_read(struct file *file,               \
 124                                        char __user *user_buf,          \
 125                                        size_t count, loff_t *ppos);
 126
 127#define DEBUGFS_WRITE_FUNC(name)                                        \
 128static ssize_t il_dbgfs_##name##_write(struct file *file,              \
 129                                        const char __user *user_buf,    \
 130                                        size_t count, loff_t *ppos);
 131
 132
 133#define DEBUGFS_READ_FILE_OPS(name)                             \
 134        DEBUGFS_READ_FUNC(name);                                \
 135static const struct file_operations il_dbgfs_##name##_ops = {   \
 136        .read = il_dbgfs_##name##_read,                         \
 137        .open = simple_open,                                    \
 138        .llseek = generic_file_llseek,                          \
 139};
 140
 141#define DEBUGFS_WRITE_FILE_OPS(name)                            \
 142        DEBUGFS_WRITE_FUNC(name);                               \
 143static const struct file_operations il_dbgfs_##name##_ops = {   \
 144        .write = il_dbgfs_##name##_write,                       \
 145        .open = simple_open,                                    \
 146        .llseek = generic_file_llseek,                          \
 147};
 148
 149#define DEBUGFS_READ_WRITE_FILE_OPS(name)                       \
 150        DEBUGFS_READ_FUNC(name);                                \
 151        DEBUGFS_WRITE_FUNC(name);                               \
 152static const struct file_operations il_dbgfs_##name##_ops = {   \
 153        .write = il_dbgfs_##name##_write,                       \
 154        .read = il_dbgfs_##name##_read,                         \
 155        .open = simple_open,                                    \
 156        .llseek = generic_file_llseek,                          \
 157};
 158
 159static const char *
 160il_get_mgmt_string(int cmd)
 161{
 162        switch (cmd) {
 163        IL_CMD(MANAGEMENT_ASSOC_REQ);
 164        IL_CMD(MANAGEMENT_ASSOC_RESP);
 165        IL_CMD(MANAGEMENT_REASSOC_REQ);
 166        IL_CMD(MANAGEMENT_REASSOC_RESP);
 167        IL_CMD(MANAGEMENT_PROBE_REQ);
 168        IL_CMD(MANAGEMENT_PROBE_RESP);
 169        IL_CMD(MANAGEMENT_BEACON);
 170        IL_CMD(MANAGEMENT_ATIM);
 171        IL_CMD(MANAGEMENT_DISASSOC);
 172        IL_CMD(MANAGEMENT_AUTH);
 173        IL_CMD(MANAGEMENT_DEAUTH);
 174        IL_CMD(MANAGEMENT_ACTION);
 175        default:
 176                return "UNKNOWN";
 177
 178        }
 179}
 180
 181static const char *
 182il_get_ctrl_string(int cmd)
 183{
 184        switch (cmd) {
 185        IL_CMD(CONTROL_BACK_REQ);
 186        IL_CMD(CONTROL_BACK);
 187        IL_CMD(CONTROL_PSPOLL);
 188        IL_CMD(CONTROL_RTS);
 189        IL_CMD(CONTROL_CTS);
 190        IL_CMD(CONTROL_ACK);
 191        IL_CMD(CONTROL_CFEND);
 192        IL_CMD(CONTROL_CFENDACK);
 193        default:
 194                return "UNKNOWN";
 195
 196        }
 197}
 198
 199static ssize_t
 200il_dbgfs_tx_stats_read(struct file *file, char __user *user_buf, size_t count,
 201                       loff_t *ppos)
 202{
 203
 204        struct il_priv *il = file->private_data;
 205        char *buf;
 206        int pos = 0;
 207
 208        int cnt;
 209        ssize_t ret;
 210        const size_t bufsz =
 211            100 + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
 212        buf = kzalloc(bufsz, GFP_KERNEL);
 213        if (!buf)
 214                return -ENOMEM;
 215        pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
 216        for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
 217                pos +=
 218                    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
 219                              il_get_mgmt_string(cnt), il->tx_stats.mgmt[cnt]);
 220        }
 221        pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
 222        for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
 223                pos +=
 224                    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
 225                              il_get_ctrl_string(cnt), il->tx_stats.ctrl[cnt]);
 226        }
 227        pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
 228        pos +=
 229            scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
 230                      il->tx_stats.data_cnt);
 231        pos +=
 232            scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
 233                      il->tx_stats.data_bytes);
 234        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 235        kfree(buf);
 236        return ret;
 237}
 238
 239static ssize_t
 240il_dbgfs_clear_traffic_stats_write(struct file *file,
 241                                   const char __user *user_buf, size_t count,
 242                                   loff_t *ppos)
 243{
 244        struct il_priv *il = file->private_data;
 245        u32 clear_flag;
 246        char buf[8];
 247        int buf_size;
 248
 249        memset(buf, 0, sizeof(buf));
 250        buf_size = min(count, sizeof(buf) - 1);
 251        if (copy_from_user(buf, user_buf, buf_size))
 252                return -EFAULT;
 253        if (sscanf(buf, "%x", &clear_flag) != 1)
 254                return -EFAULT;
 255        il_clear_traffic_stats(il);
 256
 257        return count;
 258}
 259
 260static ssize_t
 261il_dbgfs_rx_stats_read(struct file *file, char __user *user_buf, size_t count,
 262                       loff_t *ppos)
 263{
 264
 265        struct il_priv *il = file->private_data;
 266        char *buf;
 267        int pos = 0;
 268        int cnt;
 269        ssize_t ret;
 270        const size_t bufsz =
 271            100 + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
 272        buf = kzalloc(bufsz, GFP_KERNEL);
 273        if (!buf)
 274                return -ENOMEM;
 275
 276        pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
 277        for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
 278                pos +=
 279                    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
 280                              il_get_mgmt_string(cnt), il->rx_stats.mgmt[cnt]);
 281        }
 282        pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
 283        for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
 284                pos +=
 285                    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
 286                              il_get_ctrl_string(cnt), il->rx_stats.ctrl[cnt]);
 287        }
 288        pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
 289        pos +=
 290            scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
 291                      il->rx_stats.data_cnt);
 292        pos +=
 293            scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
 294                      il->rx_stats.data_bytes);
 295
 296        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 297        kfree(buf);
 298        return ret;
 299}
 300
 301#define BYTE1_MASK 0x000000ff;
 302#define BYTE2_MASK 0x0000ffff;
 303#define BYTE3_MASK 0x00ffffff;
 304static ssize_t
 305il_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count,
 306                   loff_t *ppos)
 307{
 308        u32 val;
 309        char *buf;
 310        ssize_t ret;
 311        int i;
 312        int pos = 0;
 313        struct il_priv *il = file->private_data;
 314        size_t bufsz;
 315
 316        /* default is to dump the entire data segment */
 317        if (!il->dbgfs_sram_offset && !il->dbgfs_sram_len) {
 318                il->dbgfs_sram_offset = 0x800000;
 319                if (il->ucode_type == UCODE_INIT)
 320                        il->dbgfs_sram_len = il->ucode_init_data.len;
 321                else
 322                        il->dbgfs_sram_len = il->ucode_data.len;
 323        }
 324        bufsz = 30 + il->dbgfs_sram_len * sizeof(char) * 10;
 325        buf = kmalloc(bufsz, GFP_KERNEL);
 326        if (!buf)
 327                return -ENOMEM;
 328        pos +=
 329            scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
 330                      il->dbgfs_sram_len);
 331        pos +=
 332            scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
 333                      il->dbgfs_sram_offset);
 334        for (i = il->dbgfs_sram_len; i > 0; i -= 4) {
 335                val =
 336                    il_read_targ_mem(il,
 337                                     il->dbgfs_sram_offset +
 338                                     il->dbgfs_sram_len - i);
 339                if (i < 4) {
 340                        switch (i) {
 341                        case 1:
 342                                val &= BYTE1_MASK;
 343                                break;
 344                        case 2:
 345                                val &= BYTE2_MASK;
 346                                break;
 347                        case 3:
 348                                val &= BYTE3_MASK;
 349                                break;
 350                        }
 351                }
 352                if (!(i % 16))
 353                        pos += scnprintf(buf + pos, bufsz - pos, "\n");
 354                pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
 355        }
 356        pos += scnprintf(buf + pos, bufsz - pos, "\n");
 357
 358        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 359        kfree(buf);
 360        return ret;
 361}
 362
 363static ssize_t
 364il_dbgfs_sram_write(struct file *file, const char __user *user_buf,
 365                    size_t count, loff_t *ppos)
 366{
 367        struct il_priv *il = file->private_data;
 368        char buf[64];
 369        int buf_size;
 370        u32 offset, len;
 371
 372        memset(buf, 0, sizeof(buf));
 373        buf_size = min(count, sizeof(buf) - 1);
 374        if (copy_from_user(buf, user_buf, buf_size))
 375                return -EFAULT;
 376
 377        if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
 378                il->dbgfs_sram_offset = offset;
 379                il->dbgfs_sram_len = len;
 380        } else {
 381                il->dbgfs_sram_offset = 0;
 382                il->dbgfs_sram_len = 0;
 383        }
 384
 385        return count;
 386}
 387
 388static ssize_t
 389il_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count,
 390                       loff_t *ppos)
 391{
 392        struct il_priv *il = file->private_data;
 393        struct il_station_entry *station;
 394        int max_sta = il->hw_params.max_stations;
 395        char *buf;
 396        int i, j, pos = 0;
 397        ssize_t ret;
 398        /* Add 30 for initial string */
 399        const size_t bufsz = 30 + sizeof(char) * 500 * (il->num_stations);
 400
 401        buf = kmalloc(bufsz, GFP_KERNEL);
 402        if (!buf)
 403                return -ENOMEM;
 404
 405        pos +=
 406            scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
 407                      il->num_stations);
 408
 409        for (i = 0; i < max_sta; i++) {
 410                station = &il->stations[i];
 411                if (!station->used)
 412                        continue;
 413                pos +=
 414                    scnprintf(buf + pos, bufsz - pos,
 415                              "station %d - addr: %pM, flags: %#x\n", i,
 416                              station->sta.sta.addr,
 417                              station->sta.station_flags_msk);
 418                pos +=
 419                    scnprintf(buf + pos, bufsz - pos,
 420                              "TID\tseq_num\ttxq_id\tframes\ttfds\t");
 421                pos +=
 422                    scnprintf(buf + pos, bufsz - pos,
 423                              "start_idx\tbitmap\t\t\trate_n_flags\n");
 424
 425                for (j = 0; j < MAX_TID_COUNT; j++) {
 426                        pos +=
 427                            scnprintf(buf + pos, bufsz - pos,
 428                                      "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
 429                                      j, station->tid[j].seq_number,
 430                                      station->tid[j].agg.txq_id,
 431                                      station->tid[j].agg.frame_count,
 432                                      station->tid[j].tfds_in_queue,
 433                                      station->tid[j].agg.start_idx,
 434                                      station->tid[j].agg.bitmap,
 435                                      station->tid[j].agg.rate_n_flags);
 436
 437                        if (station->tid[j].agg.wait_for_ba)
 438                                pos +=
 439                                    scnprintf(buf + pos, bufsz - pos,
 440                                              " - waitforba");
 441                        pos += scnprintf(buf + pos, bufsz - pos, "\n");
 442                }
 443
 444                pos += scnprintf(buf + pos, bufsz - pos, "\n");
 445        }
 446
 447        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 448        kfree(buf);
 449        return ret;
 450}
 451
 452static ssize_t
 453il_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count,
 454                  loff_t *ppos)
 455{
 456        ssize_t ret;
 457        struct il_priv *il = file->private_data;
 458        int pos = 0, ofs = 0, buf_size = 0;
 459        const u8 *ptr;
 460        char *buf;
 461        u16 eeprom_ver;
 462        size_t eeprom_len = il->cfg->eeprom_size;
 463        buf_size = 4 * eeprom_len + 256;
 464
 465        if (eeprom_len % 16) {
 466                IL_ERR("NVM size is not multiple of 16.\n");
 467                return -ENODATA;
 468        }
 469
 470        ptr = il->eeprom;
 471        if (!ptr) {
 472                IL_ERR("Invalid EEPROM memory\n");
 473                return -ENOMEM;
 474        }
 475
 476        /* 4 characters for byte 0xYY */
 477        buf = kzalloc(buf_size, GFP_KERNEL);
 478        if (!buf) {
 479                IL_ERR("Can not allocate Buffer\n");
 480                return -ENOMEM;
 481        }
 482        eeprom_ver = il_eeprom_query16(il, EEPROM_VERSION);
 483        pos +=
 484            scnprintf(buf + pos, buf_size - pos, "EEPROM " "version: 0x%x\n",
 485                      eeprom_ver);
 486        for (ofs = 0; ofs < eeprom_len; ofs += 16) {
 487                pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x %16ph\n",
 488                                 ofs, ptr + ofs);
 489        }
 490
 491        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 492        kfree(buf);
 493        return ret;
 494}
 495
 496static ssize_t
 497il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
 498                       loff_t *ppos)
 499{
 500        struct il_priv *il = file->private_data;
 501        struct ieee80211_channel *channels = NULL;
 502        const struct ieee80211_supported_band *supp_band = NULL;
 503        int pos = 0, i, bufsz = PAGE_SIZE;
 504        char *buf;
 505        ssize_t ret;
 506
 507        if (!test_bit(S_GEO_CONFIGURED, &il->status))
 508                return -EAGAIN;
 509
 510        buf = kzalloc(bufsz, GFP_KERNEL);
 511        if (!buf) {
 512                IL_ERR("Can not allocate Buffer\n");
 513                return -ENOMEM;
 514        }
 515
 516        supp_band = il_get_hw_mode(il, NL80211_BAND_2GHZ);
 517        if (supp_band) {
 518                channels = supp_band->channels;
 519
 520                pos +=
 521                    scnprintf(buf + pos, bufsz - pos,
 522                              "Displaying %d channels in 2.4GHz band 802.11bg):\n",
 523                              supp_band->n_channels);
 524
 525                for (i = 0; i < supp_band->n_channels; i++)
 526                        pos +=
 527                            scnprintf(buf + pos, bufsz - pos,
 528                                      "%d: %ddBm: BSS%s%s, %s.\n",
 529                                      channels[i].hw_value,
 530                                      channels[i].max_power,
 531                                      channels[i].
 532                                      flags & IEEE80211_CHAN_RADAR ?
 533                                      " (IEEE 802.11h required)" : "",
 534                                      ((channels[i].
 535                                        flags & IEEE80211_CHAN_NO_IR) ||
 536                                       (channels[i].
 537                                        flags & IEEE80211_CHAN_RADAR)) ? "" :
 538                                      ", IBSS",
 539                                      channels[i].
 540                                      flags & IEEE80211_CHAN_NO_IR ?
 541                                      "passive only" : "active/passive");
 542        }
 543        supp_band = il_get_hw_mode(il, NL80211_BAND_5GHZ);
 544        if (supp_band) {
 545                channels = supp_band->channels;
 546
 547                pos +=
 548                    scnprintf(buf + pos, bufsz - pos,
 549                              "Displaying %d channels in 5.2GHz band (802.11a)\n",
 550                              supp_band->n_channels);
 551
 552                for (i = 0; i < supp_band->n_channels; i++)
 553                        pos +=
 554                            scnprintf(buf + pos, bufsz - pos,
 555                                      "%d: %ddBm: BSS%s%s, %s.\n",
 556                                      channels[i].hw_value,
 557                                      channels[i].max_power,
 558                                      channels[i].
 559                                      flags & IEEE80211_CHAN_RADAR ?
 560                                      " (IEEE 802.11h required)" : "",
 561                                      ((channels[i].
 562                                        flags & IEEE80211_CHAN_NO_IR) ||
 563                                       (channels[i].
 564                                        flags & IEEE80211_CHAN_RADAR)) ? "" :
 565                                      ", IBSS",
 566                                      channels[i].
 567                                      flags & IEEE80211_CHAN_NO_IR ?
 568                                      "passive only" : "active/passive");
 569        }
 570        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 571        kfree(buf);
 572        return ret;
 573}
 574
 575static ssize_t
 576il_dbgfs_status_read(struct file *file, char __user *user_buf, size_t count,
 577                     loff_t *ppos)
 578{
 579
 580        struct il_priv *il = file->private_data;
 581        char buf[512];
 582        int pos = 0;
 583        const size_t bufsz = sizeof(buf);
 584
 585        pos +=
 586            scnprintf(buf + pos, bufsz - pos, "S_HCMD_ACTIVE:\t %d\n",
 587                      test_bit(S_HCMD_ACTIVE, &il->status));
 588        pos +=
 589            scnprintf(buf + pos, bufsz - pos, "S_INT_ENABLED:\t %d\n",
 590                      test_bit(S_INT_ENABLED, &il->status));
 591        pos +=
 592            scnprintf(buf + pos, bufsz - pos, "S_RFKILL:\t %d\n",
 593                      test_bit(S_RFKILL, &il->status));
 594        pos +=
 595            scnprintf(buf + pos, bufsz - pos, "S_CT_KILL:\t\t %d\n",
 596                      test_bit(S_CT_KILL, &il->status));
 597        pos +=
 598            scnprintf(buf + pos, bufsz - pos, "S_INIT:\t\t %d\n",
 599                      test_bit(S_INIT, &il->status));
 600        pos +=
 601            scnprintf(buf + pos, bufsz - pos, "S_ALIVE:\t\t %d\n",
 602                      test_bit(S_ALIVE, &il->status));
 603        pos +=
 604            scnprintf(buf + pos, bufsz - pos, "S_READY:\t\t %d\n",
 605                      test_bit(S_READY, &il->status));
 606        pos +=
 607            scnprintf(buf + pos, bufsz - pos, "S_TEMPERATURE:\t %d\n",
 608                      test_bit(S_TEMPERATURE, &il->status));
 609        pos +=
 610            scnprintf(buf + pos, bufsz - pos, "S_GEO_CONFIGURED:\t %d\n",
 611                      test_bit(S_GEO_CONFIGURED, &il->status));
 612        pos +=
 613            scnprintf(buf + pos, bufsz - pos, "S_EXIT_PENDING:\t %d\n",
 614                      test_bit(S_EXIT_PENDING, &il->status));
 615        pos +=
 616            scnprintf(buf + pos, bufsz - pos, "S_STATS:\t %d\n",
 617                      test_bit(S_STATS, &il->status));
 618        pos +=
 619            scnprintf(buf + pos, bufsz - pos, "S_SCANNING:\t %d\n",
 620                      test_bit(S_SCANNING, &il->status));
 621        pos +=
 622            scnprintf(buf + pos, bufsz - pos, "S_SCAN_ABORTING:\t %d\n",
 623                      test_bit(S_SCAN_ABORTING, &il->status));
 624        pos +=
 625            scnprintf(buf + pos, bufsz - pos, "S_SCAN_HW:\t\t %d\n",
 626                      test_bit(S_SCAN_HW, &il->status));
 627        pos +=
 628            scnprintf(buf + pos, bufsz - pos, "S_POWER_PMI:\t %d\n",
 629                      test_bit(S_POWER_PMI, &il->status));
 630        pos +=
 631            scnprintf(buf + pos, bufsz - pos, "S_FW_ERROR:\t %d\n",
 632                      test_bit(S_FW_ERROR, &il->status));
 633        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 634}
 635
 636static ssize_t
 637il_dbgfs_interrupt_read(struct file *file, char __user *user_buf, size_t count,
 638                        loff_t *ppos)
 639{
 640
 641        struct il_priv *il = file->private_data;
 642        int pos = 0;
 643        int cnt = 0;
 644        char *buf;
 645        int bufsz = 24 * 64;    /* 24 items * 64 char per item */
 646        ssize_t ret;
 647
 648        buf = kzalloc(bufsz, GFP_KERNEL);
 649        if (!buf) {
 650                IL_ERR("Can not allocate Buffer\n");
 651                return -ENOMEM;
 652        }
 653
 654        pos +=
 655            scnprintf(buf + pos, bufsz - pos, "Interrupt Statistics Report:\n");
 656
 657        pos +=
 658            scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
 659                      il->isr_stats.hw);
 660        pos +=
 661            scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
 662                      il->isr_stats.sw);
 663        if (il->isr_stats.sw || il->isr_stats.hw) {
 664                pos +=
 665                    scnprintf(buf + pos, bufsz - pos,
 666                              "\tLast Restarting Code:  0x%X\n",
 667                              il->isr_stats.err_code);
 668        }
 669#ifdef CONFIG_IWLEGACY_DEBUG
 670        pos +=
 671            scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
 672                      il->isr_stats.sch);
 673        pos +=
 674            scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
 675                      il->isr_stats.alive);
 676#endif
 677        pos +=
 678            scnprintf(buf + pos, bufsz - pos,
 679                      "HW RF KILL switch toggled:\t %u\n",
 680                      il->isr_stats.rfkill);
 681
 682        pos +=
 683            scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
 684                      il->isr_stats.ctkill);
 685
 686        pos +=
 687            scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
 688                      il->isr_stats.wakeup);
 689
 690        pos +=
 691            scnprintf(buf + pos, bufsz - pos, "Rx command responses:\t\t %u\n",
 692                      il->isr_stats.rx);
 693        for (cnt = 0; cnt < IL_CN_MAX; cnt++) {
 694                if (il->isr_stats.handlers[cnt] > 0)
 695                        pos +=
 696                            scnprintf(buf + pos, bufsz - pos,
 697                                      "\tRx handler[%36s]:\t\t %u\n",
 698                                      il_get_cmd_string(cnt),
 699                                      il->isr_stats.handlers[cnt]);
 700        }
 701
 702        pos +=
 703            scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
 704                      il->isr_stats.tx);
 705
 706        pos +=
 707            scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
 708                      il->isr_stats.unhandled);
 709
 710        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 711        kfree(buf);
 712        return ret;
 713}
 714
 715static ssize_t
 716il_dbgfs_interrupt_write(struct file *file, const char __user *user_buf,
 717                         size_t count, loff_t *ppos)
 718{
 719        struct il_priv *il = file->private_data;
 720        char buf[8];
 721        int buf_size;
 722        u32 reset_flag;
 723
 724        memset(buf, 0, sizeof(buf));
 725        buf_size = min(count, sizeof(buf) - 1);
 726        if (copy_from_user(buf, user_buf, buf_size))
 727                return -EFAULT;
 728        if (sscanf(buf, "%x", &reset_flag) != 1)
 729                return -EFAULT;
 730        if (reset_flag == 0)
 731                il_clear_isr_stats(il);
 732
 733        return count;
 734}
 735
 736static ssize_t
 737il_dbgfs_qos_read(struct file *file, char __user *user_buf, size_t count,
 738                  loff_t *ppos)
 739{
 740        struct il_priv *il = file->private_data;
 741        int pos = 0, i;
 742        char buf[256];
 743        const size_t bufsz = sizeof(buf);
 744
 745        for (i = 0; i < AC_NUM; i++) {
 746                pos +=
 747                    scnprintf(buf + pos, bufsz - pos,
 748                              "\tcw_min\tcw_max\taifsn\ttxop\n");
 749                pos +=
 750                    scnprintf(buf + pos, bufsz - pos,
 751                              "AC[%d]\t%u\t%u\t%u\t%u\n", i,
 752                              il->qos_data.def_qos_parm.ac[i].cw_min,
 753                              il->qos_data.def_qos_parm.ac[i].cw_max,
 754                              il->qos_data.def_qos_parm.ac[i].aifsn,
 755                              il->qos_data.def_qos_parm.ac[i].edca_txop);
 756        }
 757
 758        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 759}
 760
 761static ssize_t
 762il_dbgfs_disable_ht40_write(struct file *file, const char __user *user_buf,
 763                            size_t count, loff_t *ppos)
 764{
 765        struct il_priv *il = file->private_data;
 766        char buf[8];
 767        int buf_size;
 768        int ht40;
 769
 770        memset(buf, 0, sizeof(buf));
 771        buf_size = min(count, sizeof(buf) - 1);
 772        if (copy_from_user(buf, user_buf, buf_size))
 773                return -EFAULT;
 774        if (sscanf(buf, "%d", &ht40) != 1)
 775                return -EFAULT;
 776        if (!il_is_any_associated(il))
 777                il->disable_ht40 = ht40 ? true : false;
 778        else {
 779                IL_ERR("Sta associated with AP - "
 780                       "Change to 40MHz channel support is not allowed\n");
 781                return -EINVAL;
 782        }
 783
 784        return count;
 785}
 786
 787static ssize_t
 788il_dbgfs_disable_ht40_read(struct file *file, char __user *user_buf,
 789                           size_t count, loff_t *ppos)
 790{
 791        struct il_priv *il = file->private_data;
 792        char buf[100];
 793        int pos = 0;
 794        const size_t bufsz = sizeof(buf);
 795
 796        pos +=
 797            scnprintf(buf + pos, bufsz - pos, "11n 40MHz Mode: %s\n",
 798                      il->disable_ht40 ? "Disabled" : "Enabled");
 799        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 800}
 801
 802DEBUGFS_READ_WRITE_FILE_OPS(sram);
 803DEBUGFS_READ_FILE_OPS(nvm);
 804DEBUGFS_READ_FILE_OPS(stations);
 805DEBUGFS_READ_FILE_OPS(channels);
 806DEBUGFS_READ_FILE_OPS(status);
 807DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
 808DEBUGFS_READ_FILE_OPS(qos);
 809DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
 810
 811static ssize_t
 812il_dbgfs_tx_queue_read(struct file *file, char __user *user_buf, size_t count,
 813                       loff_t *ppos)
 814{
 815
 816        struct il_priv *il = file->private_data;
 817        struct il_tx_queue *txq;
 818        struct il_queue *q;
 819        char *buf;
 820        int pos = 0;
 821        int cnt;
 822        int ret;
 823        const size_t bufsz =
 824            sizeof(char) * 64 * il->cfg->num_of_queues;
 825
 826        if (!il->txq) {
 827                IL_ERR("txq not ready\n");
 828                return -EAGAIN;
 829        }
 830        buf = kzalloc(bufsz, GFP_KERNEL);
 831        if (!buf)
 832                return -ENOMEM;
 833
 834        for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) {
 835                txq = &il->txq[cnt];
 836                q = &txq->q;
 837                pos +=
 838                    scnprintf(buf + pos, bufsz - pos,
 839                              "hwq %.2d: read=%u write=%u stop=%d"
 840                              " swq_id=%#.2x (ac %d/hwq %d)\n", cnt,
 841                              q->read_ptr, q->write_ptr,
 842                              !!test_bit(cnt, il->queue_stopped),
 843                              txq->swq_id, txq->swq_id & 3,
 844                              (txq->swq_id >> 2) & 0x1f);
 845                if (cnt >= 4)
 846                        continue;
 847                /* for the ACs, display the stop count too */
 848                pos +=
 849                    scnprintf(buf + pos, bufsz - pos,
 850                              "        stop-count: %d\n",
 851                              atomic_read(&il->queue_stop_count[cnt]));
 852        }
 853        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 854        kfree(buf);
 855        return ret;
 856}
 857
 858static ssize_t
 859il_dbgfs_rx_queue_read(struct file *file, char __user *user_buf, size_t count,
 860                       loff_t *ppos)
 861{
 862
 863        struct il_priv *il = file->private_data;
 864        struct il_rx_queue *rxq = &il->rxq;
 865        char buf[256];
 866        int pos = 0;
 867        const size_t bufsz = sizeof(buf);
 868
 869        pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", rxq->read);
 870        pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", rxq->write);
 871        pos +=
 872            scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
 873                      rxq->free_count);
 874        if (rxq->rb_stts) {
 875                pos +=
 876                    scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
 877                              le16_to_cpu(rxq->rb_stts->
 878                                          closed_rb_num) & 0x0FFF);
 879        } else {
 880                pos +=
 881                    scnprintf(buf + pos, bufsz - pos,
 882                              "closed_rb_num: Not Allocated\n");
 883        }
 884        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 885}
 886
 887static ssize_t
 888il_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf,
 889                             size_t count, loff_t *ppos)
 890{
 891        struct il_priv *il = file->private_data;
 892
 893        return il->debugfs_ops->rx_stats_read(file, user_buf, count, ppos);
 894}
 895
 896static ssize_t
 897il_dbgfs_ucode_tx_stats_read(struct file *file, char __user *user_buf,
 898                             size_t count, loff_t *ppos)
 899{
 900        struct il_priv *il = file->private_data;
 901
 902        return il->debugfs_ops->tx_stats_read(file, user_buf, count, ppos);
 903}
 904
 905static ssize_t
 906il_dbgfs_ucode_general_stats_read(struct file *file, char __user *user_buf,
 907                                  size_t count, loff_t *ppos)
 908{
 909        struct il_priv *il = file->private_data;
 910
 911        return il->debugfs_ops->general_stats_read(file, user_buf, count, ppos);
 912}
 913
 914static ssize_t
 915il_dbgfs_sensitivity_read(struct file *file, char __user *user_buf,
 916                          size_t count, loff_t *ppos)
 917{
 918
 919        struct il_priv *il = file->private_data;
 920        int pos = 0;
 921        int cnt = 0;
 922        char *buf;
 923        int bufsz = sizeof(struct il_sensitivity_data) * 4 + 100;
 924        ssize_t ret;
 925        struct il_sensitivity_data *data;
 926
 927        data = &il->sensitivity_data;
 928        buf = kzalloc(bufsz, GFP_KERNEL);
 929        if (!buf) {
 930                IL_ERR("Can not allocate Buffer\n");
 931                return -ENOMEM;
 932        }
 933
 934        pos +=
 935            scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
 936                      data->auto_corr_ofdm);
 937        pos +=
 938            scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_mrc:\t\t %u\n",
 939                      data->auto_corr_ofdm_mrc);
 940        pos +=
 941            scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
 942                      data->auto_corr_ofdm_x1);
 943        pos +=
 944            scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_mrc_x1:\t\t %u\n",
 945                      data->auto_corr_ofdm_mrc_x1);
 946        pos +=
 947            scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
 948                      data->auto_corr_cck);
 949        pos +=
 950            scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
 951                      data->auto_corr_cck_mrc);
 952        pos +=
 953            scnprintf(buf + pos, bufsz - pos,
 954                      "last_bad_plcp_cnt_ofdm:\t\t %u\n",
 955                      data->last_bad_plcp_cnt_ofdm);
 956        pos +=
 957            scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
 958                      data->last_fa_cnt_ofdm);
 959        pos +=
 960            scnprintf(buf + pos, bufsz - pos, "last_bad_plcp_cnt_cck:\t\t %u\n",
 961                      data->last_bad_plcp_cnt_cck);
 962        pos +=
 963            scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
 964                      data->last_fa_cnt_cck);
 965        pos +=
 966            scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
 967                      data->nrg_curr_state);
 968        pos +=
 969            scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
 970                      data->nrg_prev_state);
 971        pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
 972        for (cnt = 0; cnt < 10; cnt++) {
 973                pos +=
 974                    scnprintf(buf + pos, bufsz - pos, " %u",
 975                              data->nrg_value[cnt]);
 976        }
 977        pos += scnprintf(buf + pos, bufsz - pos, "\n");
 978        pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
 979        for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
 980                pos +=
 981                    scnprintf(buf + pos, bufsz - pos, " %u",
 982                              data->nrg_silence_rssi[cnt]);
 983        }
 984        pos += scnprintf(buf + pos, bufsz - pos, "\n");
 985        pos +=
 986            scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
 987                      data->nrg_silence_ref);
 988        pos +=
 989            scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
 990                      data->nrg_energy_idx);
 991        pos +=
 992            scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
 993                      data->nrg_silence_idx);
 994        pos +=
 995            scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
 996                      data->nrg_th_cck);
 997        pos +=
 998            scnprintf(buf + pos, bufsz - pos,
 999                      "nrg_auto_corr_silence_diff:\t %u\n",
1000                      data->nrg_auto_corr_silence_diff);
1001        pos +=
1002            scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
1003                      data->num_in_cck_no_fa);
1004        pos +=
1005            scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
1006                      data->nrg_th_ofdm);
1007
1008        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1009        kfree(buf);
1010        return ret;
1011}
1012
1013static ssize_t
1014il_dbgfs_chain_noise_read(struct file *file, char __user *user_buf,
1015                          size_t count, loff_t *ppos)
1016{
1017
1018        struct il_priv *il = file->private_data;
1019        int pos = 0;
1020        int cnt = 0;
1021        char *buf;
1022        int bufsz = sizeof(struct il_chain_noise_data) * 4 + 100;
1023        ssize_t ret;
1024        struct il_chain_noise_data *data;
1025
1026        data = &il->chain_noise_data;
1027        buf = kzalloc(bufsz, GFP_KERNEL);
1028        if (!buf) {
1029                IL_ERR("Can not allocate Buffer\n");
1030                return -ENOMEM;
1031        }
1032
1033        pos +=
1034            scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
1035                      data->active_chains);
1036        pos +=
1037            scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
1038                      data->chain_noise_a);
1039        pos +=
1040            scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
1041                      data->chain_noise_b);
1042        pos +=
1043            scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
1044                      data->chain_noise_c);
1045        pos +=
1046            scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
1047                      data->chain_signal_a);
1048        pos +=
1049            scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
1050                      data->chain_signal_b);
1051        pos +=
1052            scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
1053                      data->chain_signal_c);
1054        pos +=
1055            scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
1056                      data->beacon_count);
1057
1058        pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
1059        for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
1060                pos +=
1061                    scnprintf(buf + pos, bufsz - pos, " %u",
1062                              data->disconn_array[cnt]);
1063        }
1064        pos += scnprintf(buf + pos, bufsz - pos, "\n");
1065        pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
1066        for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
1067                pos +=
1068                    scnprintf(buf + pos, bufsz - pos, " %u",
1069                              data->delta_gain_code[cnt]);
1070        }
1071        pos += scnprintf(buf + pos, bufsz - pos, "\n");
1072        pos +=
1073            scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
1074                      data->radio_write);
1075        pos +=
1076            scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
1077                      data->state);
1078
1079        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1080        kfree(buf);
1081        return ret;
1082}
1083
1084static ssize_t
1085il_dbgfs_power_save_status_read(struct file *file, char __user *user_buf,
1086                                size_t count, loff_t *ppos)
1087{
1088        struct il_priv *il = file->private_data;
1089        char buf[60];
1090        int pos = 0;
1091        const size_t bufsz = sizeof(buf);
1092        u32 pwrsave_status;
1093
1094        pwrsave_status =
1095            _il_rd(il, CSR_GP_CNTRL) & CSR_GP_REG_POWER_SAVE_STATUS_MSK;
1096
1097        pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
1098        pos +=
1099            scnprintf(buf + pos, bufsz - pos, "%s\n",
1100                      (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
1101                      (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
1102                      (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
1103                      "error");
1104
1105        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1106}
1107
1108static ssize_t
1109il_dbgfs_clear_ucode_stats_write(struct file *file,
1110                                 const char __user *user_buf, size_t count,
1111                                 loff_t *ppos)
1112{
1113        struct il_priv *il = file->private_data;
1114        char buf[8];
1115        int buf_size;
1116        int clear;
1117
1118        memset(buf, 0, sizeof(buf));
1119        buf_size = min(count, sizeof(buf) - 1);
1120        if (copy_from_user(buf, user_buf, buf_size))
1121                return -EFAULT;
1122        if (sscanf(buf, "%d", &clear) != 1)
1123                return -EFAULT;
1124
1125        /* make request to uCode to retrieve stats information */
1126        mutex_lock(&il->mutex);
1127        il_send_stats_request(il, CMD_SYNC, true);
1128        mutex_unlock(&il->mutex);
1129
1130        return count;
1131}
1132
1133static ssize_t
1134il_dbgfs_rxon_flags_read(struct file *file, char __user *user_buf,
1135                         size_t count, loff_t *ppos)
1136{
1137
1138        struct il_priv *il = file->private_data;
1139        int len = 0;
1140        char buf[20];
1141
1142        len = sprintf(buf, "0x%04X\n", le32_to_cpu(il->active.flags));
1143        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1144}
1145
1146static ssize_t
1147il_dbgfs_rxon_filter_flags_read(struct file *file, char __user *user_buf,
1148                                size_t count, loff_t *ppos)
1149{
1150
1151        struct il_priv *il = file->private_data;
1152        int len = 0;
1153        char buf[20];
1154
1155        len =
1156            sprintf(buf, "0x%04X\n", le32_to_cpu(il->active.filter_flags));
1157        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1158}
1159
1160static ssize_t
1161il_dbgfs_fh_reg_read(struct file *file, char __user *user_buf, size_t count,
1162                     loff_t *ppos)
1163{
1164        struct il_priv *il = file->private_data;
1165        char *buf;
1166        int pos = 0;
1167        ssize_t ret = -EFAULT;
1168
1169        if (il->ops->dump_fh) {
1170                ret = pos = il->ops->dump_fh(il, &buf, true);
1171                if (buf) {
1172                        ret =
1173                            simple_read_from_buffer(user_buf, count, ppos, buf,
1174                                                    pos);
1175                        kfree(buf);
1176                }
1177        }
1178
1179        return ret;
1180}
1181
1182static ssize_t
1183il_dbgfs_missed_beacon_read(struct file *file, char __user *user_buf,
1184                            size_t count, loff_t *ppos)
1185{
1186
1187        struct il_priv *il = file->private_data;
1188        int pos = 0;
1189        char buf[12];
1190        const size_t bufsz = sizeof(buf);
1191
1192        pos +=
1193            scnprintf(buf + pos, bufsz - pos, "%d\n",
1194                      il->missed_beacon_threshold);
1195
1196        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1197}
1198
1199static ssize_t
1200il_dbgfs_missed_beacon_write(struct file *file, const char __user *user_buf,
1201                             size_t count, loff_t *ppos)
1202{
1203        struct il_priv *il = file->private_data;
1204        char buf[8];
1205        int buf_size;
1206        int missed;
1207
1208        memset(buf, 0, sizeof(buf));
1209        buf_size = min(count, sizeof(buf) - 1);
1210        if (copy_from_user(buf, user_buf, buf_size))
1211                return -EFAULT;
1212        if (sscanf(buf, "%d", &missed) != 1)
1213                return -EINVAL;
1214
1215        if (missed < IL_MISSED_BEACON_THRESHOLD_MIN ||
1216            missed > IL_MISSED_BEACON_THRESHOLD_MAX)
1217                il->missed_beacon_threshold = IL_MISSED_BEACON_THRESHOLD_DEF;
1218        else
1219                il->missed_beacon_threshold = missed;
1220
1221        return count;
1222}
1223
1224static ssize_t
1225il_dbgfs_force_reset_read(struct file *file, char __user *user_buf,
1226                          size_t count, loff_t *ppos)
1227{
1228
1229        struct il_priv *il = file->private_data;
1230        int pos = 0;
1231        char buf[300];
1232        const size_t bufsz = sizeof(buf);
1233        struct il_force_reset *force_reset;
1234
1235        force_reset = &il->force_reset;
1236
1237        pos +=
1238            scnprintf(buf + pos, bufsz - pos, "\tnumber of reset request: %d\n",
1239                      force_reset->reset_request_count);
1240        pos +=
1241            scnprintf(buf + pos, bufsz - pos,
1242                      "\tnumber of reset request success: %d\n",
1243                      force_reset->reset_success_count);
1244        pos +=
1245            scnprintf(buf + pos, bufsz - pos,
1246                      "\tnumber of reset request reject: %d\n",
1247                      force_reset->reset_reject_count);
1248        pos +=
1249            scnprintf(buf + pos, bufsz - pos, "\treset duration: %lu\n",
1250                      force_reset->reset_duration);
1251
1252        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1253}
1254
1255static ssize_t
1256il_dbgfs_force_reset_write(struct file *file, const char __user *user_buf,
1257                           size_t count, loff_t *ppos)
1258{
1259
1260        int ret;
1261        struct il_priv *il = file->private_data;
1262
1263        ret = il_force_reset(il, true);
1264
1265        return ret ? ret : count;
1266}
1267
1268static ssize_t
1269il_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf,
1270                          size_t count, loff_t *ppos)
1271{
1272
1273        struct il_priv *il = file->private_data;
1274        char buf[8];
1275        int buf_size;
1276        int timeout;
1277
1278        memset(buf, 0, sizeof(buf));
1279        buf_size = min(count, sizeof(buf) - 1);
1280        if (copy_from_user(buf, user_buf, buf_size))
1281                return -EFAULT;
1282        if (sscanf(buf, "%d", &timeout) != 1)
1283                return -EINVAL;
1284        if (timeout < 0 || timeout > IL_MAX_WD_TIMEOUT)
1285                timeout = IL_DEF_WD_TIMEOUT;
1286
1287        il->cfg->wd_timeout = timeout;
1288        il_setup_watchdog(il);
1289        return count;
1290}
1291
1292DEBUGFS_READ_FILE_OPS(rx_stats);
1293DEBUGFS_READ_FILE_OPS(tx_stats);
1294DEBUGFS_READ_FILE_OPS(rx_queue);
1295DEBUGFS_READ_FILE_OPS(tx_queue);
1296DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
1297DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
1298DEBUGFS_READ_FILE_OPS(ucode_general_stats);
1299DEBUGFS_READ_FILE_OPS(sensitivity);
1300DEBUGFS_READ_FILE_OPS(chain_noise);
1301DEBUGFS_READ_FILE_OPS(power_save_status);
1302DEBUGFS_WRITE_FILE_OPS(clear_ucode_stats);
1303DEBUGFS_WRITE_FILE_OPS(clear_traffic_stats);
1304DEBUGFS_READ_FILE_OPS(fh_reg);
1305DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
1306DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
1307DEBUGFS_READ_FILE_OPS(rxon_flags);
1308DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
1309DEBUGFS_WRITE_FILE_OPS(wd_timeout);
1310
1311/*
1312 * Create the debugfs files and directories
1313 *
1314 */
1315void
1316il_dbgfs_register(struct il_priv *il, const char *name)
1317{
1318        struct dentry *phyd = il->hw->wiphy->debugfsdir;
1319        struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
1320
1321        dir_drv = debugfs_create_dir(name, phyd);
1322        il->debugfs_dir = dir_drv;
1323
1324        dir_data = debugfs_create_dir("data", dir_drv);
1325        dir_rf = debugfs_create_dir("rf", dir_drv);
1326        dir_debug = debugfs_create_dir("debug", dir_drv);
1327
1328        DEBUGFS_ADD_FILE(nvm, dir_data, 0400);
1329        DEBUGFS_ADD_FILE(sram, dir_data, 0600);
1330        DEBUGFS_ADD_FILE(stations, dir_data, 0400);
1331        DEBUGFS_ADD_FILE(channels, dir_data, 0400);
1332        DEBUGFS_ADD_FILE(status, dir_data, 0400);
1333        DEBUGFS_ADD_FILE(interrupt, dir_data, 0600);
1334        DEBUGFS_ADD_FILE(qos, dir_data, 0400);
1335        DEBUGFS_ADD_FILE(disable_ht40, dir_data, 0600);
1336        DEBUGFS_ADD_FILE(rx_stats, dir_debug, 0400);
1337        DEBUGFS_ADD_FILE(tx_stats, dir_debug, 0400);
1338        DEBUGFS_ADD_FILE(rx_queue, dir_debug, 0400);
1339        DEBUGFS_ADD_FILE(tx_queue, dir_debug, 0400);
1340        DEBUGFS_ADD_FILE(power_save_status, dir_debug, 0400);
1341        DEBUGFS_ADD_FILE(clear_ucode_stats, dir_debug, 0200);
1342        DEBUGFS_ADD_FILE(clear_traffic_stats, dir_debug, 0200);
1343        DEBUGFS_ADD_FILE(fh_reg, dir_debug, 0400);
1344        DEBUGFS_ADD_FILE(missed_beacon, dir_debug, 0200);
1345        DEBUGFS_ADD_FILE(force_reset, dir_debug, 0600);
1346        DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, 0400);
1347        DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, 0400);
1348        DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, 0400);
1349
1350        if (il->cfg->sensitivity_calib_by_driver)
1351                DEBUGFS_ADD_FILE(sensitivity, dir_debug, 0400);
1352        if (il->cfg->chain_noise_calib_by_driver)
1353                DEBUGFS_ADD_FILE(chain_noise, dir_debug, 0400);
1354        DEBUGFS_ADD_FILE(rxon_flags, dir_debug, 0200);
1355        DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, 0200);
1356        DEBUGFS_ADD_FILE(wd_timeout, dir_debug, 0200);
1357        if (il->cfg->sensitivity_calib_by_driver)
1358                DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
1359                                 &il->disable_sens_cal);
1360        if (il->cfg->chain_noise_calib_by_driver)
1361                DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
1362                                 &il->disable_chain_noise_cal);
1363        DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, &il->disable_tx_power_cal);
1364}
1365EXPORT_SYMBOL(il_dbgfs_register);
1366
1367/*
1368 * Remove the debugfs files and directories
1369 */
1370void
1371il_dbgfs_unregister(struct il_priv *il)
1372{
1373        if (!il->debugfs_dir)
1374                return;
1375
1376        debugfs_remove_recursive(il->debugfs_dir);
1377        il->debugfs_dir = NULL;
1378}
1379EXPORT_SYMBOL(il_dbgfs_unregister);
1380