Merge commit 'c1e140bf79d817d4a7aa9932eb98b0359c87af33' from mac80211-next
[pandora-kernel.git] / drivers / net / wireless / ath / wil6210 / debugfs.c
1 /*
2  * Copyright (c) 2012-2014 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
24 #include "wil6210.h"
25 #include "wmi.h"
26 #include "txrx.h"
27
28 /* Nasty hack. Better have per device instances */
29 static u32 mem_addr;
30 static u32 dbg_txdesc_index;
31 static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
32
33 enum dbg_off_type {
34         doff_u32 = 0,
35         doff_x32 = 1,
36         doff_ulong = 2,
37         doff_io32 = 3,
38 };
39
40 /* offset to "wil" */
41 struct dbg_off {
42         const char *name;
43         umode_t mode;
44         ulong off;
45         enum dbg_off_type type;
46 };
47
48 static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
49                             const char *name, struct vring *vring,
50                             char _s, char _h)
51 {
52         void __iomem *x = wmi_addr(wil, vring->hwtail);
53         u32 v;
54
55         seq_printf(s, "VRING %s = {\n", name);
56         seq_printf(s, "  pa     = %pad\n", &vring->pa);
57         seq_printf(s, "  va     = 0x%p\n", vring->va);
58         seq_printf(s, "  size   = %d\n", vring->size);
59         seq_printf(s, "  swtail = %d\n", vring->swtail);
60         seq_printf(s, "  swhead = %d\n", vring->swhead);
61         seq_printf(s, "  hwtail = [0x%08x] -> ", vring->hwtail);
62         if (x) {
63                 v = ioread32(x);
64                 seq_printf(s, "0x%08x = %d\n", v, v);
65         } else {
66                 seq_puts(s, "???\n");
67         }
68
69         if (vring->va && (vring->size < 1025)) {
70                 uint i;
71
72                 for (i = 0; i < vring->size; i++) {
73                         volatile struct vring_tx_desc *d = &vring->va[i].tx;
74
75                         if ((i % 64) == 0 && (i != 0))
76                                 seq_puts(s, "\n");
77                         seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
78                                         _s : (vring->ctx[i].skb ? _h : 'h'));
79                 }
80                 seq_puts(s, "\n");
81         }
82         seq_puts(s, "}\n");
83 }
84
85 static int wil_vring_debugfs_show(struct seq_file *s, void *data)
86 {
87         uint i;
88         struct wil6210_priv *wil = s->private;
89
90         wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
91
92         for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
93                 struct vring *vring = &wil->vring_tx[i];
94                 struct vring_tx_data *txdata = &wil->vring_tx_data[i];
95
96                 if (vring->va) {
97                         int cid = wil->vring2cid_tid[i][0];
98                         int tid = wil->vring2cid_tid[i][1];
99                         u32 swhead = vring->swhead;
100                         u32 swtail = vring->swtail;
101                         int used = (vring->size + swhead - swtail)
102                                    % vring->size;
103                         int avail = vring->size - used - 1;
104                         char name[10];
105                         /* performance monitoring */
106                         cycles_t now = get_cycles();
107                         uint64_t idle = txdata->idle * 100;
108                         uint64_t total = now - txdata->begin;
109
110                         do_div(idle, total);
111                         txdata->begin = now;
112                         txdata->idle = 0ULL;
113
114                         snprintf(name, sizeof(name), "tx_%2d", i);
115
116                         seq_printf(s,
117                                    "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %3d%%\n",
118                                    wil->sta[cid].addr, cid, tid,
119                                    txdata->agg_wsize, txdata->agg_timeout,
120                                    txdata->agg_amsdu ? "+" : "-",
121                                    used, avail, (int)idle);
122
123                         wil_print_vring(s, wil, name, vring, '_', 'H');
124                 }
125         }
126
127         return 0;
128 }
129
130 static int wil_vring_seq_open(struct inode *inode, struct file *file)
131 {
132         return single_open(file, wil_vring_debugfs_show, inode->i_private);
133 }
134
135 static const struct file_operations fops_vring = {
136         .open           = wil_vring_seq_open,
137         .release        = single_release,
138         .read           = seq_read,
139         .llseek         = seq_lseek,
140 };
141
142 static void wil_print_ring(struct seq_file *s, const char *prefix,
143                            void __iomem *off)
144 {
145         struct wil6210_priv *wil = s->private;
146         struct wil6210_mbox_ring r;
147         int rsize;
148         uint i;
149
150         wil_memcpy_fromio_32(&r, off, sizeof(r));
151         wil_mbox_ring_le2cpus(&r);
152         /*
153          * we just read memory block from NIC. This memory may be
154          * garbage. Check validity before using it.
155          */
156         rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
157
158         seq_printf(s, "ring %s = {\n", prefix);
159         seq_printf(s, "  base = 0x%08x\n", r.base);
160         seq_printf(s, "  size = 0x%04x bytes -> %d entries\n", r.size, rsize);
161         seq_printf(s, "  tail = 0x%08x\n", r.tail);
162         seq_printf(s, "  head = 0x%08x\n", r.head);
163         seq_printf(s, "  entry size = %d\n", r.entry_size);
164
165         if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
166                 seq_printf(s, "  ??? size is not multiple of %zd, garbage?\n",
167                            sizeof(struct wil6210_mbox_ring_desc));
168                 goto out;
169         }
170
171         if (!wmi_addr(wil, r.base) ||
172             !wmi_addr(wil, r.tail) ||
173             !wmi_addr(wil, r.head)) {
174                 seq_puts(s, "  ??? pointers are garbage?\n");
175                 goto out;
176         }
177
178         for (i = 0; i < rsize; i++) {
179                 struct wil6210_mbox_ring_desc d;
180                 struct wil6210_mbox_hdr hdr;
181                 size_t delta = i * sizeof(d);
182                 void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
183
184                 wil_memcpy_fromio_32(&d, x, sizeof(d));
185
186                 seq_printf(s, "  [%2x] %s %s%s 0x%08x", i,
187                            d.sync ? "F" : "E",
188                            (r.tail - r.base == delta) ? "t" : " ",
189                            (r.head - r.base == delta) ? "h" : " ",
190                            le32_to_cpu(d.addr));
191                 if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
192                         u16 len = le16_to_cpu(hdr.len);
193
194                         seq_printf(s, " -> %04x %04x %04x %02x\n",
195                                    le16_to_cpu(hdr.seq), len,
196                                    le16_to_cpu(hdr.type), hdr.flags);
197                         if (len <= MAX_MBOXITEM_SIZE) {
198                                 int n = 0;
199                                 char printbuf[16 * 3 + 2];
200                                 unsigned char databuf[MAX_MBOXITEM_SIZE];
201                                 void __iomem *src = wmi_buffer(wil, d.addr) +
202                                         sizeof(struct wil6210_mbox_hdr);
203                                 /*
204                                  * No need to check @src for validity -
205                                  * we already validated @d.addr while
206                                  * reading header
207                                  */
208                                 wil_memcpy_fromio_32(databuf, src, len);
209                                 while (n < len) {
210                                         int l = min(len - n, 16);
211
212                                         hex_dump_to_buffer(databuf + n, l,
213                                                            16, 1, printbuf,
214                                                            sizeof(printbuf),
215                                                            false);
216                                         seq_printf(s, "      : %s\n", printbuf);
217                                         n += l;
218                                 }
219                         }
220                 } else {
221                         seq_puts(s, "\n");
222                 }
223         }
224  out:
225         seq_puts(s, "}\n");
226 }
227
228 static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
229 {
230         struct wil6210_priv *wil = s->private;
231
232         wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
233                        offsetof(struct wil6210_mbox_ctl, tx));
234         wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
235                        offsetof(struct wil6210_mbox_ctl, rx));
236
237         return 0;
238 }
239
240 static int wil_mbox_seq_open(struct inode *inode, struct file *file)
241 {
242         return single_open(file, wil_mbox_debugfs_show, inode->i_private);
243 }
244
245 static const struct file_operations fops_mbox = {
246         .open           = wil_mbox_seq_open,
247         .release        = single_release,
248         .read           = seq_read,
249         .llseek         = seq_lseek,
250 };
251
252 static int wil_debugfs_iomem_x32_set(void *data, u64 val)
253 {
254         iowrite32(val, (void __iomem *)data);
255         wmb(); /* make sure write propagated to HW */
256
257         return 0;
258 }
259
260 static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
261 {
262         *val = ioread32((void __iomem *)data);
263
264         return 0;
265 }
266
267 DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
268                         wil_debugfs_iomem_x32_set, "0x%08llx\n");
269
270 static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
271                                                    umode_t mode,
272                                                    struct dentry *parent,
273                                                    void *value)
274 {
275         return debugfs_create_file(name, mode, parent, value,
276                                    &fops_iomem_x32);
277 }
278
279 static int wil_debugfs_ulong_set(void *data, u64 val)
280 {
281         *(ulong *)data = val;
282         return 0;
283 }
284
285 static int wil_debugfs_ulong_get(void *data, u64 *val)
286 {
287         *val = *(ulong *)data;
288         return 0;
289 }
290
291 DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
292                         wil_debugfs_ulong_set, "%llu\n");
293
294 static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
295                                                struct dentry *parent,
296                                                ulong *value)
297 {
298         return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
299 }
300
301 /**
302  * wil6210_debugfs_init_offset - create set of debugfs files
303  * @wil - driver's context, used for printing
304  * @dbg - directory on the debugfs, where files will be created
305  * @base - base address used in address calculation
306  * @tbl - table with file descriptions. Should be terminated with empty element.
307  *
308  * Creates files accordingly to the @tbl.
309  */
310 static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
311                                         struct dentry *dbg, void *base,
312                                         const struct dbg_off * const tbl)
313 {
314         int i;
315
316         for (i = 0; tbl[i].name; i++) {
317                 struct dentry *f;
318
319                 switch (tbl[i].type) {
320                 case doff_u32:
321                         f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
322                                                base + tbl[i].off);
323                         break;
324                 case doff_x32:
325                         f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
326                                                base + tbl[i].off);
327                         break;
328                 case doff_ulong:
329                         f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
330                                                      dbg, base + tbl[i].off);
331                         break;
332                 case doff_io32:
333                         f = wil_debugfs_create_iomem_x32(tbl[i].name,
334                                                          tbl[i].mode, dbg,
335                                                          base + tbl[i].off);
336                         break;
337                 default:
338                         f = ERR_PTR(-EINVAL);
339                 }
340                 if (IS_ERR_OR_NULL(f))
341                         wil_err(wil, "Create file \"%s\": err %ld\n",
342                                 tbl[i].name, PTR_ERR(f));
343         }
344 }
345
346 static const struct dbg_off isr_off[] = {
347         {"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
348         {"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
349         {"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
350         {"ICS",           S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
351         {"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
352         {"IMS",           S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
353         {"IMC",           S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
354         {},
355 };
356
357 static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
358                                       const char *name,
359                                       struct dentry *parent, u32 off)
360 {
361         struct dentry *d = debugfs_create_dir(name, parent);
362
363         if (IS_ERR_OR_NULL(d))
364                 return -ENODEV;
365
366         wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
367                                     isr_off);
368
369         return 0;
370 }
371
372 static const struct dbg_off pseudo_isr_off[] = {
373         {"CAUSE",   S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
374         {"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
375         {"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
376         {},
377 };
378
379 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
380                                              struct dentry *parent)
381 {
382         struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
383
384         if (IS_ERR_OR_NULL(d))
385                 return -ENODEV;
386
387         wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
388                                     pseudo_isr_off);
389
390         return 0;
391 }
392
393 static const struct dbg_off lgc_itr_cnt_off[] = {
394         {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
395         {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
396         {"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
397         {},
398 };
399
400 static const struct dbg_off tx_itr_cnt_off[] = {
401         {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
402          doff_io32},
403         {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
404          doff_io32},
405         {"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
406          doff_io32},
407         {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
408          doff_io32},
409         {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
410          doff_io32},
411         {"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
412          doff_io32},
413         {},
414 };
415
416 static const struct dbg_off rx_itr_cnt_off[] = {
417         {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
418          doff_io32},
419         {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
420          doff_io32},
421         {"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
422          doff_io32},
423         {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
424          doff_io32},
425         {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
426          doff_io32},
427         {"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
428          doff_io32},
429         {},
430 };
431
432 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
433                                           struct dentry *parent)
434 {
435         struct dentry *d, *dtx, *drx;
436
437         d = debugfs_create_dir("ITR_CNT", parent);
438         if (IS_ERR_OR_NULL(d))
439                 return -ENODEV;
440
441         dtx = debugfs_create_dir("TX", d);
442         drx = debugfs_create_dir("RX", d);
443         if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
444                 return -ENODEV;
445
446         wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
447                                     lgc_itr_cnt_off);
448
449         wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
450                                     tx_itr_cnt_off);
451
452         wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
453                                     rx_itr_cnt_off);
454         return 0;
455 }
456
457 static int wil_memread_debugfs_show(struct seq_file *s, void *data)
458 {
459         struct wil6210_priv *wil = s->private;
460         void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
461
462         if (a)
463                 seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a));
464         else
465                 seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
466
467         return 0;
468 }
469
470 static int wil_memread_seq_open(struct inode *inode, struct file *file)
471 {
472         return single_open(file, wil_memread_debugfs_show, inode->i_private);
473 }
474
475 static const struct file_operations fops_memread = {
476         .open           = wil_memread_seq_open,
477         .release        = single_release,
478         .read           = seq_read,
479         .llseek         = seq_lseek,
480 };
481
482 static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
483                                     size_t count, loff_t *ppos)
484 {
485         enum { max_count = 4096 };
486         struct debugfs_blob_wrapper *blob = file->private_data;
487         loff_t pos = *ppos;
488         size_t available = blob->size;
489         void *buf;
490         size_t ret;
491
492         if (pos < 0)
493                 return -EINVAL;
494
495         if (pos >= available || !count)
496                 return 0;
497
498         if (count > available - pos)
499                 count = available - pos;
500         if (count > max_count)
501                 count = max_count;
502
503         buf = kmalloc(count, GFP_KERNEL);
504         if (!buf)
505                 return -ENOMEM;
506
507         wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data +
508                              pos, count);
509
510         ret = copy_to_user(user_buf, buf, count);
511         kfree(buf);
512         if (ret == count)
513                 return -EFAULT;
514
515         count -= ret;
516         *ppos = pos + count;
517
518         return count;
519 }
520
521 static const struct file_operations fops_ioblob = {
522         .read =         wil_read_file_ioblob,
523         .open =         simple_open,
524         .llseek =       default_llseek,
525 };
526
527 static
528 struct dentry *wil_debugfs_create_ioblob(const char *name,
529                                          umode_t mode,
530                                          struct dentry *parent,
531                                          struct debugfs_blob_wrapper *blob)
532 {
533         return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
534 }
535
536 /*---reset---*/
537 static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
538                                     size_t len, loff_t *ppos)
539 {
540         struct wil6210_priv *wil = file->private_data;
541         struct net_device *ndev = wil_to_ndev(wil);
542
543         /**
544          * BUG:
545          * this code does NOT sync device state with the rest of system
546          * use with care, debug only!!!
547          */
548         rtnl_lock();
549         dev_close(ndev);
550         ndev->flags &= ~IFF_UP;
551         rtnl_unlock();
552         wil_reset(wil);
553
554         return len;
555 }
556
557 static const struct file_operations fops_reset = {
558         .write = wil_write_file_reset,
559         .open  = simple_open,
560 };
561
562 /*---write channel 1..4 to rxon for it, 0 to rxoff---*/
563 static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
564                                    size_t len, loff_t *ppos)
565 {
566         struct wil6210_priv *wil = file->private_data;
567         int rc;
568         long channel;
569         bool on;
570
571         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
572
573         if (!kbuf)
574                 return -ENOMEM;
575         if (copy_from_user(kbuf, buf, len)) {
576                 kfree(kbuf);
577                 return -EIO;
578         }
579
580         kbuf[len] = '\0';
581         rc = kstrtol(kbuf, 0, &channel);
582         kfree(kbuf);
583         if (rc)
584                 return rc;
585
586         if ((channel < 0) || (channel > 4)) {
587                 wil_err(wil, "Invalid channel %ld\n", channel);
588                 return -EINVAL;
589         }
590         on = !!channel;
591
592         if (on) {
593                 rc = wmi_set_channel(wil, (int)channel);
594                 if (rc)
595                         return rc;
596         }
597
598         rc = wmi_rxon(wil, on);
599         if (rc)
600                 return rc;
601
602         return len;
603 }
604
605 static const struct file_operations fops_rxon = {
606         .write = wil_write_file_rxon,
607         .open  = simple_open,
608 };
609
610 /* block ack control, write:
611  * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
612  * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
613  * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
614  */
615 static ssize_t wil_write_back(struct file *file, const char __user *buf,
616                               size_t len, loff_t *ppos)
617 {
618         struct wil6210_priv *wil = file->private_data;
619         int rc;
620         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
621         char cmd[8];
622         int p1, p2, p3;
623
624         if (!kbuf)
625                 return -ENOMEM;
626
627         rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
628         if (rc != len) {
629                 kfree(kbuf);
630                 return rc >= 0 ? -EIO : rc;
631         }
632
633         kbuf[len] = '\0';
634         rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
635         kfree(kbuf);
636
637         if (rc < 0)
638                 return rc;
639         if (rc < 2)
640                 return -EINVAL;
641
642         if (0 == strcmp(cmd, "add")) {
643                 if (rc < 3) {
644                         wil_err(wil, "BACK: add require at least 2 params\n");
645                         return -EINVAL;
646                 }
647                 if (rc < 4)
648                         p3 = 0;
649                 wmi_addba(wil, p1, p2, p3);
650         } else if (0 == strcmp(cmd, "del_tx")) {
651                 if (rc < 3)
652                         p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
653                 wmi_delba_tx(wil, p1, p2);
654         } else if (0 == strcmp(cmd, "del_rx")) {
655                 if (rc < 3) {
656                         wil_err(wil,
657                                 "BACK: del_rx require at least 2 params\n");
658                         return -EINVAL;
659                 }
660                 if (rc < 4)
661                         p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
662                 wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
663         } else {
664                 wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
665                 return -EINVAL;
666         }
667
668         return len;
669 }
670
671 static ssize_t wil_read_back(struct file *file, char __user *user_buf,
672                              size_t count, loff_t *ppos)
673 {
674         static const char text[] = "block ack control, write:\n"
675         " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
676         "If missing, <timeout> defaults to 0\n"
677         " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
678         " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
679         "If missing, <reason> set to \"STA_LEAVING\" (36)\n";
680
681         return simple_read_from_buffer(user_buf, count, ppos, text,
682                                        sizeof(text));
683 }
684
685 static const struct file_operations fops_back = {
686         .read = wil_read_back,
687         .write = wil_write_back,
688         .open  = simple_open,
689 };
690
691 /*---tx_mgmt---*/
692 /* Write mgmt frame to this file to send it */
693 static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
694                                      size_t len, loff_t *ppos)
695 {
696         struct wil6210_priv *wil = file->private_data;
697         struct wiphy *wiphy = wil_to_wiphy(wil);
698         struct wireless_dev *wdev = wil_to_wdev(wil);
699         struct cfg80211_mgmt_tx_params params;
700         int rc;
701         void *frame = kmalloc(len, GFP_KERNEL);
702
703         if (!frame)
704                 return -ENOMEM;
705
706         if (copy_from_user(frame, buf, len)) {
707                 kfree(frame);
708                 return -EIO;
709         }
710
711         params.buf = frame;
712         params.len = len;
713         params.chan = wdev->preset_chandef.chan;
714
715         rc = wil_cfg80211_mgmt_tx(wiphy, wdev, &params, NULL);
716
717         kfree(frame);
718         wil_info(wil, "%s() -> %d\n", __func__, rc);
719
720         return len;
721 }
722
723 static const struct file_operations fops_txmgmt = {
724         .write = wil_write_file_txmgmt,
725         .open  = simple_open,
726 };
727
728 /* Write WMI command (w/o mbox header) to this file to send it
729  * WMI starts from wil6210_mbox_hdr_wmi header
730  */
731 static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
732                                   size_t len, loff_t *ppos)
733 {
734         struct wil6210_priv *wil = file->private_data;
735         struct wil6210_mbox_hdr_wmi *wmi;
736         void *cmd;
737         int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi);
738         u16 cmdid;
739         int rc, rc1;
740
741         if (cmdlen <= 0)
742                 return -EINVAL;
743
744         wmi = kmalloc(len, GFP_KERNEL);
745         if (!wmi)
746                 return -ENOMEM;
747
748         rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
749         if (rc < 0) {
750                 kfree(wmi);
751                 return rc;
752         }
753
754         cmd = &wmi[1];
755         cmdid = le16_to_cpu(wmi->id);
756
757         rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
758         kfree(wmi);
759
760         wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1);
761
762         return rc;
763 }
764
765 static const struct file_operations fops_wmi = {
766         .write = wil_write_file_wmi,
767         .open  = simple_open,
768 };
769
770 static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
771                             const char *prefix)
772 {
773         char printbuf[16 * 3 + 2];
774         int i = 0;
775
776         while (i < len) {
777                 int l = min(len - i, 16);
778
779                 hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
780                                    sizeof(printbuf), false);
781                 seq_printf(s, "%s%s\n", prefix, printbuf);
782                 i += l;
783         }
784 }
785
786 static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
787 {
788         int i = 0;
789         int len = skb_headlen(skb);
790         void *p = skb->data;
791         int nr_frags = skb_shinfo(skb)->nr_frags;
792
793         seq_printf(s, "    len = %d\n", len);
794         wil_seq_hexdump(s, p, len, "      : ");
795
796         if (nr_frags) {
797                 seq_printf(s, "    nr_frags = %d\n", nr_frags);
798                 for (i = 0; i < nr_frags; i++) {
799                         const struct skb_frag_struct *frag =
800                                         &skb_shinfo(skb)->frags[i];
801
802                         len = skb_frag_size(frag);
803                         p = skb_frag_address_safe(frag);
804                         seq_printf(s, "    [%2d] : len = %d\n", i, len);
805                         wil_seq_hexdump(s, p, len, "      : ");
806                 }
807         }
808 }
809
810 /*---------Tx/Rx descriptor------------*/
811 static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
812 {
813         struct wil6210_priv *wil = s->private;
814         struct vring *vring;
815         bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
816
817         vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
818
819         if (!vring->va) {
820                 if (tx)
821                         seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index);
822                 else
823                         seq_puts(s, "No Rx VRING\n");
824                 return 0;
825         }
826
827         if (dbg_txdesc_index < vring->size) {
828                 /* use struct vring_tx_desc for Rx as well,
829                  * only field used, .dma.length, is the same
830                  */
831                 volatile struct vring_tx_desc *d =
832                                 &vring->va[dbg_txdesc_index].tx;
833                 volatile u32 *u = (volatile u32 *)d;
834                 struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
835
836                 if (tx)
837                         seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index,
838                                    dbg_txdesc_index);
839                 else
840                         seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);
841                 seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
842                            u[0], u[1], u[2], u[3]);
843                 seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
844                            u[4], u[5], u[6], u[7]);
845                 seq_printf(s, "  SKB = 0x%p\n", skb);
846
847                 if (skb) {
848                         skb_get(skb);
849                         wil_seq_print_skb(s, skb);
850                         kfree_skb(skb);
851                 }
852                 seq_puts(s, "}\n");
853         } else {
854                 if (tx)
855                         seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
856                                    dbg_vring_index, dbg_txdesc_index,
857                                    vring->size);
858                 else
859                         seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
860                                    dbg_txdesc_index, vring->size);
861         }
862
863         return 0;
864 }
865
866 static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
867 {
868         return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
869 }
870
871 static const struct file_operations fops_txdesc = {
872         .open           = wil_txdesc_seq_open,
873         .release        = single_release,
874         .read           = seq_read,
875         .llseek         = seq_lseek,
876 };
877
878 /*---------beamforming------------*/
879 static char *wil_bfstatus_str(u32 status)
880 {
881         switch (status) {
882         case 0:
883                 return "Failed";
884         case 1:
885                 return "OK";
886         case 2:
887                 return "Retrying";
888         default:
889                 return "??";
890         }
891 }
892
893 static bool is_all_zeros(void * const x_, size_t sz)
894 {
895         /* if reply is all-0, ignore this CID */
896         u32 *x = x_;
897         int n;
898
899         for (n = 0; n < sz / sizeof(*x); n++)
900                 if (x[n])
901                         return false;
902
903         return true;
904 }
905
906 static int wil_bf_debugfs_show(struct seq_file *s, void *data)
907 {
908         int rc;
909         int i;
910         struct wil6210_priv *wil = s->private;
911         struct wmi_notify_req_cmd cmd = {
912                 .interval_usec = 0,
913         };
914         struct {
915                 struct wil6210_mbox_hdr_wmi wmi;
916                 struct wmi_notify_req_done_event evt;
917         } __packed reply;
918
919         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
920                 u32 status;
921
922                 cmd.cid = i;
923                 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
924                               WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
925                               sizeof(reply), 20);
926                 /* if reply is all-0, ignore this CID */
927                 if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
928                         continue;
929
930                 status = le32_to_cpu(reply.evt.status);
931                 seq_printf(s, "CID %d {\n"
932                            "  TSF = 0x%016llx\n"
933                            "  TxMCS = %2d TxTpt = %4d\n"
934                            "  SQI = %4d\n"
935                            "  Status = 0x%08x %s\n"
936                            "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
937                            "  Goodput(rx:tx) %4d:%4d\n"
938                            "}\n",
939                            i,
940                            le64_to_cpu(reply.evt.tsf),
941                            le16_to_cpu(reply.evt.bf_mcs),
942                            le32_to_cpu(reply.evt.tx_tpt),
943                            reply.evt.sqi,
944                            status, wil_bfstatus_str(status),
945                            le16_to_cpu(reply.evt.my_rx_sector),
946                            le16_to_cpu(reply.evt.my_tx_sector),
947                            le16_to_cpu(reply.evt.other_rx_sector),
948                            le16_to_cpu(reply.evt.other_tx_sector),
949                            le32_to_cpu(reply.evt.rx_goodput),
950                            le32_to_cpu(reply.evt.tx_goodput));
951         }
952         return 0;
953 }
954
955 static int wil_bf_seq_open(struct inode *inode, struct file *file)
956 {
957         return single_open(file, wil_bf_debugfs_show, inode->i_private);
958 }
959
960 static const struct file_operations fops_bf = {
961         .open           = wil_bf_seq_open,
962         .release        = single_release,
963         .read           = seq_read,
964         .llseek         = seq_lseek,
965 };
966
967 /*---------SSID------------*/
968 static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
969                                   size_t count, loff_t *ppos)
970 {
971         struct wil6210_priv *wil = file->private_data;
972         struct wireless_dev *wdev = wil_to_wdev(wil);
973
974         return simple_read_from_buffer(user_buf, count, ppos,
975                                        wdev->ssid, wdev->ssid_len);
976 }
977
978 static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf,
979                                    size_t count, loff_t *ppos)
980 {
981         struct wil6210_priv *wil = file->private_data;
982         struct wireless_dev *wdev = wil_to_wdev(wil);
983         struct net_device *ndev = wil_to_ndev(wil);
984
985         if (*ppos != 0) {
986                 wil_err(wil, "Unable to set SSID substring from [%d]\n",
987                         (int)*ppos);
988                 return -EINVAL;
989         }
990
991         if (count > sizeof(wdev->ssid)) {
992                 wil_err(wil, "SSID too long, len = %d\n", (int)count);
993                 return -EINVAL;
994         }
995         if (netif_running(ndev)) {
996                 wil_err(wil, "Unable to change SSID on running interface\n");
997                 return -EINVAL;
998         }
999
1000         wdev->ssid_len = count;
1001         return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos,
1002                                       buf, count);
1003 }
1004
1005 static const struct file_operations fops_ssid = {
1006         .read = wil_read_file_ssid,
1007         .write = wil_write_file_ssid,
1008         .open  = simple_open,
1009 };
1010
1011 /*---------temp------------*/
1012 static void print_temp(struct seq_file *s, const char *prefix, u32 t)
1013 {
1014         switch (t) {
1015         case 0:
1016         case ~(u32)0:
1017                 seq_printf(s, "%s N/A\n", prefix);
1018         break;
1019         default:
1020                 seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000);
1021                 break;
1022         }
1023 }
1024
1025 static int wil_temp_debugfs_show(struct seq_file *s, void *data)
1026 {
1027         struct wil6210_priv *wil = s->private;
1028         u32 t_m, t_r;
1029         int rc = wmi_get_temperature(wil, &t_m, &t_r);
1030
1031         if (rc) {
1032                 seq_puts(s, "Failed\n");
1033                 return 0;
1034         }
1035
1036         print_temp(s, "T_mac   =", t_m);
1037         print_temp(s, "T_radio =", t_r);
1038
1039         return 0;
1040 }
1041
1042 static int wil_temp_seq_open(struct inode *inode, struct file *file)
1043 {
1044         return single_open(file, wil_temp_debugfs_show, inode->i_private);
1045 }
1046
1047 static const struct file_operations fops_temp = {
1048         .open           = wil_temp_seq_open,
1049         .release        = single_release,
1050         .read           = seq_read,
1051         .llseek         = seq_lseek,
1052 };
1053
1054 /*---------freq------------*/
1055 static int wil_freq_debugfs_show(struct seq_file *s, void *data)
1056 {
1057         struct wil6210_priv *wil = s->private;
1058         struct wireless_dev *wdev = wil_to_wdev(wil);
1059         u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
1060
1061         seq_printf(s, "Freq = %d\n", freq);
1062
1063         return 0;
1064 }
1065
1066 static int wil_freq_seq_open(struct inode *inode, struct file *file)
1067 {
1068         return single_open(file, wil_freq_debugfs_show, inode->i_private);
1069 }
1070
1071 static const struct file_operations fops_freq = {
1072         .open           = wil_freq_seq_open,
1073         .release        = single_release,
1074         .read           = seq_read,
1075         .llseek         = seq_lseek,
1076 };
1077
1078 /*---------link------------*/
1079 static int wil_link_debugfs_show(struct seq_file *s, void *data)
1080 {
1081         struct wil6210_priv *wil = s->private;
1082         struct station_info sinfo;
1083         int i, rc;
1084
1085         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1086                 struct wil_sta_info *p = &wil->sta[i];
1087                 char *status = "unknown";
1088
1089                 switch (p->status) {
1090                 case wil_sta_unused:
1091                         status = "unused   ";
1092                         break;
1093                 case wil_sta_conn_pending:
1094                         status = "pending  ";
1095                         break;
1096                 case wil_sta_connected:
1097                         status = "connected";
1098                         break;
1099                 }
1100                 seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
1101                            (p->data_port_open ? " data_port_open" : ""));
1102
1103                 if (p->status == wil_sta_connected) {
1104                         rc = wil_cid_fill_sinfo(wil, i, &sinfo);
1105                         if (rc)
1106                                 return rc;
1107
1108                         seq_printf(s, "  Tx_mcs = %d\n", sinfo.txrate.mcs);
1109                         seq_printf(s, "  Rx_mcs = %d\n", sinfo.rxrate.mcs);
1110                         seq_printf(s, "  SQ     = %d\n", sinfo.signal);
1111                 }
1112         }
1113
1114         return 0;
1115 }
1116
1117 static int wil_link_seq_open(struct inode *inode, struct file *file)
1118 {
1119         return single_open(file, wil_link_debugfs_show, inode->i_private);
1120 }
1121
1122 static const struct file_operations fops_link = {
1123         .open           = wil_link_seq_open,
1124         .release        = single_release,
1125         .read           = seq_read,
1126         .llseek         = seq_lseek,
1127 };
1128
1129 /*---------info------------*/
1130 static int wil_info_debugfs_show(struct seq_file *s, void *data)
1131 {
1132         struct wil6210_priv *wil = s->private;
1133         struct net_device *ndev = wil_to_ndev(wil);
1134         int is_ac = power_supply_is_system_supplied();
1135         int rx = atomic_xchg(&wil->isr_count_rx, 0);
1136         int tx = atomic_xchg(&wil->isr_count_tx, 0);
1137         static ulong rxf_old, txf_old;
1138         ulong rxf = ndev->stats.rx_packets;
1139         ulong txf = ndev->stats.tx_packets;
1140         unsigned int i;
1141
1142         /* >0 : AC; 0 : battery; <0 : error */
1143         seq_printf(s, "AC powered : %d\n", is_ac);
1144         seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
1145         seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
1146         rxf_old = rxf;
1147         txf_old = txf;
1148
1149 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1150         " " __stringify(x) : ""
1151
1152         for (i = 0; i < ndev->num_tx_queues; i++) {
1153                 struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
1154                 unsigned long state = txq->state;
1155
1156                 seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
1157                            CHECK_QSTATE(DRV_XOFF),
1158                            CHECK_QSTATE(STACK_XOFF),
1159                            CHECK_QSTATE(FROZEN)
1160                           );
1161         }
1162 #undef CHECK_QSTATE
1163         return 0;
1164 }
1165
1166 static int wil_info_seq_open(struct inode *inode, struct file *file)
1167 {
1168         return single_open(file, wil_info_debugfs_show, inode->i_private);
1169 }
1170
1171 static const struct file_operations fops_info = {
1172         .open           = wil_info_seq_open,
1173         .release        = single_release,
1174         .read           = seq_read,
1175         .llseek         = seq_lseek,
1176 };
1177
1178 /*---------recovery------------*/
1179 /* mode = [manual|auto]
1180  * state = [idle|pending|running]
1181  */
1182 static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
1183                                       size_t count, loff_t *ppos)
1184 {
1185         struct wil6210_priv *wil = file->private_data;
1186         char buf[80];
1187         int n;
1188         static const char * const sstate[] = {"idle", "pending", "running"};
1189
1190         n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
1191                      no_fw_recovery ? "manual" : "auto",
1192                      sstate[wil->recovery_state]);
1193
1194         n = min_t(int, n, sizeof(buf));
1195
1196         return simple_read_from_buffer(user_buf, count, ppos,
1197                                        buf, n);
1198 }
1199
1200 static ssize_t wil_write_file_recovery(struct file *file,
1201                                        const char __user *buf_,
1202                                        size_t count, loff_t *ppos)
1203 {
1204         struct wil6210_priv *wil = file->private_data;
1205         static const char run_command[] = "run";
1206         char buf[sizeof(run_command) + 1]; /* to detect "runx" */
1207         ssize_t rc;
1208
1209         if (wil->recovery_state != fw_recovery_pending) {
1210                 wil_err(wil, "No recovery pending\n");
1211                 return -EINVAL;
1212         }
1213
1214         if (*ppos != 0) {
1215                 wil_err(wil, "Offset [%d]\n", (int)*ppos);
1216                 return -EINVAL;
1217         }
1218
1219         if (count > sizeof(buf)) {
1220                 wil_err(wil, "Input too long, len = %d\n", (int)count);
1221                 return -EINVAL;
1222         }
1223
1224         rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
1225         if (rc < 0)
1226                 return rc;
1227
1228         buf[rc] = '\0';
1229         if (0 == strcmp(buf, run_command))
1230                 wil_set_recovery_state(wil, fw_recovery_running);
1231         else
1232                 wil_err(wil, "Bad recovery command \"%s\"\n", buf);
1233
1234         return rc;
1235 }
1236
1237 static const struct file_operations fops_recovery = {
1238         .read = wil_read_file_recovery,
1239         .write = wil_write_file_recovery,
1240         .open  = simple_open,
1241 };
1242
1243 /*---------Station matrix------------*/
1244 static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
1245 {
1246         int i;
1247         u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
1248
1249         seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout,
1250                    r->head_seq_num);
1251         for (i = 0; i < r->buf_size; i++) {
1252                 if (i == index)
1253                         seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
1254                 else
1255                         seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
1256         }
1257         seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop);
1258 }
1259
1260 static int wil_sta_debugfs_show(struct seq_file *s, void *data)
1261 __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1262 {
1263         struct wil6210_priv *wil = s->private;
1264         int i, tid;
1265
1266         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1267                 struct wil_sta_info *p = &wil->sta[i];
1268                 char *status = "unknown";
1269
1270                 switch (p->status) {
1271                 case wil_sta_unused:
1272                         status = "unused   ";
1273                         break;
1274                 case wil_sta_conn_pending:
1275                         status = "pending  ";
1276                         break;
1277                 case wil_sta_connected:
1278                         status = "connected";
1279                         break;
1280                 }
1281                 seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
1282                            (p->data_port_open ? " data_port_open" : ""));
1283
1284                 if (p->status == wil_sta_connected) {
1285                         spin_lock_bh(&p->tid_rx_lock);
1286                         for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
1287                                 struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
1288
1289                                 if (r) {
1290                                         seq_printf(s, "[%2d] ", tid);
1291                                         wil_print_rxtid(s, r);
1292                                 }
1293                         }
1294                         spin_unlock_bh(&p->tid_rx_lock);
1295                 }
1296         }
1297
1298         return 0;
1299 }
1300
1301 static int wil_sta_seq_open(struct inode *inode, struct file *file)
1302 {
1303         return single_open(file, wil_sta_debugfs_show, inode->i_private);
1304 }
1305
1306 static const struct file_operations fops_sta = {
1307         .open           = wil_sta_seq_open,
1308         .release        = single_release,
1309         .read           = seq_read,
1310         .llseek         = seq_lseek,
1311 };
1312
1313 /*----------------*/
1314 static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
1315                                        struct dentry *dbg)
1316 {
1317         int i;
1318         char name[32];
1319
1320         for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
1321                 struct debugfs_blob_wrapper *blob = &wil->blobs[i];
1322                 const struct fw_map *map = &fw_mapping[i];
1323
1324                 if (!map->name)
1325                         continue;
1326
1327                 blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
1328                 blob->size = map->to - map->from;
1329                 snprintf(name, sizeof(name), "blob_%s", map->name);
1330                 wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob);
1331         }
1332 }
1333
1334 /* misc files */
1335 static const struct {
1336         const char *name;
1337         umode_t mode;
1338         const struct file_operations *fops;
1339 } dbg_files[] = {
1340         {"mbox",        S_IRUGO,                &fops_mbox},
1341         {"vrings",      S_IRUGO,                &fops_vring},
1342         {"stations",    S_IRUGO,                &fops_sta},
1343         {"desc",        S_IRUGO,                &fops_txdesc},
1344         {"bf",          S_IRUGO,                &fops_bf},
1345         {"ssid",        S_IRUGO | S_IWUSR,      &fops_ssid},
1346         {"mem_val",     S_IRUGO,                &fops_memread},
1347         {"reset",                 S_IWUSR,      &fops_reset},
1348         {"rxon",                  S_IWUSR,      &fops_rxon},
1349         {"tx_mgmt",               S_IWUSR,      &fops_txmgmt},
1350         {"wmi_send",              S_IWUSR,      &fops_wmi},
1351         {"back",        S_IRUGO | S_IWUSR,      &fops_back},
1352         {"temp",        S_IRUGO,                &fops_temp},
1353         {"freq",        S_IRUGO,                &fops_freq},
1354         {"link",        S_IRUGO,                &fops_link},
1355         {"info",        S_IRUGO,                &fops_info},
1356         {"recovery",    S_IRUGO | S_IWUSR,      &fops_recovery},
1357 };
1358
1359 static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
1360                                        struct dentry *dbg)
1361 {
1362         int i;
1363
1364         for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
1365                 debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
1366                                     wil, dbg_files[i].fops);
1367 }
1368
1369 /* interrupt control blocks */
1370 static const struct {
1371         const char *name;
1372         u32 icr_off;
1373 } dbg_icr[] = {
1374         {"USER_ICR",            HOSTADDR(RGF_USER_USER_ICR)},
1375         {"DMA_EP_TX_ICR",       HOSTADDR(RGF_DMA_EP_TX_ICR)},
1376         {"DMA_EP_RX_ICR",       HOSTADDR(RGF_DMA_EP_RX_ICR)},
1377         {"DMA_EP_MISC_ICR",     HOSTADDR(RGF_DMA_EP_MISC_ICR)},
1378 };
1379
1380 static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
1381                                      struct dentry *dbg)
1382 {
1383         int i;
1384
1385         for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
1386                 wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
1387                                            dbg_icr[i].icr_off);
1388 }
1389
1390 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
1391         offsetof(struct wil6210_priv, name), type}
1392
1393 /* fields in struct wil6210_priv */
1394 static const struct dbg_off dbg_wil_off[] = {
1395         WIL_FIELD(secure_pcp,   S_IRUGO | S_IWUSR,      doff_u32),
1396         WIL_FIELD(status[0],    S_IRUGO | S_IWUSR,      doff_ulong),
1397         WIL_FIELD(fw_version,   S_IRUGO,                doff_u32),
1398         WIL_FIELD(hw_version,   S_IRUGO,                doff_x32),
1399         WIL_FIELD(recovery_count, S_IRUGO,              doff_u32),
1400         {},
1401 };
1402
1403 static const struct dbg_off dbg_wil_regs[] = {
1404         {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
1405                 doff_io32},
1406         {"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
1407         {},
1408 };
1409
1410 /* static parameters */
1411 static const struct dbg_off dbg_statics[] = {
1412         {"desc_index",  S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
1413         {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
1414         {"mem_addr",    S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
1415         {},
1416 };
1417
1418 int wil6210_debugfs_init(struct wil6210_priv *wil)
1419 {
1420         struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
1421                         wil_to_wiphy(wil)->debugfsdir);
1422
1423         if (IS_ERR_OR_NULL(dbg))
1424                 return -ENODEV;
1425
1426         wil6210_debugfs_init_files(wil, dbg);
1427         wil6210_debugfs_init_isr(wil, dbg);
1428         wil6210_debugfs_init_blobs(wil, dbg);
1429         wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
1430         wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
1431                                     dbg_wil_regs);
1432         wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
1433
1434         wil6210_debugfs_create_pseudo_ISR(wil, dbg);
1435
1436         wil6210_debugfs_create_ITR_CNT(wil, dbg);
1437
1438         return 0;
1439 }
1440
1441 void wil6210_debugfs_remove(struct wil6210_priv *wil)
1442 {
1443         debugfs_remove_recursive(wil->debug);
1444         wil->debug = NULL;
1445 }