linux/drivers/net/wireless/ath/wil6210/debugfs.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/debugfs.h>
  19#include <linux/seq_file.h>
  20#include <linux/pci.h>
  21#include <linux/rtnetlink.h>
  22#include <linux/power_supply.h>
  23#include "wil6210.h"
  24#include "wmi.h"
  25#include "txrx.h"
  26#include "pmc.h"
  27
  28/* Nasty hack. Better have per device instances */
  29static u32 mem_addr;
  30static u32 dbg_txdesc_index;
  31static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
  32
  33enum dbg_off_type {
  34        doff_u32 = 0,
  35        doff_x32 = 1,
  36        doff_ulong = 2,
  37        doff_io32 = 3,
  38        doff_u8 = 4
  39};
  40
  41/* offset to "wil" */
  42struct dbg_off {
  43        const char *name;
  44        umode_t mode;
  45        ulong off;
  46        enum dbg_off_type type;
  47};
  48
  49static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
  50                            const char *name, struct vring *vring,
  51                            char _s, char _h)
  52{
  53        void __iomem *x = wmi_addr(wil, vring->hwtail);
  54        u32 v;
  55
  56        seq_printf(s, "VRING %s = {\n", name);
  57        seq_printf(s, "  pa     = %pad\n", &vring->pa);
  58        seq_printf(s, "  va     = 0x%p\n", vring->va);
  59        seq_printf(s, "  size   = %d\n", vring->size);
  60        seq_printf(s, "  swtail = %d\n", vring->swtail);
  61        seq_printf(s, "  swhead = %d\n", vring->swhead);
  62        seq_printf(s, "  hwtail = [0x%08x] -> ", vring->hwtail);
  63        if (x) {
  64                v = readl(x);
  65                seq_printf(s, "0x%08x = %d\n", v, v);
  66        } else {
  67                seq_puts(s, "???\n");
  68        }
  69
  70        if (vring->va && (vring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
  71                uint i;
  72
  73                for (i = 0; i < vring->size; i++) {
  74                        volatile struct vring_tx_desc *d = &vring->va[i].tx;
  75
  76                        if ((i % 128) == 0 && (i != 0))
  77                                seq_puts(s, "\n");
  78                        seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
  79                                        _s : (vring->ctx[i].skb ? _h : 'h'));
  80                }
  81                seq_puts(s, "\n");
  82        }
  83        seq_puts(s, "}\n");
  84}
  85
  86static int wil_vring_debugfs_show(struct seq_file *s, void *data)
  87{
  88        uint i;
  89        struct wil6210_priv *wil = s->private;
  90
  91        wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
  92
  93        for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
  94                struct vring *vring = &wil->vring_tx[i];
  95                struct vring_tx_data *txdata = &wil->vring_tx_data[i];
  96
  97                if (vring->va) {
  98                        int cid = wil->vring2cid_tid[i][0];
  99                        int tid = wil->vring2cid_tid[i][1];
 100                        u32 swhead = vring->swhead;
 101                        u32 swtail = vring->swtail;
 102                        int used = (vring->size + swhead - swtail)
 103                                   % vring->size;
 104                        int avail = vring->size - used - 1;
 105                        char name[10];
 106                        char sidle[10];
 107                        /* performance monitoring */
 108                        cycles_t now = get_cycles();
 109                        uint64_t idle = txdata->idle * 100;
 110                        uint64_t total = now - txdata->begin;
 111
 112                        if (total != 0) {
 113                                do_div(idle, total);
 114                                snprintf(sidle, sizeof(sidle), "%3d%%",
 115                                         (int)idle);
 116                        } else {
 117                                snprintf(sidle, sizeof(sidle), "N/A");
 118                        }
 119                        txdata->begin = now;
 120                        txdata->idle = 0ULL;
 121
 122                        snprintf(name, sizeof(name), "tx_%2d", i);
 123
 124                        if (cid < WIL6210_MAX_CID)
 125                                seq_printf(s,
 126                                           "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
 127                                           wil->sta[cid].addr, cid, tid,
 128                                           txdata->dot1x_open ? "+" : "-",
 129                                           txdata->agg_wsize,
 130                                           txdata->agg_timeout,
 131                                           txdata->agg_amsdu ? "+" : "-",
 132                                           used, avail, sidle);
 133                        else
 134                                seq_printf(s,
 135                                           "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
 136                                           txdata->dot1x_open ? "+" : "-",
 137                                           used, avail, sidle);
 138
 139                        wil_print_vring(s, wil, name, vring, '_', 'H');
 140                }
 141        }
 142
 143        return 0;
 144}
 145
 146static int wil_vring_seq_open(struct inode *inode, struct file *file)
 147{
 148        return single_open(file, wil_vring_debugfs_show, inode->i_private);
 149}
 150
 151static const struct file_operations fops_vring = {
 152        .open           = wil_vring_seq_open,
 153        .release        = single_release,
 154        .read           = seq_read,
 155        .llseek         = seq_lseek,
 156};
 157
 158static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
 159                            const char *prefix)
 160{
 161        seq_hex_dump(s, prefix, DUMP_PREFIX_NONE, 16, 1, p, len, false);
 162}
 163
 164static void wil_print_ring(struct seq_file *s, const char *prefix,
 165                           void __iomem *off)
 166{
 167        struct wil6210_priv *wil = s->private;
 168        struct wil6210_mbox_ring r;
 169        int rsize;
 170        uint i;
 171
 172        wil_halp_vote(wil);
 173
 174        wil_memcpy_fromio_32(&r, off, sizeof(r));
 175        wil_mbox_ring_le2cpus(&r);
 176        /*
 177         * we just read memory block from NIC. This memory may be
 178         * garbage. Check validity before using it.
 179         */
 180        rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
 181
 182        seq_printf(s, "ring %s = {\n", prefix);
 183        seq_printf(s, "  base = 0x%08x\n", r.base);
 184        seq_printf(s, "  size = 0x%04x bytes -> %d entries\n", r.size, rsize);
 185        seq_printf(s, "  tail = 0x%08x\n", r.tail);
 186        seq_printf(s, "  head = 0x%08x\n", r.head);
 187        seq_printf(s, "  entry size = %d\n", r.entry_size);
 188
 189        if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
 190                seq_printf(s, "  ??? size is not multiple of %zd, garbage?\n",
 191                           sizeof(struct wil6210_mbox_ring_desc));
 192                goto out;
 193        }
 194
 195        if (!wmi_addr(wil, r.base) ||
 196            !wmi_addr(wil, r.tail) ||
 197            !wmi_addr(wil, r.head)) {
 198                seq_puts(s, "  ??? pointers are garbage?\n");
 199                goto out;
 200        }
 201
 202        for (i = 0; i < rsize; i++) {
 203                struct wil6210_mbox_ring_desc d;
 204                struct wil6210_mbox_hdr hdr;
 205                size_t delta = i * sizeof(d);
 206                void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
 207
 208                wil_memcpy_fromio_32(&d, x, sizeof(d));
 209
 210                seq_printf(s, "  [%2x] %s %s%s 0x%08x", i,
 211                           d.sync ? "F" : "E",
 212                           (r.tail - r.base == delta) ? "t" : " ",
 213                           (r.head - r.base == delta) ? "h" : " ",
 214                           le32_to_cpu(d.addr));
 215                if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
 216                        u16 len = le16_to_cpu(hdr.len);
 217
 218                        seq_printf(s, " -> %04x %04x %04x %02x\n",
 219                                   le16_to_cpu(hdr.seq), len,
 220                                   le16_to_cpu(hdr.type), hdr.flags);
 221                        if (len <= MAX_MBOXITEM_SIZE) {
 222                                unsigned char databuf[MAX_MBOXITEM_SIZE];
 223                                void __iomem *src = wmi_buffer(wil, d.addr) +
 224                                        sizeof(struct wil6210_mbox_hdr);
 225                                /*
 226                                 * No need to check @src for validity -
 227                                 * we already validated @d.addr while
 228                                 * reading header
 229                                 */
 230                                wil_memcpy_fromio_32(databuf, src, len);
 231                                wil_seq_hexdump(s, databuf, len, "      : ");
 232                        }
 233                } else {
 234                        seq_puts(s, "\n");
 235                }
 236        }
 237 out:
 238        seq_puts(s, "}\n");
 239        wil_halp_unvote(wil);
 240}
 241
 242static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
 243{
 244        struct wil6210_priv *wil = s->private;
 245        int ret;
 246
 247        ret = wil_pm_runtime_get(wil);
 248        if (ret < 0)
 249                return ret;
 250
 251        wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
 252                       offsetof(struct wil6210_mbox_ctl, tx));
 253        wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
 254                       offsetof(struct wil6210_mbox_ctl, rx));
 255
 256        wil_pm_runtime_put(wil);
 257
 258        return 0;
 259}
 260
 261static int wil_mbox_seq_open(struct inode *inode, struct file *file)
 262{
 263        return single_open(file, wil_mbox_debugfs_show, inode->i_private);
 264}
 265
 266static const struct file_operations fops_mbox = {
 267        .open           = wil_mbox_seq_open,
 268        .release        = single_release,
 269        .read           = seq_read,
 270        .llseek         = seq_lseek,
 271};
 272
 273static int wil_debugfs_iomem_x32_set(void *data, u64 val)
 274{
 275        struct wil_debugfs_iomem_data *d = (struct
 276                                            wil_debugfs_iomem_data *)data;
 277        struct wil6210_priv *wil = d->wil;
 278        int ret;
 279
 280        ret = wil_pm_runtime_get(wil);
 281        if (ret < 0)
 282                return ret;
 283
 284        writel(val, (void __iomem *)d->offset);
 285        wmb(); /* make sure write propagated to HW */
 286
 287        wil_pm_runtime_put(wil);
 288
 289        return 0;
 290}
 291
 292static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
 293{
 294        struct wil_debugfs_iomem_data *d = (struct
 295                                            wil_debugfs_iomem_data *)data;
 296        struct wil6210_priv *wil = d->wil;
 297        int ret;
 298
 299        ret = wil_pm_runtime_get(wil);
 300        if (ret < 0)
 301                return ret;
 302
 303        *val = readl((void __iomem *)d->offset);
 304
 305        wil_pm_runtime_put(wil);
 306
 307        return 0;
 308}
 309
 310DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
 311                        wil_debugfs_iomem_x32_set, "0x%08llx\n");
 312
 313static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
 314                                                   umode_t mode,
 315                                                   struct dentry *parent,
 316                                                   void *value,
 317                                                   struct wil6210_priv *wil)
 318{
 319        struct dentry *file;
 320        struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[
 321                                              wil->dbg_data.iomem_data_count];
 322
 323        data->wil = wil;
 324        data->offset = value;
 325
 326        file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32);
 327        if (!IS_ERR_OR_NULL(file))
 328                wil->dbg_data.iomem_data_count++;
 329
 330        return file;
 331}
 332
 333static int wil_debugfs_ulong_set(void *data, u64 val)
 334{
 335        *(ulong *)data = val;
 336        return 0;
 337}
 338
 339static int wil_debugfs_ulong_get(void *data, u64 *val)
 340{
 341        *val = *(ulong *)data;
 342        return 0;
 343}
 344
 345DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
 346                        wil_debugfs_ulong_set, "0x%llx\n");
 347
 348static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
 349                                               struct dentry *parent,
 350                                               ulong *value)
 351{
 352        return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
 353}
 354
 355/**
 356 * wil6210_debugfs_init_offset - create set of debugfs files
 357 * @wil - driver's context, used for printing
 358 * @dbg - directory on the debugfs, where files will be created
 359 * @base - base address used in address calculation
 360 * @tbl - table with file descriptions. Should be terminated with empty element.
 361 *
 362 * Creates files accordingly to the @tbl.
 363 */
 364static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
 365                                        struct dentry *dbg, void *base,
 366                                        const struct dbg_off * const tbl)
 367{
 368        int i;
 369
 370        for (i = 0; tbl[i].name; i++) {
 371                struct dentry *f;
 372
 373                switch (tbl[i].type) {
 374                case doff_u32:
 375                        f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
 376                                               base + tbl[i].off);
 377                        break;
 378                case doff_x32:
 379                        f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
 380                                               base + tbl[i].off);
 381                        break;
 382                case doff_ulong:
 383                        f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
 384                                                     dbg, base + tbl[i].off);
 385                        break;
 386                case doff_io32:
 387                        f = wil_debugfs_create_iomem_x32(tbl[i].name,
 388                                                         tbl[i].mode, dbg,
 389                                                         base + tbl[i].off,
 390                                                         wil);
 391                        break;
 392                case doff_u8:
 393                        f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
 394                                              base + tbl[i].off);
 395                        break;
 396                default:
 397                        f = ERR_PTR(-EINVAL);
 398                }
 399                if (IS_ERR_OR_NULL(f))
 400                        wil_err(wil, "Create file \"%s\": err %ld\n",
 401                                tbl[i].name, PTR_ERR(f));
 402        }
 403}
 404
 405static const struct dbg_off isr_off[] = {
 406        {"ICC", 0644, offsetof(struct RGF_ICR, ICC), doff_io32},
 407        {"ICR", 0644, offsetof(struct RGF_ICR, ICR), doff_io32},
 408        {"ICM", 0644, offsetof(struct RGF_ICR, ICM), doff_io32},
 409        {"ICS", 0244, offsetof(struct RGF_ICR, ICS), doff_io32},
 410        {"IMV", 0644, offsetof(struct RGF_ICR, IMV), doff_io32},
 411        {"IMS", 0244, offsetof(struct RGF_ICR, IMS), doff_io32},
 412        {"IMC", 0244, offsetof(struct RGF_ICR, IMC), doff_io32},
 413        {},
 414};
 415
 416static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
 417                                      const char *name,
 418                                      struct dentry *parent, u32 off)
 419{
 420        struct dentry *d = debugfs_create_dir(name, parent);
 421
 422        if (IS_ERR_OR_NULL(d))
 423                return -ENODEV;
 424
 425        wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
 426                                    isr_off);
 427
 428        return 0;
 429}
 430
 431static const struct dbg_off pseudo_isr_off[] = {
 432        {"CAUSE",   0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
 433        {"MASK_SW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
 434        {"MASK_FW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
 435        {},
 436};
 437
 438static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
 439                                             struct dentry *parent)
 440{
 441        struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
 442
 443        if (IS_ERR_OR_NULL(d))
 444                return -ENODEV;
 445
 446        wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
 447                                    pseudo_isr_off);
 448
 449        return 0;
 450}
 451
 452static const struct dbg_off lgc_itr_cnt_off[] = {
 453        {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
 454        {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
 455        {"CTL",  0644, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
 456        {},
 457};
 458
 459static const struct dbg_off tx_itr_cnt_off[] = {
 460        {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
 461         doff_io32},
 462        {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
 463         doff_io32},
 464        {"CTL",  0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
 465         doff_io32},
 466        {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
 467         doff_io32},
 468        {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
 469         doff_io32},
 470        {"IDL_CTL",  0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
 471         doff_io32},
 472        {},
 473};
 474
 475static const struct dbg_off rx_itr_cnt_off[] = {
 476        {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
 477         doff_io32},
 478        {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
 479         doff_io32},
 480        {"CTL",  0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
 481         doff_io32},
 482        {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
 483         doff_io32},
 484        {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
 485         doff_io32},
 486        {"IDL_CTL",  0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
 487         doff_io32},
 488        {},
 489};
 490
 491static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
 492                                          struct dentry *parent)
 493{
 494        struct dentry *d, *dtx, *drx;
 495
 496        d = debugfs_create_dir("ITR_CNT", parent);
 497        if (IS_ERR_OR_NULL(d))
 498                return -ENODEV;
 499
 500        dtx = debugfs_create_dir("TX", d);
 501        drx = debugfs_create_dir("RX", d);
 502        if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
 503                return -ENODEV;
 504
 505        wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
 506                                    lgc_itr_cnt_off);
 507
 508        wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
 509                                    tx_itr_cnt_off);
 510
 511        wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
 512                                    rx_itr_cnt_off);
 513        return 0;
 514}
 515
 516static int wil_memread_debugfs_show(struct seq_file *s, void *data)
 517{
 518        struct wil6210_priv *wil = s->private;
 519        void __iomem *a;
 520        int ret;
 521
 522        ret = wil_pm_runtime_get(wil);
 523        if (ret < 0)
 524                return ret;
 525
 526        a = wmi_buffer(wil, cpu_to_le32(mem_addr));
 527
 528        if (a)
 529                seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a));
 530        else
 531                seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
 532
 533        wil_pm_runtime_put(wil);
 534
 535        return 0;
 536}
 537
 538static int wil_memread_seq_open(struct inode *inode, struct file *file)
 539{
 540        return single_open(file, wil_memread_debugfs_show, inode->i_private);
 541}
 542
 543static const struct file_operations fops_memread = {
 544        .open           = wil_memread_seq_open,
 545        .release        = single_release,
 546        .read           = seq_read,
 547        .llseek         = seq_lseek,
 548};
 549
 550static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
 551                                    size_t count, loff_t *ppos)
 552{
 553        enum { max_count = 4096 };
 554        struct wil_blob_wrapper *wil_blob = file->private_data;
 555        struct wil6210_priv *wil = wil_blob->wil;
 556        loff_t pos = *ppos;
 557        size_t available = wil_blob->blob.size;
 558        void *buf;
 559        size_t ret;
 560        int rc;
 561
 562        if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
 563            test_bit(wil_status_suspended, wil_blob->wil->status))
 564                return 0;
 565
 566        if (pos < 0)
 567                return -EINVAL;
 568
 569        if (pos >= available || !count)
 570                return 0;
 571
 572        if (count > available - pos)
 573                count = available - pos;
 574        if (count > max_count)
 575                count = max_count;
 576
 577        buf = kmalloc(count, GFP_KERNEL);
 578        if (!buf)
 579                return -ENOMEM;
 580
 581        rc = wil_pm_runtime_get(wil);
 582        if (rc < 0) {
 583                kfree(buf);
 584                return rc;
 585        }
 586
 587        wil_memcpy_fromio_32(buf, (const void __iomem *)
 588                             wil_blob->blob.data + pos, count);
 589
 590        ret = copy_to_user(user_buf, buf, count);
 591
 592        wil_pm_runtime_put(wil);
 593
 594        kfree(buf);
 595        if (ret == count)
 596                return -EFAULT;
 597
 598        count -= ret;
 599        *ppos = pos + count;
 600
 601        return count;
 602}
 603
 604static const struct file_operations fops_ioblob = {
 605        .read =         wil_read_file_ioblob,
 606        .open =         simple_open,
 607        .llseek =       default_llseek,
 608};
 609
 610static
 611struct dentry *wil_debugfs_create_ioblob(const char *name,
 612                                         umode_t mode,
 613                                         struct dentry *parent,
 614                                         struct wil_blob_wrapper *wil_blob)
 615{
 616        return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob);
 617}
 618
 619/*---reset---*/
 620static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
 621                                    size_t len, loff_t *ppos)
 622{
 623        struct wil6210_priv *wil = file->private_data;
 624        struct net_device *ndev = wil_to_ndev(wil);
 625
 626        /**
 627         * BUG:
 628         * this code does NOT sync device state with the rest of system
 629         * use with care, debug only!!!
 630         */
 631        rtnl_lock();
 632        dev_close(ndev);
 633        ndev->flags &= ~IFF_UP;
 634        rtnl_unlock();
 635        wil_reset(wil, true);
 636
 637        return len;
 638}
 639
 640static const struct file_operations fops_reset = {
 641        .write = wil_write_file_reset,
 642        .open  = simple_open,
 643};
 644
 645/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
 646static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
 647                                   size_t len, loff_t *ppos)
 648{
 649        struct wil6210_priv *wil = file->private_data;
 650        int rc;
 651        long channel;
 652        bool on;
 653
 654        char *kbuf = memdup_user_nul(buf, len);
 655
 656        if (IS_ERR(kbuf))
 657                return PTR_ERR(kbuf);
 658        rc = kstrtol(kbuf, 0, &channel);
 659        kfree(kbuf);
 660        if (rc)
 661                return rc;
 662
 663        if ((channel < 0) || (channel > 4)) {
 664                wil_err(wil, "Invalid channel %ld\n", channel);
 665                return -EINVAL;
 666        }
 667        on = !!channel;
 668
 669        if (on) {
 670                rc = wmi_set_channel(wil, (int)channel);
 671                if (rc)
 672                        return rc;
 673        }
 674
 675        rc = wmi_rxon(wil, on);
 676        if (rc)
 677                return rc;
 678
 679        return len;
 680}
 681
 682static const struct file_operations fops_rxon = {
 683        .write = wil_write_file_rxon,
 684        .open  = simple_open,
 685};
 686
 687/* block ack control, write:
 688 * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
 689 * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
 690 * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
 691 */
 692static ssize_t wil_write_back(struct file *file, const char __user *buf,
 693                              size_t len, loff_t *ppos)
 694{
 695        struct wil6210_priv *wil = file->private_data;
 696        int rc;
 697        char *kbuf = kmalloc(len + 1, GFP_KERNEL);
 698        char cmd[9];
 699        int p1, p2, p3;
 700
 701        if (!kbuf)
 702                return -ENOMEM;
 703
 704        rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
 705        if (rc != len) {
 706                kfree(kbuf);
 707                return rc >= 0 ? -EIO : rc;
 708        }
 709
 710        kbuf[len] = '\0';
 711        rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
 712        kfree(kbuf);
 713
 714        if (rc < 0)
 715                return rc;
 716        if (rc < 2)
 717                return -EINVAL;
 718
 719        if (0 == strcmp(cmd, "add")) {
 720                if (rc < 3) {
 721                        wil_err(wil, "BACK: add require at least 2 params\n");
 722                        return -EINVAL;
 723                }
 724                if (rc < 4)
 725                        p3 = 0;
 726                wmi_addba(wil, p1, p2, p3);
 727        } else if (0 == strcmp(cmd, "del_tx")) {
 728                if (rc < 3)
 729                        p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
 730                wmi_delba_tx(wil, p1, p2);
 731        } else if (0 == strcmp(cmd, "del_rx")) {
 732                if (rc < 3) {
 733                        wil_err(wil,
 734                                "BACK: del_rx require at least 2 params\n");
 735                        return -EINVAL;
 736                }
 737                if (rc < 4)
 738                        p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
 739                wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
 740        } else {
 741                wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
 742                return -EINVAL;
 743        }
 744
 745        return len;
 746}
 747
 748static ssize_t wil_read_back(struct file *file, char __user *user_buf,
 749                             size_t count, loff_t *ppos)
 750{
 751        static const char text[] = "block ack control, write:\n"
 752        " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
 753        "If missing, <timeout> defaults to 0\n"
 754        " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
 755        " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
 756        "If missing, <reason> set to \"STA_LEAVING\" (36)\n";
 757
 758        return simple_read_from_buffer(user_buf, count, ppos, text,
 759                                       sizeof(text));
 760}
 761
 762static const struct file_operations fops_back = {
 763        .read = wil_read_back,
 764        .write = wil_write_back,
 765        .open  = simple_open,
 766};
 767
 768/* pmc control, write:
 769 * - "alloc <num descriptors> <descriptor_size>" to allocate PMC
 770 * - "free" to release memory allocated for PMC
 771 */
 772static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf,
 773                                size_t len, loff_t *ppos)
 774{
 775        struct wil6210_priv *wil = file->private_data;
 776        int rc;
 777        char *kbuf = kmalloc(len + 1, GFP_KERNEL);
 778        char cmd[9];
 779        int num_descs, desc_size;
 780
 781        if (!kbuf)
 782                return -ENOMEM;
 783
 784        rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
 785        if (rc != len) {
 786                kfree(kbuf);
 787                return rc >= 0 ? -EIO : rc;
 788        }
 789
 790        kbuf[len] = '\0';
 791        rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size);
 792        kfree(kbuf);
 793
 794        if (rc < 0)
 795                return rc;
 796
 797        if (rc < 1) {
 798                wil_err(wil, "pmccfg: no params given\n");
 799                return -EINVAL;
 800        }
 801
 802        if (0 == strcmp(cmd, "alloc")) {
 803                if (rc != 3) {
 804                        wil_err(wil, "pmccfg: alloc requires 2 params\n");
 805                        return -EINVAL;
 806                }
 807                wil_pmc_alloc(wil, num_descs, desc_size);
 808        } else if (0 == strcmp(cmd, "free")) {
 809                if (rc != 1) {
 810                        wil_err(wil, "pmccfg: free does not have any params\n");
 811                        return -EINVAL;
 812                }
 813                wil_pmc_free(wil, true);
 814        } else {
 815                wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd);
 816                return -EINVAL;
 817        }
 818
 819        return len;
 820}
 821
 822static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf,
 823                               size_t count, loff_t *ppos)
 824{
 825        struct wil6210_priv *wil = file->private_data;
 826        char text[256];
 827        char help[] = "pmc control, write:\n"
 828        " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
 829        " - \"free\" to free memory allocated for pmc\n";
 830
 831        sprintf(text, "Last command status: %d\n\n%s",
 832                wil_pmc_last_cmd_status(wil),
 833                help);
 834
 835        return simple_read_from_buffer(user_buf, count, ppos, text,
 836                                       strlen(text) + 1);
 837}
 838
 839static const struct file_operations fops_pmccfg = {
 840        .read = wil_read_pmccfg,
 841        .write = wil_write_pmccfg,
 842        .open  = simple_open,
 843};
 844
 845static const struct file_operations fops_pmcdata = {
 846        .open           = simple_open,
 847        .read           = wil_pmc_read,
 848        .llseek         = wil_pmc_llseek,
 849};
 850
 851/*---tx_mgmt---*/
 852/* Write mgmt frame to this file to send it */
 853static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
 854                                     size_t len, loff_t *ppos)
 855{
 856        struct wil6210_priv *wil = file->private_data;
 857        struct wiphy *wiphy = wil_to_wiphy(wil);
 858        struct wireless_dev *wdev = wil_to_wdev(wil);
 859        struct cfg80211_mgmt_tx_params params;
 860        int rc;
 861        void *frame;
 862
 863        if (!len)
 864                return -EINVAL;
 865
 866        frame = memdup_user(buf, len);
 867        if (IS_ERR(frame))
 868                return PTR_ERR(frame);
 869
 870        params.buf = frame;
 871        params.len = len;
 872
 873        rc = wil_cfg80211_mgmt_tx(wiphy, wdev, &params, NULL);
 874
 875        kfree(frame);
 876        wil_info(wil, "-> %d\n", rc);
 877
 878        return len;
 879}
 880
 881static const struct file_operations fops_txmgmt = {
 882        .write = wil_write_file_txmgmt,
 883        .open  = simple_open,
 884};
 885
 886/* Write WMI command (w/o mbox header) to this file to send it
 887 * WMI starts from wil6210_mbox_hdr_wmi header
 888 */
 889static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
 890                                  size_t len, loff_t *ppos)
 891{
 892        struct wil6210_priv *wil = file->private_data;
 893        struct wmi_cmd_hdr *wmi;
 894        void *cmd;
 895        int cmdlen = len - sizeof(struct wmi_cmd_hdr);
 896        u16 cmdid;
 897        int rc, rc1;
 898
 899        if (cmdlen < 0)
 900                return -EINVAL;
 901
 902        wmi = kmalloc(len, GFP_KERNEL);
 903        if (!wmi)
 904                return -ENOMEM;
 905
 906        rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
 907        if (rc < 0) {
 908                kfree(wmi);
 909                return rc;
 910        }
 911
 912        cmd = (cmdlen > 0) ? &wmi[1] : NULL;
 913        cmdid = le16_to_cpu(wmi->command_id);
 914
 915        rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
 916        kfree(wmi);
 917
 918        wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
 919
 920        return rc;
 921}
 922
 923static const struct file_operations fops_wmi = {
 924        .write = wil_write_file_wmi,
 925        .open  = simple_open,
 926};
 927
 928static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
 929{
 930        int i = 0;
 931        int len = skb_headlen(skb);
 932        void *p = skb->data;
 933        int nr_frags = skb_shinfo(skb)->nr_frags;
 934
 935        seq_printf(s, "    len = %d\n", len);
 936        wil_seq_hexdump(s, p, len, "      : ");
 937
 938        if (nr_frags) {
 939                seq_printf(s, "    nr_frags = %d\n", nr_frags);
 940                for (i = 0; i < nr_frags; i++) {
 941                        const struct skb_frag_struct *frag =
 942                                        &skb_shinfo(skb)->frags[i];
 943
 944                        len = skb_frag_size(frag);
 945                        p = skb_frag_address_safe(frag);
 946                        seq_printf(s, "    [%2d] : len = %d\n", i, len);
 947                        wil_seq_hexdump(s, p, len, "      : ");
 948                }
 949        }
 950}
 951
 952/*---------Tx/Rx descriptor------------*/
 953static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
 954{
 955        struct wil6210_priv *wil = s->private;
 956        struct vring *vring;
 957        bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
 958
 959        vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
 960
 961        if (!vring->va) {
 962                if (tx)
 963                        seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index);
 964                else
 965                        seq_puts(s, "No Rx VRING\n");
 966                return 0;
 967        }
 968
 969        if (dbg_txdesc_index < vring->size) {
 970                /* use struct vring_tx_desc for Rx as well,
 971                 * only field used, .dma.length, is the same
 972                 */
 973                volatile struct vring_tx_desc *d =
 974                                &vring->va[dbg_txdesc_index].tx;
 975                volatile u32 *u = (volatile u32 *)d;
 976                struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
 977
 978                if (tx)
 979                        seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index,
 980                                   dbg_txdesc_index);
 981                else
 982                        seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);
 983                seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
 984                           u[0], u[1], u[2], u[3]);
 985                seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
 986                           u[4], u[5], u[6], u[7]);
 987                seq_printf(s, "  SKB = 0x%p\n", skb);
 988
 989                if (skb) {
 990                        skb_get(skb);
 991                        wil_seq_print_skb(s, skb);
 992                        kfree_skb(skb);
 993                }
 994                seq_puts(s, "}\n");
 995        } else {
 996                if (tx)
 997                        seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
 998                                   dbg_vring_index, dbg_txdesc_index,
 999                                   vring->size);
1000                else
1001                        seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
1002                                   dbg_txdesc_index, vring->size);
1003        }
1004
1005        return 0;
1006}
1007
1008static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
1009{
1010        return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
1011}
1012
1013static const struct file_operations fops_txdesc = {
1014        .open           = wil_txdesc_seq_open,
1015        .release        = single_release,
1016        .read           = seq_read,
1017        .llseek         = seq_lseek,
1018};
1019
1020/*---------beamforming------------*/
1021static char *wil_bfstatus_str(u32 status)
1022{
1023        switch (status) {
1024        case 0:
1025                return "Failed";
1026        case 1:
1027                return "OK";
1028        case 2:
1029                return "Retrying";
1030        default:
1031                return "??";
1032        }
1033}
1034
1035static bool is_all_zeros(void * const x_, size_t sz)
1036{
1037        /* if reply is all-0, ignore this CID */
1038        u32 *x = x_;
1039        int n;
1040
1041        for (n = 0; n < sz / sizeof(*x); n++)
1042                if (x[n])
1043                        return false;
1044
1045        return true;
1046}
1047
1048static int wil_bf_debugfs_show(struct seq_file *s, void *data)
1049{
1050        int rc;
1051        int i;
1052        struct wil6210_priv *wil = s->private;
1053        struct wmi_notify_req_cmd cmd = {
1054                .interval_usec = 0,
1055        };
1056        struct {
1057                struct wmi_cmd_hdr wmi;
1058                struct wmi_notify_req_done_event evt;
1059        } __packed reply;
1060
1061        for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1062                u32 status;
1063
1064                cmd.cid = i;
1065                rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
1066                              WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
1067                              sizeof(reply), 20);
1068                /* if reply is all-0, ignore this CID */
1069                if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
1070                        continue;
1071
1072                status = le32_to_cpu(reply.evt.status);
1073                seq_printf(s, "CID %d {\n"
1074                           "  TSF = 0x%016llx\n"
1075                           "  TxMCS = %2d TxTpt = %4d\n"
1076                           "  SQI = %4d\n"
1077                           "  RSSI = %4d\n"
1078                           "  Status = 0x%08x %s\n"
1079                           "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
1080                           "  Goodput(rx:tx) %4d:%4d\n"
1081                           "}\n",
1082                           i,
1083                           le64_to_cpu(reply.evt.tsf),
1084                           le16_to_cpu(reply.evt.bf_mcs),
1085                           le32_to_cpu(reply.evt.tx_tpt),
1086                           reply.evt.sqi,
1087                           reply.evt.rssi,
1088                           status, wil_bfstatus_str(status),
1089                           le16_to_cpu(reply.evt.my_rx_sector),
1090                           le16_to_cpu(reply.evt.my_tx_sector),
1091                           le16_to_cpu(reply.evt.other_rx_sector),
1092                           le16_to_cpu(reply.evt.other_tx_sector),
1093                           le32_to_cpu(reply.evt.rx_goodput),
1094                           le32_to_cpu(reply.evt.tx_goodput));
1095        }
1096        return 0;
1097}
1098
1099static int wil_bf_seq_open(struct inode *inode, struct file *file)
1100{
1101        return single_open(file, wil_bf_debugfs_show, inode->i_private);
1102}
1103
1104static const struct file_operations fops_bf = {
1105        .open           = wil_bf_seq_open,
1106        .release        = single_release,
1107        .read           = seq_read,
1108        .llseek         = seq_lseek,
1109};
1110
1111/*---------temp------------*/
1112static void print_temp(struct seq_file *s, const char *prefix, u32 t)
1113{
1114        switch (t) {
1115        case 0:
1116        case ~(u32)0:
1117                seq_printf(s, "%s N/A\n", prefix);
1118        break;
1119        default:
1120                seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000);
1121                break;
1122        }
1123}
1124
1125static int wil_temp_debugfs_show(struct seq_file *s, void *data)
1126{
1127        struct wil6210_priv *wil = s->private;
1128        u32 t_m, t_r;
1129        int rc = wmi_get_temperature(wil, &t_m, &t_r);
1130
1131        if (rc) {
1132                seq_puts(s, "Failed\n");
1133                return 0;
1134        }
1135
1136        print_temp(s, "T_mac   =", t_m);
1137        print_temp(s, "T_radio =", t_r);
1138
1139        return 0;
1140}
1141
1142static int wil_temp_seq_open(struct inode *inode, struct file *file)
1143{
1144        return single_open(file, wil_temp_debugfs_show, inode->i_private);
1145}
1146
1147static const struct file_operations fops_temp = {
1148        .open           = wil_temp_seq_open,
1149        .release        = single_release,
1150        .read           = seq_read,
1151        .llseek         = seq_lseek,
1152};
1153
1154/*---------freq------------*/
1155static int wil_freq_debugfs_show(struct seq_file *s, void *data)
1156{
1157        struct wil6210_priv *wil = s->private;
1158        struct wireless_dev *wdev = wil_to_wdev(wil);
1159        u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
1160
1161        seq_printf(s, "Freq = %d\n", freq);
1162
1163        return 0;
1164}
1165
1166static int wil_freq_seq_open(struct inode *inode, struct file *file)
1167{
1168        return single_open(file, wil_freq_debugfs_show, inode->i_private);
1169}
1170
1171static const struct file_operations fops_freq = {
1172        .open           = wil_freq_seq_open,
1173        .release        = single_release,
1174        .read           = seq_read,
1175        .llseek         = seq_lseek,
1176};
1177
1178/*---------link------------*/
1179static int wil_link_debugfs_show(struct seq_file *s, void *data)
1180{
1181        struct wil6210_priv *wil = s->private;
1182        struct station_info sinfo;
1183        int i, rc;
1184
1185        for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1186                struct wil_sta_info *p = &wil->sta[i];
1187                char *status = "unknown";
1188
1189                switch (p->status) {
1190                case wil_sta_unused:
1191                        status = "unused   ";
1192                        break;
1193                case wil_sta_conn_pending:
1194                        status = "pending  ";
1195                        break;
1196                case wil_sta_connected:
1197                        status = "connected";
1198                        break;
1199                }
1200                seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
1201
1202                if (p->status == wil_sta_connected) {
1203                        rc = wil_cid_fill_sinfo(wil, i, &sinfo);
1204                        if (rc)
1205                                return rc;
1206
1207                        seq_printf(s, "  Tx_mcs = %d\n", sinfo.txrate.mcs);
1208                        seq_printf(s, "  Rx_mcs = %d\n", sinfo.rxrate.mcs);
1209                        seq_printf(s, "  SQ     = %d\n", sinfo.signal);
1210                }
1211        }
1212
1213        return 0;
1214}
1215
1216static int wil_link_seq_open(struct inode *inode, struct file *file)
1217{
1218        return single_open(file, wil_link_debugfs_show, inode->i_private);
1219}
1220
1221static const struct file_operations fops_link = {
1222        .open           = wil_link_seq_open,
1223        .release        = single_release,
1224        .read           = seq_read,
1225        .llseek         = seq_lseek,
1226};
1227
1228/*---------info------------*/
1229static int wil_info_debugfs_show(struct seq_file *s, void *data)
1230{
1231        struct wil6210_priv *wil = s->private;
1232        struct net_device *ndev = wil_to_ndev(wil);
1233        int is_ac = power_supply_is_system_supplied();
1234        int rx = atomic_xchg(&wil->isr_count_rx, 0);
1235        int tx = atomic_xchg(&wil->isr_count_tx, 0);
1236        static ulong rxf_old, txf_old;
1237        ulong rxf = ndev->stats.rx_packets;
1238        ulong txf = ndev->stats.tx_packets;
1239        unsigned int i;
1240
1241        /* >0 : AC; 0 : battery; <0 : error */
1242        seq_printf(s, "AC powered : %d\n", is_ac);
1243        seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
1244        seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
1245        rxf_old = rxf;
1246        txf_old = txf;
1247
1248#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1249        " " __stringify(x) : ""
1250
1251        for (i = 0; i < ndev->num_tx_queues; i++) {
1252                struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
1253                unsigned long state = txq->state;
1254
1255                seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
1256                           CHECK_QSTATE(DRV_XOFF),
1257                           CHECK_QSTATE(STACK_XOFF),
1258                           CHECK_QSTATE(FROZEN)
1259                          );
1260        }
1261#undef CHECK_QSTATE
1262        return 0;
1263}
1264
1265static int wil_info_seq_open(struct inode *inode, struct file *file)
1266{
1267        return single_open(file, wil_info_debugfs_show, inode->i_private);
1268}
1269
1270static const struct file_operations fops_info = {
1271        .open           = wil_info_seq_open,
1272        .release        = single_release,
1273        .read           = seq_read,
1274        .llseek         = seq_lseek,
1275};
1276
1277/*---------recovery------------*/
1278/* mode = [manual|auto]
1279 * state = [idle|pending|running]
1280 */
1281static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
1282                                      size_t count, loff_t *ppos)
1283{
1284        struct wil6210_priv *wil = file->private_data;
1285        char buf[80];
1286        int n;
1287        static const char * const sstate[] = {"idle", "pending", "running"};
1288
1289        n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
1290                     no_fw_recovery ? "manual" : "auto",
1291                     sstate[wil->recovery_state]);
1292
1293        n = min_t(int, n, sizeof(buf));
1294
1295        return simple_read_from_buffer(user_buf, count, ppos,
1296                                       buf, n);
1297}
1298
1299static ssize_t wil_write_file_recovery(struct file *file,
1300                                       const char __user *buf_,
1301                                       size_t count, loff_t *ppos)
1302{
1303        struct wil6210_priv *wil = file->private_data;
1304        static const char run_command[] = "run";
1305        char buf[sizeof(run_command) + 1]; /* to detect "runx" */
1306        ssize_t rc;
1307
1308        if (wil->recovery_state != fw_recovery_pending) {
1309                wil_err(wil, "No recovery pending\n");
1310                return -EINVAL;
1311        }
1312
1313        if (*ppos != 0) {
1314                wil_err(wil, "Offset [%d]\n", (int)*ppos);
1315                return -EINVAL;
1316        }
1317
1318        if (count > sizeof(buf)) {
1319                wil_err(wil, "Input too long, len = %d\n", (int)count);
1320                return -EINVAL;
1321        }
1322
1323        rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
1324        if (rc < 0)
1325                return rc;
1326
1327        buf[rc] = '\0';
1328        if (0 == strcmp(buf, run_command))
1329                wil_set_recovery_state(wil, fw_recovery_running);
1330        else
1331                wil_err(wil, "Bad recovery command \"%s\"\n", buf);
1332
1333        return rc;
1334}
1335
1336static const struct file_operations fops_recovery = {
1337        .read = wil_read_file_recovery,
1338        .write = wil_write_file_recovery,
1339        .open  = simple_open,
1340};
1341
1342/*---------Station matrix------------*/
1343static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
1344{
1345        int i;
1346        u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
1347        unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old;
1348
1349        seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout,
1350                   r->head_seq_num);
1351        for (i = 0; i < r->buf_size; i++) {
1352                if (i == index)
1353                        seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
1354                else
1355                        seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
1356        }
1357        seq_printf(s,
1358                   "] total %llu drop %llu (dup %llu + old %llu) last 0x%03x\n",
1359                   r->total, drop_dup + drop_old, drop_dup, drop_old,
1360                   r->ssn_last_drop);
1361}
1362
1363static void wil_print_rxtid_crypto(struct seq_file *s, int tid,
1364                                   struct wil_tid_crypto_rx *c)
1365{
1366        int i;
1367
1368        for (i = 0; i < 4; i++) {
1369                struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
1370
1371                if (cc->key_set)
1372                        goto has_keys;
1373        }
1374        return;
1375
1376has_keys:
1377        if (tid < WIL_STA_TID_NUM)
1378                seq_printf(s, "  [%2d] PN", tid);
1379        else
1380                seq_puts(s, "  [GR] PN");
1381
1382        for (i = 0; i < 4; i++) {
1383                struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
1384
1385                seq_printf(s, " [%i%s]%6phN", i, cc->key_set ? "+" : "-",
1386                           cc->pn);
1387        }
1388        seq_puts(s, "\n");
1389}
1390
1391static int wil_sta_debugfs_show(struct seq_file *s, void *data)
1392__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1393{
1394        struct wil6210_priv *wil = s->private;
1395        int i, tid, mcs;
1396
1397        for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1398                struct wil_sta_info *p = &wil->sta[i];
1399                char *status = "unknown";
1400                u8 aid = 0;
1401
1402                switch (p->status) {
1403                case wil_sta_unused:
1404                        status = "unused   ";
1405                        break;
1406                case wil_sta_conn_pending:
1407                        status = "pending  ";
1408                        break;
1409                case wil_sta_connected:
1410                        status = "connected";
1411                        aid = p->aid;
1412                        break;
1413                }
1414                seq_printf(s, "[%d] %pM %s AID %d\n", i, p->addr, status, aid);
1415
1416                if (p->status == wil_sta_connected) {
1417                        spin_lock_bh(&p->tid_rx_lock);
1418                        for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
1419                                struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
1420                                struct wil_tid_crypto_rx *c =
1421                                                &p->tid_crypto_rx[tid];
1422
1423                                if (r) {
1424                                        seq_printf(s, "  [%2d] ", tid);
1425                                        wil_print_rxtid(s, r);
1426                                }
1427
1428                                wil_print_rxtid_crypto(s, tid, c);
1429                        }
1430                        wil_print_rxtid_crypto(s, WIL_STA_TID_NUM,
1431                                               &p->group_crypto_rx);
1432                        spin_unlock_bh(&p->tid_rx_lock);
1433                        seq_printf(s,
1434                                   "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n",
1435                                   p->stats.rx_non_data_frame,
1436                                   p->stats.rx_short_frame,
1437                                   p->stats.rx_large_frame,
1438                                   p->stats.rx_replay);
1439
1440                        seq_puts(s, "Rx/MCS:");
1441                        for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
1442                             mcs++)
1443                                seq_printf(s, " %lld",
1444                                           p->stats.rx_per_mcs[mcs]);
1445                        seq_puts(s, "\n");
1446                }
1447        }
1448
1449        return 0;
1450}
1451
1452static int wil_sta_seq_open(struct inode *inode, struct file *file)
1453{
1454        return single_open(file, wil_sta_debugfs_show, inode->i_private);
1455}
1456
1457static const struct file_operations fops_sta = {
1458        .open           = wil_sta_seq_open,
1459        .release        = single_release,
1460        .read           = seq_read,
1461        .llseek         = seq_lseek,
1462};
1463
1464static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
1465                                     size_t count, loff_t *ppos)
1466{
1467        char buf[80];
1468        int n;
1469
1470        n = snprintf(buf, sizeof(buf),
1471                     "led_id is set to %d, echo 1 to enable, 0 to disable\n",
1472                     led_id);
1473
1474        n = min_t(int, n, sizeof(buf));
1475
1476        return simple_read_from_buffer(user_buf, count, ppos,
1477                                       buf, n);
1478}
1479
1480static ssize_t wil_write_file_led_cfg(struct file *file,
1481                                      const char __user *buf_,
1482                                      size_t count, loff_t *ppos)
1483{
1484        struct wil6210_priv *wil = file->private_data;
1485        int val;
1486        int rc;
1487
1488        rc = kstrtoint_from_user(buf_, count, 0, &val);
1489        if (rc) {
1490                wil_err(wil, "Invalid argument\n");
1491                return rc;
1492        }
1493
1494        wil_info(wil, "%s led %d\n", val ? "Enabling" : "Disabling", led_id);
1495        rc = wmi_led_cfg(wil, val);
1496        if (rc) {
1497                wil_info(wil, "%s led %d failed\n",
1498                         val ? "Enabling" : "Disabling", led_id);
1499                return rc;
1500        }
1501
1502        return count;
1503}
1504
1505static const struct file_operations fops_led_cfg = {
1506        .read = wil_read_file_led_cfg,
1507        .write = wil_write_file_led_cfg,
1508        .open  = simple_open,
1509};
1510
1511/* led_blink_time, write:
1512 * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
1513 */
1514static ssize_t wil_write_led_blink_time(struct file *file,
1515                                        const char __user *buf,
1516                                        size_t len, loff_t *ppos)
1517{
1518        int rc;
1519        char *kbuf = kmalloc(len + 1, GFP_KERNEL);
1520
1521        if (!kbuf)
1522                return -ENOMEM;
1523
1524        rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
1525        if (rc != len) {
1526                kfree(kbuf);
1527                return rc >= 0 ? -EIO : rc;
1528        }
1529
1530        kbuf[len] = '\0';
1531        rc = sscanf(kbuf, "%d %d %d %d %d %d",
1532                    &led_blink_time[WIL_LED_TIME_SLOW].on_ms,
1533                    &led_blink_time[WIL_LED_TIME_SLOW].off_ms,
1534                    &led_blink_time[WIL_LED_TIME_MED].on_ms,
1535                    &led_blink_time[WIL_LED_TIME_MED].off_ms,
1536                    &led_blink_time[WIL_LED_TIME_FAST].on_ms,
1537                    &led_blink_time[WIL_LED_TIME_FAST].off_ms);
1538        kfree(kbuf);
1539
1540        if (rc < 0)
1541                return rc;
1542        if (rc < 6)
1543                return -EINVAL;
1544
1545        return len;
1546}
1547
1548static ssize_t wil_read_led_blink_time(struct file *file, char __user *user_buf,
1549                                       size_t count, loff_t *ppos)
1550{
1551        static char text[400];
1552
1553        snprintf(text, sizeof(text),
1554                 "To set led blink on/off time variables write:\n"
1555                 "<blink_on_slow> <blink_off_slow> <blink_on_med> "
1556                 "<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
1557                 "The current values are:\n"
1558                 "%d %d %d %d %d %d\n",
1559                 led_blink_time[WIL_LED_TIME_SLOW].on_ms,
1560                 led_blink_time[WIL_LED_TIME_SLOW].off_ms,
1561                 led_blink_time[WIL_LED_TIME_MED].on_ms,
1562                 led_blink_time[WIL_LED_TIME_MED].off_ms,
1563                 led_blink_time[WIL_LED_TIME_FAST].on_ms,
1564                 led_blink_time[WIL_LED_TIME_FAST].off_ms);
1565
1566        return simple_read_from_buffer(user_buf, count, ppos, text,
1567                                       sizeof(text));
1568}
1569
1570static const struct file_operations fops_led_blink_time = {
1571        .read = wil_read_led_blink_time,
1572        .write = wil_write_led_blink_time,
1573        .open  = simple_open,
1574};
1575
1576/*---------FW capabilities------------*/
1577static int wil_fw_capabilities_debugfs_show(struct seq_file *s, void *data)
1578{
1579        struct wil6210_priv *wil = s->private;
1580
1581        seq_printf(s, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX,
1582                   wil->fw_capabilities);
1583
1584        return 0;
1585}
1586
1587static int wil_fw_capabilities_seq_open(struct inode *inode, struct file *file)
1588{
1589        return single_open(file, wil_fw_capabilities_debugfs_show,
1590                           inode->i_private);
1591}
1592
1593static const struct file_operations fops_fw_capabilities = {
1594        .open           = wil_fw_capabilities_seq_open,
1595        .release        = single_release,
1596        .read           = seq_read,
1597        .llseek         = seq_lseek,
1598};
1599
1600/*---------FW version------------*/
1601static int wil_fw_version_debugfs_show(struct seq_file *s, void *data)
1602{
1603        struct wil6210_priv *wil = s->private;
1604
1605        if (wil->fw_version[0])
1606                seq_printf(s, "%s\n", wil->fw_version);
1607        else
1608                seq_puts(s, "N/A\n");
1609
1610        return 0;
1611}
1612
1613static int wil_fw_version_seq_open(struct inode *inode, struct file *file)
1614{
1615        return single_open(file, wil_fw_version_debugfs_show,
1616                           inode->i_private);
1617}
1618
1619static const struct file_operations fops_fw_version = {
1620        .open           = wil_fw_version_seq_open,
1621        .release        = single_release,
1622        .read           = seq_read,
1623        .llseek         = seq_lseek,
1624};
1625
1626/*---------suspend_stats---------*/
1627static ssize_t wil_write_suspend_stats(struct file *file,
1628                                       const char __user *buf,
1629                                       size_t len, loff_t *ppos)
1630{
1631        struct wil6210_priv *wil = file->private_data;
1632
1633        memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
1634
1635        return len;
1636}
1637
1638static ssize_t wil_read_suspend_stats(struct file *file,
1639                                      char __user *user_buf,
1640                                      size_t count, loff_t *ppos)
1641{
1642        struct wil6210_priv *wil = file->private_data;
1643        char *text;
1644        int n, ret, text_size = 500;
1645
1646        text = kmalloc(text_size, GFP_KERNEL);
1647        if (!text)
1648                return -ENOMEM;
1649
1650        n = snprintf(text, text_size,
1651                     "Radio on suspend statistics:\n"
1652                     "successful suspends:%ld failed suspends:%ld\n"
1653                     "successful resumes:%ld failed resumes:%ld\n"
1654                     "rejected by device:%ld\n"
1655                     "Radio off suspend statistics:\n"
1656                     "successful suspends:%ld failed suspends:%ld\n"
1657                     "successful resumes:%ld failed resumes:%ld\n"
1658                     "General statistics:\n"
1659                     "rejected by host:%ld\n",
1660                     wil->suspend_stats.r_on.successful_suspends,
1661                     wil->suspend_stats.r_on.failed_suspends,
1662                     wil->suspend_stats.r_on.successful_resumes,
1663                     wil->suspend_stats.r_on.failed_resumes,
1664                     wil->suspend_stats.rejected_by_device,
1665                     wil->suspend_stats.r_off.successful_suspends,
1666                     wil->suspend_stats.r_off.failed_suspends,
1667                     wil->suspend_stats.r_off.successful_resumes,
1668                     wil->suspend_stats.r_off.failed_resumes,
1669                     wil->suspend_stats.rejected_by_host);
1670
1671        n = min_t(int, n, text_size);
1672
1673        ret = simple_read_from_buffer(user_buf, count, ppos, text, n);
1674
1675        kfree(text);
1676
1677        return ret;
1678}
1679
1680static const struct file_operations fops_suspend_stats = {
1681        .read = wil_read_suspend_stats,
1682        .write = wil_write_suspend_stats,
1683        .open  = simple_open,
1684};
1685
1686/*----------------*/
1687static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
1688                                       struct dentry *dbg)
1689{
1690        int i;
1691        char name[32];
1692
1693        for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
1694                struct wil_blob_wrapper *wil_blob = &wil->blobs[i];
1695                struct debugfs_blob_wrapper *blob = &wil_blob->blob;
1696                const struct fw_map *map = &fw_mapping[i];
1697
1698                if (!map->name)
1699                        continue;
1700
1701                wil_blob->wil = wil;
1702                blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
1703                blob->size = map->to - map->from;
1704                snprintf(name, sizeof(name), "blob_%s", map->name);
1705                wil_debugfs_create_ioblob(name, 0444, dbg, wil_blob);
1706        }
1707}
1708
1709/* misc files */
1710static const struct {
1711        const char *name;
1712        umode_t mode;
1713        const struct file_operations *fops;
1714} dbg_files[] = {
1715        {"mbox",        0444,           &fops_mbox},
1716        {"vrings",      0444,           &fops_vring},
1717        {"stations", 0444,              &fops_sta},
1718        {"desc",        0444,           &fops_txdesc},
1719        {"bf",          0444,           &fops_bf},
1720        {"mem_val",     0644,           &fops_memread},
1721        {"reset",       0244,           &fops_reset},
1722        {"rxon",        0244,           &fops_rxon},
1723        {"tx_mgmt",     0244,           &fops_txmgmt},
1724        {"wmi_send", 0244,              &fops_wmi},
1725        {"back",        0644,           &fops_back},
1726        {"pmccfg",      0644,           &fops_pmccfg},
1727        {"pmcdata",     0444,           &fops_pmcdata},
1728        {"temp",        0444,           &fops_temp},
1729        {"freq",        0444,           &fops_freq},
1730        {"link",        0444,           &fops_link},
1731        {"info",        0444,           &fops_info},
1732        {"recovery", 0644,              &fops_recovery},
1733        {"led_cfg",     0644,           &fops_led_cfg},
1734        {"led_blink_time",      0644,   &fops_led_blink_time},
1735        {"fw_capabilities",     0444,   &fops_fw_capabilities},
1736        {"fw_version",  0444,           &fops_fw_version},
1737        {"suspend_stats",       0644,   &fops_suspend_stats},
1738};
1739
1740static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
1741                                       struct dentry *dbg)
1742{
1743        int i;
1744
1745        for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
1746                debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
1747                                    wil, dbg_files[i].fops);
1748}
1749
1750/* interrupt control blocks */
1751static const struct {
1752        const char *name;
1753        u32 icr_off;
1754} dbg_icr[] = {
1755        {"USER_ICR",            HOSTADDR(RGF_USER_USER_ICR)},
1756        {"DMA_EP_TX_ICR",       HOSTADDR(RGF_DMA_EP_TX_ICR)},
1757        {"DMA_EP_RX_ICR",       HOSTADDR(RGF_DMA_EP_RX_ICR)},
1758        {"DMA_EP_MISC_ICR",     HOSTADDR(RGF_DMA_EP_MISC_ICR)},
1759};
1760
1761static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
1762                                     struct dentry *dbg)
1763{
1764        int i;
1765
1766        for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
1767                wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
1768                                           dbg_icr[i].icr_off);
1769}
1770
1771#define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
1772        offsetof(struct wil6210_priv, name), type}
1773
1774/* fields in struct wil6210_priv */
1775static const struct dbg_off dbg_wil_off[] = {
1776        WIL_FIELD(privacy,      0444,           doff_u32),
1777        WIL_FIELD(status[0],    0644,   doff_ulong),
1778        WIL_FIELD(hw_version,   0444,   doff_x32),
1779        WIL_FIELD(recovery_count, 0444, doff_u32),
1780        WIL_FIELD(ap_isolate,   0444,   doff_u32),
1781        WIL_FIELD(discovery_mode, 0644, doff_u8),
1782        WIL_FIELD(chip_revision, 0444,  doff_u8),
1783        WIL_FIELD(abft_len, 0644,               doff_u8),
1784        WIL_FIELD(wakeup_trigger, 0644,         doff_u8),
1785        WIL_FIELD(vring_idle_trsh, 0644,        doff_u32),
1786        {},
1787};
1788
1789static const struct dbg_off dbg_wil_regs[] = {
1790        {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
1791                doff_io32},
1792        {"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
1793        {},
1794};
1795
1796/* static parameters */
1797static const struct dbg_off dbg_statics[] = {
1798        {"desc_index",  0644, (ulong)&dbg_txdesc_index, doff_u32},
1799        {"vring_index", 0644, (ulong)&dbg_vring_index, doff_u32},
1800        {"mem_addr",    0644, (ulong)&mem_addr, doff_u32},
1801        {"led_polarity", 0644, (ulong)&led_polarity, doff_u8},
1802        {},
1803};
1804
1805static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) +
1806                                ARRAY_SIZE(dbg_wil_regs) - 1 +
1807                                ARRAY_SIZE(pseudo_isr_off) - 1 +
1808                                ARRAY_SIZE(lgc_itr_cnt_off) - 1 +
1809                                ARRAY_SIZE(tx_itr_cnt_off) - 1 +
1810                                ARRAY_SIZE(rx_itr_cnt_off) - 1;
1811
1812int wil6210_debugfs_init(struct wil6210_priv *wil)
1813{
1814        struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
1815                        wil_to_wiphy(wil)->debugfsdir);
1816        if (IS_ERR_OR_NULL(dbg))
1817                return -ENODEV;
1818
1819        wil->dbg_data.data_arr = kcalloc(dbg_off_count,
1820                                         sizeof(struct wil_debugfs_iomem_data),
1821                                         GFP_KERNEL);
1822        if (!wil->dbg_data.data_arr) {
1823                debugfs_remove_recursive(dbg);
1824                wil->debug = NULL;
1825                return -ENOMEM;
1826        }
1827
1828        wil->dbg_data.iomem_data_count = 0;
1829
1830        wil_pmc_init(wil);
1831
1832        wil6210_debugfs_init_files(wil, dbg);
1833        wil6210_debugfs_init_isr(wil, dbg);
1834        wil6210_debugfs_init_blobs(wil, dbg);
1835        wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
1836        wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
1837                                    dbg_wil_regs);
1838        wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
1839
1840        wil6210_debugfs_create_pseudo_ISR(wil, dbg);
1841
1842        wil6210_debugfs_create_ITR_CNT(wil, dbg);
1843
1844        return 0;
1845}
1846
1847void wil6210_debugfs_remove(struct wil6210_priv *wil)
1848{
1849        debugfs_remove_recursive(wil->debug);
1850        wil->debug = NULL;
1851
1852        kfree(wil->dbg_data.data_arr);
1853
1854        /* free pmc memory without sending command to fw, as it will
1855         * be reset on the way down anyway
1856         */
1857        wil_pmc_free(wil, false);
1858}
1859