]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/ath/wil6210/debugfs.c
Merge branch 'hpfs' (patches from Mikulas)
[karo-tx-linux.git] / drivers / net / wireless / ath / wil6210 / debugfs.c
1 /*
2  * Copyright (c) 2012-2015 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 #include "pmc.h"
28
29 /* Nasty hack. Better have per device instances */
30 static u32 mem_addr;
31 static u32 dbg_txdesc_index;
32 static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
33 u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */
34
35 enum dbg_off_type {
36         doff_u32 = 0,
37         doff_x32 = 1,
38         doff_ulong = 2,
39         doff_io32 = 3,
40 };
41
42 /* offset to "wil" */
43 struct dbg_off {
44         const char *name;
45         umode_t mode;
46         ulong off;
47         enum dbg_off_type type;
48 };
49
50 static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
51                             const char *name, struct vring *vring,
52                             char _s, char _h)
53 {
54         void __iomem *x = wmi_addr(wil, vring->hwtail);
55         u32 v;
56
57         seq_printf(s, "VRING %s = {\n", name);
58         seq_printf(s, "  pa     = %pad\n", &vring->pa);
59         seq_printf(s, "  va     = 0x%p\n", vring->va);
60         seq_printf(s, "  size   = %d\n", vring->size);
61         seq_printf(s, "  swtail = %d\n", vring->swtail);
62         seq_printf(s, "  swhead = %d\n", vring->swhead);
63         seq_printf(s, "  hwtail = [0x%08x] -> ", vring->hwtail);
64         if (x) {
65                 v = readl(x);
66                 seq_printf(s, "0x%08x = %d\n", v, v);
67         } else {
68                 seq_puts(s, "???\n");
69         }
70
71         if (vring->va && (vring->size < 1025)) {
72                 uint i;
73
74                 for (i = 0; i < vring->size; i++) {
75                         volatile struct vring_tx_desc *d = &vring->va[i].tx;
76
77                         if ((i % 64) == 0 && (i != 0))
78                                 seq_puts(s, "\n");
79                         seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
80                                         _s : (vring->ctx[i].skb ? _h : 'h'));
81                 }
82                 seq_puts(s, "\n");
83         }
84         seq_puts(s, "}\n");
85 }
86
87 static int wil_vring_debugfs_show(struct seq_file *s, void *data)
88 {
89         uint i;
90         struct wil6210_priv *wil = s->private;
91
92         wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
93
94         for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
95                 struct vring *vring = &wil->vring_tx[i];
96                 struct vring_tx_data *txdata = &wil->vring_tx_data[i];
97
98                 if (vring->va) {
99                         int cid = wil->vring2cid_tid[i][0];
100                         int tid = wil->vring2cid_tid[i][1];
101                         u32 swhead = vring->swhead;
102                         u32 swtail = vring->swtail;
103                         int used = (vring->size + swhead - swtail)
104                                    % vring->size;
105                         int avail = vring->size - used - 1;
106                         char name[10];
107                         char sidle[10];
108                         /* performance monitoring */
109                         cycles_t now = get_cycles();
110                         uint64_t idle = txdata->idle * 100;
111                         uint64_t total = now - txdata->begin;
112
113                         if (total != 0) {
114                                 do_div(idle, total);
115                                 snprintf(sidle, sizeof(sidle), "%3d%%",
116                                          (int)idle);
117                         } else {
118                                 snprintf(sidle, sizeof(sidle), "N/A");
119                         }
120                         txdata->begin = now;
121                         txdata->idle = 0ULL;
122
123                         snprintf(name, sizeof(name), "tx_%2d", i);
124
125                         if (cid < WIL6210_MAX_CID)
126                                 seq_printf(s,
127                                            "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
128                                            wil->sta[cid].addr, cid, tid,
129                                            txdata->dot1x_open ? "+" : "-",
130                                            txdata->agg_wsize,
131                                            txdata->agg_timeout,
132                                            txdata->agg_amsdu ? "+" : "-",
133                                            used, avail, sidle);
134                         else
135                                 seq_printf(s,
136                                            "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
137                                            txdata->dot1x_open ? "+" : "-",
138                                            used, avail, sidle);
139
140                         wil_print_vring(s, wil, name, vring, '_', 'H');
141                 }
142         }
143
144         return 0;
145 }
146
147 static int wil_vring_seq_open(struct inode *inode, struct file *file)
148 {
149         return single_open(file, wil_vring_debugfs_show, inode->i_private);
150 }
151
152 static const struct file_operations fops_vring = {
153         .open           = wil_vring_seq_open,
154         .release        = single_release,
155         .read           = seq_read,
156         .llseek         = seq_lseek,
157 };
158
159 static void wil_print_ring(struct seq_file *s, const char *prefix,
160                            void __iomem *off)
161 {
162         struct wil6210_priv *wil = s->private;
163         struct wil6210_mbox_ring r;
164         int rsize;
165         uint i;
166
167         wil_memcpy_fromio_32(&r, off, sizeof(r));
168         wil_mbox_ring_le2cpus(&r);
169         /*
170          * we just read memory block from NIC. This memory may be
171          * garbage. Check validity before using it.
172          */
173         rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
174
175         seq_printf(s, "ring %s = {\n", prefix);
176         seq_printf(s, "  base = 0x%08x\n", r.base);
177         seq_printf(s, "  size = 0x%04x bytes -> %d entries\n", r.size, rsize);
178         seq_printf(s, "  tail = 0x%08x\n", r.tail);
179         seq_printf(s, "  head = 0x%08x\n", r.head);
180         seq_printf(s, "  entry size = %d\n", r.entry_size);
181
182         if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
183                 seq_printf(s, "  ??? size is not multiple of %zd, garbage?\n",
184                            sizeof(struct wil6210_mbox_ring_desc));
185                 goto out;
186         }
187
188         if (!wmi_addr(wil, r.base) ||
189             !wmi_addr(wil, r.tail) ||
190             !wmi_addr(wil, r.head)) {
191                 seq_puts(s, "  ??? pointers are garbage?\n");
192                 goto out;
193         }
194
195         for (i = 0; i < rsize; i++) {
196                 struct wil6210_mbox_ring_desc d;
197                 struct wil6210_mbox_hdr hdr;
198                 size_t delta = i * sizeof(d);
199                 void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
200
201                 wil_memcpy_fromio_32(&d, x, sizeof(d));
202
203                 seq_printf(s, "  [%2x] %s %s%s 0x%08x", i,
204                            d.sync ? "F" : "E",
205                            (r.tail - r.base == delta) ? "t" : " ",
206                            (r.head - r.base == delta) ? "h" : " ",
207                            le32_to_cpu(d.addr));
208                 if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
209                         u16 len = le16_to_cpu(hdr.len);
210
211                         seq_printf(s, " -> %04x %04x %04x %02x\n",
212                                    le16_to_cpu(hdr.seq), len,
213                                    le16_to_cpu(hdr.type), hdr.flags);
214                         if (len <= MAX_MBOXITEM_SIZE) {
215                                 int n = 0;
216                                 char printbuf[16 * 3 + 2];
217                                 unsigned char databuf[MAX_MBOXITEM_SIZE];
218                                 void __iomem *src = wmi_buffer(wil, d.addr) +
219                                         sizeof(struct wil6210_mbox_hdr);
220                                 /*
221                                  * No need to check @src for validity -
222                                  * we already validated @d.addr while
223                                  * reading header
224                                  */
225                                 wil_memcpy_fromio_32(databuf, src, len);
226                                 while (n < len) {
227                                         int l = min(len - n, 16);
228
229                                         hex_dump_to_buffer(databuf + n, l,
230                                                            16, 1, printbuf,
231                                                            sizeof(printbuf),
232                                                            false);
233                                         seq_printf(s, "      : %s\n", printbuf);
234                                         n += l;
235                                 }
236                         }
237                 } else {
238                         seq_puts(s, "\n");
239                 }
240         }
241  out:
242         seq_puts(s, "}\n");
243 }
244
245 static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
246 {
247         struct wil6210_priv *wil = s->private;
248
249         wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
250                        offsetof(struct wil6210_mbox_ctl, tx));
251         wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
252                        offsetof(struct wil6210_mbox_ctl, rx));
253
254         return 0;
255 }
256
257 static int wil_mbox_seq_open(struct inode *inode, struct file *file)
258 {
259         return single_open(file, wil_mbox_debugfs_show, inode->i_private);
260 }
261
262 static const struct file_operations fops_mbox = {
263         .open           = wil_mbox_seq_open,
264         .release        = single_release,
265         .read           = seq_read,
266         .llseek         = seq_lseek,
267 };
268
269 static int wil_debugfs_iomem_x32_set(void *data, u64 val)
270 {
271         writel(val, (void __iomem *)data);
272         wmb(); /* make sure write propagated to HW */
273
274         return 0;
275 }
276
277 static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
278 {
279         *val = readl((void __iomem *)data);
280
281         return 0;
282 }
283
284 DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
285                         wil_debugfs_iomem_x32_set, "0x%08llx\n");
286
287 static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
288                                                    umode_t mode,
289                                                    struct dentry *parent,
290                                                    void *value)
291 {
292         return debugfs_create_file(name, mode, parent, value,
293                                    &fops_iomem_x32);
294 }
295
296 static int wil_debugfs_ulong_set(void *data, u64 val)
297 {
298         *(ulong *)data = val;
299         return 0;
300 }
301
302 static int wil_debugfs_ulong_get(void *data, u64 *val)
303 {
304         *val = *(ulong *)data;
305         return 0;
306 }
307
308 DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
309                         wil_debugfs_ulong_set, "0x%llx\n");
310
311 static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
312                                                struct dentry *parent,
313                                                ulong *value)
314 {
315         return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
316 }
317
318 /**
319  * wil6210_debugfs_init_offset - create set of debugfs files
320  * @wil - driver's context, used for printing
321  * @dbg - directory on the debugfs, where files will be created
322  * @base - base address used in address calculation
323  * @tbl - table with file descriptions. Should be terminated with empty element.
324  *
325  * Creates files accordingly to the @tbl.
326  */
327 static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
328                                         struct dentry *dbg, void *base,
329                                         const struct dbg_off * const tbl)
330 {
331         int i;
332
333         for (i = 0; tbl[i].name; i++) {
334                 struct dentry *f;
335
336                 switch (tbl[i].type) {
337                 case doff_u32:
338                         f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
339                                                base + tbl[i].off);
340                         break;
341                 case doff_x32:
342                         f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
343                                                base + tbl[i].off);
344                         break;
345                 case doff_ulong:
346                         f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
347                                                      dbg, base + tbl[i].off);
348                         break;
349                 case doff_io32:
350                         f = wil_debugfs_create_iomem_x32(tbl[i].name,
351                                                          tbl[i].mode, dbg,
352                                                          base + tbl[i].off);
353                         break;
354                 default:
355                         f = ERR_PTR(-EINVAL);
356                 }
357                 if (IS_ERR_OR_NULL(f))
358                         wil_err(wil, "Create file \"%s\": err %ld\n",
359                                 tbl[i].name, PTR_ERR(f));
360         }
361 }
362
363 static const struct dbg_off isr_off[] = {
364         {"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
365         {"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
366         {"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
367         {"ICS",           S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
368         {"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
369         {"IMS",           S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
370         {"IMC",           S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
371         {},
372 };
373
374 static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
375                                       const char *name,
376                                       struct dentry *parent, u32 off)
377 {
378         struct dentry *d = debugfs_create_dir(name, parent);
379
380         if (IS_ERR_OR_NULL(d))
381                 return -ENODEV;
382
383         wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
384                                     isr_off);
385
386         return 0;
387 }
388
389 static const struct dbg_off pseudo_isr_off[] = {
390         {"CAUSE",   S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
391         {"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
392         {"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
393         {},
394 };
395
396 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
397                                              struct dentry *parent)
398 {
399         struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
400
401         if (IS_ERR_OR_NULL(d))
402                 return -ENODEV;
403
404         wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
405                                     pseudo_isr_off);
406
407         return 0;
408 }
409
410 static const struct dbg_off lgc_itr_cnt_off[] = {
411         {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
412         {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
413         {"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
414         {},
415 };
416
417 static const struct dbg_off tx_itr_cnt_off[] = {
418         {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
419          doff_io32},
420         {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
421          doff_io32},
422         {"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
423          doff_io32},
424         {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
425          doff_io32},
426         {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
427          doff_io32},
428         {"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
429          doff_io32},
430         {},
431 };
432
433 static const struct dbg_off rx_itr_cnt_off[] = {
434         {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
435          doff_io32},
436         {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
437          doff_io32},
438         {"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
439          doff_io32},
440         {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
441          doff_io32},
442         {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
443          doff_io32},
444         {"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
445          doff_io32},
446         {},
447 };
448
449 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
450                                           struct dentry *parent)
451 {
452         struct dentry *d, *dtx, *drx;
453
454         d = debugfs_create_dir("ITR_CNT", parent);
455         if (IS_ERR_OR_NULL(d))
456                 return -ENODEV;
457
458         dtx = debugfs_create_dir("TX", d);
459         drx = debugfs_create_dir("RX", d);
460         if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
461                 return -ENODEV;
462
463         wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
464                                     lgc_itr_cnt_off);
465
466         wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
467                                     tx_itr_cnt_off);
468
469         wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
470                                     rx_itr_cnt_off);
471         return 0;
472 }
473
474 static int wil_memread_debugfs_show(struct seq_file *s, void *data)
475 {
476         struct wil6210_priv *wil = s->private;
477         void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
478
479         if (a)
480                 seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a));
481         else
482                 seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
483
484         return 0;
485 }
486
487 static int wil_memread_seq_open(struct inode *inode, struct file *file)
488 {
489         return single_open(file, wil_memread_debugfs_show, inode->i_private);
490 }
491
492 static const struct file_operations fops_memread = {
493         .open           = wil_memread_seq_open,
494         .release        = single_release,
495         .read           = seq_read,
496         .llseek         = seq_lseek,
497 };
498
499 static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
500                                     size_t count, loff_t *ppos)
501 {
502         enum { max_count = 4096 };
503         struct debugfs_blob_wrapper *blob = file->private_data;
504         loff_t pos = *ppos;
505         size_t available = blob->size;
506         void *buf;
507         size_t ret;
508
509         if (pos < 0)
510                 return -EINVAL;
511
512         if (pos >= available || !count)
513                 return 0;
514
515         if (count > available - pos)
516                 count = available - pos;
517         if (count > max_count)
518                 count = max_count;
519
520         buf = kmalloc(count, GFP_KERNEL);
521         if (!buf)
522                 return -ENOMEM;
523
524         wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data +
525                              pos, count);
526
527         ret = copy_to_user(user_buf, buf, count);
528         kfree(buf);
529         if (ret == count)
530                 return -EFAULT;
531
532         count -= ret;
533         *ppos = pos + count;
534
535         return count;
536 }
537
538 static const struct file_operations fops_ioblob = {
539         .read =         wil_read_file_ioblob,
540         .open =         simple_open,
541         .llseek =       default_llseek,
542 };
543
544 static
545 struct dentry *wil_debugfs_create_ioblob(const char *name,
546                                          umode_t mode,
547                                          struct dentry *parent,
548                                          struct debugfs_blob_wrapper *blob)
549 {
550         return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
551 }
552
553 /*---reset---*/
554 static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
555                                     size_t len, loff_t *ppos)
556 {
557         struct wil6210_priv *wil = file->private_data;
558         struct net_device *ndev = wil_to_ndev(wil);
559
560         /**
561          * BUG:
562          * this code does NOT sync device state with the rest of system
563          * use with care, debug only!!!
564          */
565         rtnl_lock();
566         dev_close(ndev);
567         ndev->flags &= ~IFF_UP;
568         rtnl_unlock();
569         wil_reset(wil, true);
570
571         return len;
572 }
573
574 static const struct file_operations fops_reset = {
575         .write = wil_write_file_reset,
576         .open  = simple_open,
577 };
578
579 /*---write channel 1..4 to rxon for it, 0 to rxoff---*/
580 static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
581                                    size_t len, loff_t *ppos)
582 {
583         struct wil6210_priv *wil = file->private_data;
584         int rc;
585         long channel;
586         bool on;
587
588         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
589
590         if (!kbuf)
591                 return -ENOMEM;
592         if (copy_from_user(kbuf, buf, len)) {
593                 kfree(kbuf);
594                 return -EIO;
595         }
596
597         kbuf[len] = '\0';
598         rc = kstrtol(kbuf, 0, &channel);
599         kfree(kbuf);
600         if (rc)
601                 return rc;
602
603         if ((channel < 0) || (channel > 4)) {
604                 wil_err(wil, "Invalid channel %ld\n", channel);
605                 return -EINVAL;
606         }
607         on = !!channel;
608
609         if (on) {
610                 rc = wmi_set_channel(wil, (int)channel);
611                 if (rc)
612                         return rc;
613         }
614
615         rc = wmi_rxon(wil, on);
616         if (rc)
617                 return rc;
618
619         return len;
620 }
621
622 static const struct file_operations fops_rxon = {
623         .write = wil_write_file_rxon,
624         .open  = simple_open,
625 };
626
627 /* block ack control, write:
628  * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
629  * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
630  * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
631  */
632 static ssize_t wil_write_back(struct file *file, const char __user *buf,
633                               size_t len, loff_t *ppos)
634 {
635         struct wil6210_priv *wil = file->private_data;
636         int rc;
637         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
638         char cmd[9];
639         int p1, p2, p3;
640
641         if (!kbuf)
642                 return -ENOMEM;
643
644         rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
645         if (rc != len) {
646                 kfree(kbuf);
647                 return rc >= 0 ? -EIO : rc;
648         }
649
650         kbuf[len] = '\0';
651         rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
652         kfree(kbuf);
653
654         if (rc < 0)
655                 return rc;
656         if (rc < 2)
657                 return -EINVAL;
658
659         if (0 == strcmp(cmd, "add")) {
660                 if (rc < 3) {
661                         wil_err(wil, "BACK: add require at least 2 params\n");
662                         return -EINVAL;
663                 }
664                 if (rc < 4)
665                         p3 = 0;
666                 wmi_addba(wil, p1, p2, p3);
667         } else if (0 == strcmp(cmd, "del_tx")) {
668                 if (rc < 3)
669                         p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
670                 wmi_delba_tx(wil, p1, p2);
671         } else if (0 == strcmp(cmd, "del_rx")) {
672                 if (rc < 3) {
673                         wil_err(wil,
674                                 "BACK: del_rx require at least 2 params\n");
675                         return -EINVAL;
676                 }
677                 if (rc < 4)
678                         p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
679                 wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
680         } else {
681                 wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
682                 return -EINVAL;
683         }
684
685         return len;
686 }
687
688 static ssize_t wil_read_back(struct file *file, char __user *user_buf,
689                              size_t count, loff_t *ppos)
690 {
691         static const char text[] = "block ack control, write:\n"
692         " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
693         "If missing, <timeout> defaults to 0\n"
694         " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
695         " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
696         "If missing, <reason> set to \"STA_LEAVING\" (36)\n";
697
698         return simple_read_from_buffer(user_buf, count, ppos, text,
699                                        sizeof(text));
700 }
701
702 static const struct file_operations fops_back = {
703         .read = wil_read_back,
704         .write = wil_write_back,
705         .open  = simple_open,
706 };
707
708 /* pmc control, write:
709  * - "alloc <num descriptors> <descriptor_size>" to allocate PMC
710  * - "free" to release memory allocated for PMC
711  */
712 static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf,
713                                 size_t len, loff_t *ppos)
714 {
715         struct wil6210_priv *wil = file->private_data;
716         int rc;
717         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
718         char cmd[9];
719         int num_descs, desc_size;
720
721         if (!kbuf)
722                 return -ENOMEM;
723
724         rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
725         if (rc != len) {
726                 kfree(kbuf);
727                 return rc >= 0 ? -EIO : rc;
728         }
729
730         kbuf[len] = '\0';
731         rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size);
732         kfree(kbuf);
733
734         if (rc < 0)
735                 return rc;
736
737         if (rc < 1) {
738                 wil_err(wil, "pmccfg: no params given\n");
739                 return -EINVAL;
740         }
741
742         if (0 == strcmp(cmd, "alloc")) {
743                 if (rc != 3) {
744                         wil_err(wil, "pmccfg: alloc requires 2 params\n");
745                         return -EINVAL;
746                 }
747                 wil_pmc_alloc(wil, num_descs, desc_size);
748         } else if (0 == strcmp(cmd, "free")) {
749                 if (rc != 1) {
750                         wil_err(wil, "pmccfg: free does not have any params\n");
751                         return -EINVAL;
752                 }
753                 wil_pmc_free(wil, true);
754         } else {
755                 wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd);
756                 return -EINVAL;
757         }
758
759         return len;
760 }
761
762 static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf,
763                                size_t count, loff_t *ppos)
764 {
765         struct wil6210_priv *wil = file->private_data;
766         char text[256];
767         char help[] = "pmc control, write:\n"
768         " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
769         " - \"free\" to free memory allocated for pmc\n";
770
771         sprintf(text, "Last command status: %d\n\n%s",
772                 wil_pmc_last_cmd_status(wil),
773                 help);
774
775         return simple_read_from_buffer(user_buf, count, ppos, text,
776                                        strlen(text) + 1);
777 }
778
779 static const struct file_operations fops_pmccfg = {
780         .read = wil_read_pmccfg,
781         .write = wil_write_pmccfg,
782         .open  = simple_open,
783 };
784
785 static const struct file_operations fops_pmcdata = {
786         .open           = simple_open,
787         .read           = wil_pmc_read,
788         .llseek         = wil_pmc_llseek,
789 };
790
791 /*---tx_mgmt---*/
792 /* Write mgmt frame to this file to send it */
793 static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
794                                      size_t len, loff_t *ppos)
795 {
796         struct wil6210_priv *wil = file->private_data;
797         struct wiphy *wiphy = wil_to_wiphy(wil);
798         struct wireless_dev *wdev = wil_to_wdev(wil);
799         struct cfg80211_mgmt_tx_params params;
800         int rc;
801         void *frame = kmalloc(len, GFP_KERNEL);
802
803         if (!frame)
804                 return -ENOMEM;
805
806         if (copy_from_user(frame, buf, len)) {
807                 kfree(frame);
808                 return -EIO;
809         }
810
811         params.buf = frame;
812         params.len = len;
813         params.chan = wdev->preset_chandef.chan;
814
815         rc = wil_cfg80211_mgmt_tx(wiphy, wdev, &params, NULL);
816
817         kfree(frame);
818         wil_info(wil, "%s() -> %d\n", __func__, rc);
819
820         return len;
821 }
822
823 static const struct file_operations fops_txmgmt = {
824         .write = wil_write_file_txmgmt,
825         .open  = simple_open,
826 };
827
828 /* Write WMI command (w/o mbox header) to this file to send it
829  * WMI starts from wil6210_mbox_hdr_wmi header
830  */
831 static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
832                                   size_t len, loff_t *ppos)
833 {
834         struct wil6210_priv *wil = file->private_data;
835         struct wil6210_mbox_hdr_wmi *wmi;
836         void *cmd;
837         int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi);
838         u16 cmdid;
839         int rc, rc1;
840
841         if (cmdlen <= 0)
842                 return -EINVAL;
843
844         wmi = kmalloc(len, GFP_KERNEL);
845         if (!wmi)
846                 return -ENOMEM;
847
848         rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
849         if (rc < 0) {
850                 kfree(wmi);
851                 return rc;
852         }
853
854         cmd = &wmi[1];
855         cmdid = le16_to_cpu(wmi->id);
856
857         rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
858         kfree(wmi);
859
860         wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1);
861
862         return rc;
863 }
864
865 static const struct file_operations fops_wmi = {
866         .write = wil_write_file_wmi,
867         .open  = simple_open,
868 };
869
870 static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
871                             const char *prefix)
872 {
873         char printbuf[16 * 3 + 2];
874         int i = 0;
875
876         while (i < len) {
877                 int l = min(len - i, 16);
878
879                 hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
880                                    sizeof(printbuf), false);
881                 seq_printf(s, "%s%s\n", prefix, printbuf);
882                 i += l;
883         }
884 }
885
886 static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
887 {
888         int i = 0;
889         int len = skb_headlen(skb);
890         void *p = skb->data;
891         int nr_frags = skb_shinfo(skb)->nr_frags;
892
893         seq_printf(s, "    len = %d\n", len);
894         wil_seq_hexdump(s, p, len, "      : ");
895
896         if (nr_frags) {
897                 seq_printf(s, "    nr_frags = %d\n", nr_frags);
898                 for (i = 0; i < nr_frags; i++) {
899                         const struct skb_frag_struct *frag =
900                                         &skb_shinfo(skb)->frags[i];
901
902                         len = skb_frag_size(frag);
903                         p = skb_frag_address_safe(frag);
904                         seq_printf(s, "    [%2d] : len = %d\n", i, len);
905                         wil_seq_hexdump(s, p, len, "      : ");
906                 }
907         }
908 }
909
910 /*---------Tx/Rx descriptor------------*/
911 static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
912 {
913         struct wil6210_priv *wil = s->private;
914         struct vring *vring;
915         bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
916
917         vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
918
919         if (!vring->va) {
920                 if (tx)
921                         seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index);
922                 else
923                         seq_puts(s, "No Rx VRING\n");
924                 return 0;
925         }
926
927         if (dbg_txdesc_index < vring->size) {
928                 /* use struct vring_tx_desc for Rx as well,
929                  * only field used, .dma.length, is the same
930                  */
931                 volatile struct vring_tx_desc *d =
932                                 &vring->va[dbg_txdesc_index].tx;
933                 volatile u32 *u = (volatile u32 *)d;
934                 struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
935
936                 if (tx)
937                         seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index,
938                                    dbg_txdesc_index);
939                 else
940                         seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);
941                 seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
942                            u[0], u[1], u[2], u[3]);
943                 seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
944                            u[4], u[5], u[6], u[7]);
945                 seq_printf(s, "  SKB = 0x%p\n", skb);
946
947                 if (skb) {
948                         skb_get(skb);
949                         wil_seq_print_skb(s, skb);
950                         kfree_skb(skb);
951                 }
952                 seq_puts(s, "}\n");
953         } else {
954                 if (tx)
955                         seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
956                                    dbg_vring_index, dbg_txdesc_index,
957                                    vring->size);
958                 else
959                         seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
960                                    dbg_txdesc_index, vring->size);
961         }
962
963         return 0;
964 }
965
966 static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
967 {
968         return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
969 }
970
971 static const struct file_operations fops_txdesc = {
972         .open           = wil_txdesc_seq_open,
973         .release        = single_release,
974         .read           = seq_read,
975         .llseek         = seq_lseek,
976 };
977
978 /*---------beamforming------------*/
979 static char *wil_bfstatus_str(u32 status)
980 {
981         switch (status) {
982         case 0:
983                 return "Failed";
984         case 1:
985                 return "OK";
986         case 2:
987                 return "Retrying";
988         default:
989                 return "??";
990         }
991 }
992
993 static bool is_all_zeros(void * const x_, size_t sz)
994 {
995         /* if reply is all-0, ignore this CID */
996         u32 *x = x_;
997         int n;
998
999         for (n = 0; n < sz / sizeof(*x); n++)
1000                 if (x[n])
1001                         return false;
1002
1003         return true;
1004 }
1005
1006 static int wil_bf_debugfs_show(struct seq_file *s, void *data)
1007 {
1008         int rc;
1009         int i;
1010         struct wil6210_priv *wil = s->private;
1011         struct wmi_notify_req_cmd cmd = {
1012                 .interval_usec = 0,
1013         };
1014         struct {
1015                 struct wil6210_mbox_hdr_wmi wmi;
1016                 struct wmi_notify_req_done_event evt;
1017         } __packed reply;
1018
1019         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1020                 u32 status;
1021
1022                 cmd.cid = i;
1023                 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
1024                               WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
1025                               sizeof(reply), 20);
1026                 /* if reply is all-0, ignore this CID */
1027                 if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
1028                         continue;
1029
1030                 status = le32_to_cpu(reply.evt.status);
1031                 seq_printf(s, "CID %d {\n"
1032                            "  TSF = 0x%016llx\n"
1033                            "  TxMCS = %2d TxTpt = %4d\n"
1034                            "  SQI = %4d\n"
1035                            "  Status = 0x%08x %s\n"
1036                            "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
1037                            "  Goodput(rx:tx) %4d:%4d\n"
1038                            "}\n",
1039                            i,
1040                            le64_to_cpu(reply.evt.tsf),
1041                            le16_to_cpu(reply.evt.bf_mcs),
1042                            le32_to_cpu(reply.evt.tx_tpt),
1043                            reply.evt.sqi,
1044                            status, wil_bfstatus_str(status),
1045                            le16_to_cpu(reply.evt.my_rx_sector),
1046                            le16_to_cpu(reply.evt.my_tx_sector),
1047                            le16_to_cpu(reply.evt.other_rx_sector),
1048                            le16_to_cpu(reply.evt.other_tx_sector),
1049                            le32_to_cpu(reply.evt.rx_goodput),
1050                            le32_to_cpu(reply.evt.tx_goodput));
1051         }
1052         return 0;
1053 }
1054
1055 static int wil_bf_seq_open(struct inode *inode, struct file *file)
1056 {
1057         return single_open(file, wil_bf_debugfs_show, inode->i_private);
1058 }
1059
1060 static const struct file_operations fops_bf = {
1061         .open           = wil_bf_seq_open,
1062         .release        = single_release,
1063         .read           = seq_read,
1064         .llseek         = seq_lseek,
1065 };
1066
1067 /*---------SSID------------*/
1068 static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
1069                                   size_t count, loff_t *ppos)
1070 {
1071         struct wil6210_priv *wil = file->private_data;
1072         struct wireless_dev *wdev = wil_to_wdev(wil);
1073
1074         return simple_read_from_buffer(user_buf, count, ppos,
1075                                        wdev->ssid, wdev->ssid_len);
1076 }
1077
1078 static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf,
1079                                    size_t count, loff_t *ppos)
1080 {
1081         struct wil6210_priv *wil = file->private_data;
1082         struct wireless_dev *wdev = wil_to_wdev(wil);
1083         struct net_device *ndev = wil_to_ndev(wil);
1084
1085         if (*ppos != 0) {
1086                 wil_err(wil, "Unable to set SSID substring from [%d]\n",
1087                         (int)*ppos);
1088                 return -EINVAL;
1089         }
1090
1091         if (count > sizeof(wdev->ssid)) {
1092                 wil_err(wil, "SSID too long, len = %d\n", (int)count);
1093                 return -EINVAL;
1094         }
1095         if (netif_running(ndev)) {
1096                 wil_err(wil, "Unable to change SSID on running interface\n");
1097                 return -EINVAL;
1098         }
1099
1100         wdev->ssid_len = count;
1101         return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos,
1102                                       buf, count);
1103 }
1104
1105 static const struct file_operations fops_ssid = {
1106         .read = wil_read_file_ssid,
1107         .write = wil_write_file_ssid,
1108         .open  = simple_open,
1109 };
1110
1111 /*---------temp------------*/
1112 static 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
1125 static 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
1142 static 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
1147 static 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------------*/
1155 static 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
1166 static 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
1171 static 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------------*/
1179 static 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
1216 static 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
1221 static 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------------*/
1229 static 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
1265 static 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
1270 static 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  */
1281 static 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
1299 static 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
1336 static 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------------*/
1343 static 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
1363 static int wil_sta_debugfs_show(struct seq_file *s, void *data)
1364 __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1365 {
1366         struct wil6210_priv *wil = s->private;
1367         int i, tid, mcs;
1368
1369         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1370                 struct wil_sta_info *p = &wil->sta[i];
1371                 char *status = "unknown";
1372
1373                 switch (p->status) {
1374                 case wil_sta_unused:
1375                         status = "unused   ";
1376                         break;
1377                 case wil_sta_conn_pending:
1378                         status = "pending  ";
1379                         break;
1380                 case wil_sta_connected:
1381                         status = "connected";
1382                         break;
1383                 }
1384                 seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
1385
1386                 if (p->status == wil_sta_connected) {
1387                         spin_lock_bh(&p->tid_rx_lock);
1388                         for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
1389                                 struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
1390
1391                                 if (r) {
1392                                         seq_printf(s, "[%2d] ", tid);
1393                                         wil_print_rxtid(s, r);
1394                                 }
1395                         }
1396                         spin_unlock_bh(&p->tid_rx_lock);
1397                         seq_puts(s, "Rx/MCS:");
1398                         for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
1399                              mcs++)
1400                                 seq_printf(s, " %lld",
1401                                            p->stats.rx_per_mcs[mcs]);
1402                         seq_puts(s, "\n");
1403                 }
1404         }
1405
1406         return 0;
1407 }
1408
1409 static int wil_sta_seq_open(struct inode *inode, struct file *file)
1410 {
1411         return single_open(file, wil_sta_debugfs_show, inode->i_private);
1412 }
1413
1414 static const struct file_operations fops_sta = {
1415         .open           = wil_sta_seq_open,
1416         .release        = single_release,
1417         .read           = seq_read,
1418         .llseek         = seq_lseek,
1419 };
1420
1421 /*----------------*/
1422 static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
1423                                        struct dentry *dbg)
1424 {
1425         int i;
1426         char name[32];
1427
1428         for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
1429                 struct debugfs_blob_wrapper *blob = &wil->blobs[i];
1430                 const struct fw_map *map = &fw_mapping[i];
1431
1432                 if (!map->name)
1433                         continue;
1434
1435                 blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
1436                 blob->size = map->to - map->from;
1437                 snprintf(name, sizeof(name), "blob_%s", map->name);
1438                 wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob);
1439         }
1440 }
1441
1442 /* misc files */
1443 static const struct {
1444         const char *name;
1445         umode_t mode;
1446         const struct file_operations *fops;
1447 } dbg_files[] = {
1448         {"mbox",        S_IRUGO,                &fops_mbox},
1449         {"vrings",      S_IRUGO,                &fops_vring},
1450         {"stations",    S_IRUGO,                &fops_sta},
1451         {"desc",        S_IRUGO,                &fops_txdesc},
1452         {"bf",          S_IRUGO,                &fops_bf},
1453         {"ssid",        S_IRUGO | S_IWUSR,      &fops_ssid},
1454         {"mem_val",     S_IRUGO,                &fops_memread},
1455         {"reset",                 S_IWUSR,      &fops_reset},
1456         {"rxon",                  S_IWUSR,      &fops_rxon},
1457         {"tx_mgmt",               S_IWUSR,      &fops_txmgmt},
1458         {"wmi_send",              S_IWUSR,      &fops_wmi},
1459         {"back",        S_IRUGO | S_IWUSR,      &fops_back},
1460         {"pmccfg",      S_IRUGO | S_IWUSR,      &fops_pmccfg},
1461         {"pmcdata",     S_IRUGO,                &fops_pmcdata},
1462         {"temp",        S_IRUGO,                &fops_temp},
1463         {"freq",        S_IRUGO,                &fops_freq},
1464         {"link",        S_IRUGO,                &fops_link},
1465         {"info",        S_IRUGO,                &fops_info},
1466         {"recovery",    S_IRUGO | S_IWUSR,      &fops_recovery},
1467 };
1468
1469 static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
1470                                        struct dentry *dbg)
1471 {
1472         int i;
1473
1474         for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
1475                 debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
1476                                     wil, dbg_files[i].fops);
1477 }
1478
1479 /* interrupt control blocks */
1480 static const struct {
1481         const char *name;
1482         u32 icr_off;
1483 } dbg_icr[] = {
1484         {"USER_ICR",            HOSTADDR(RGF_USER_USER_ICR)},
1485         {"DMA_EP_TX_ICR",       HOSTADDR(RGF_DMA_EP_TX_ICR)},
1486         {"DMA_EP_RX_ICR",       HOSTADDR(RGF_DMA_EP_RX_ICR)},
1487         {"DMA_EP_MISC_ICR",     HOSTADDR(RGF_DMA_EP_MISC_ICR)},
1488 };
1489
1490 static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
1491                                      struct dentry *dbg)
1492 {
1493         int i;
1494
1495         for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
1496                 wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
1497                                            dbg_icr[i].icr_off);
1498 }
1499
1500 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
1501         offsetof(struct wil6210_priv, name), type}
1502
1503 /* fields in struct wil6210_priv */
1504 static const struct dbg_off dbg_wil_off[] = {
1505         WIL_FIELD(privacy,      S_IRUGO,                doff_u32),
1506         WIL_FIELD(status[0],    S_IRUGO | S_IWUSR,      doff_ulong),
1507         WIL_FIELD(fw_version,   S_IRUGO,                doff_u32),
1508         WIL_FIELD(hw_version,   S_IRUGO,                doff_x32),
1509         WIL_FIELD(recovery_count, S_IRUGO,              doff_u32),
1510         WIL_FIELD(ap_isolate,   S_IRUGO,                doff_u32),
1511         {},
1512 };
1513
1514 static const struct dbg_off dbg_wil_regs[] = {
1515         {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
1516                 doff_io32},
1517         {"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
1518         {},
1519 };
1520
1521 /* static parameters */
1522 static const struct dbg_off dbg_statics[] = {
1523         {"desc_index",  S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
1524         {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
1525         {"mem_addr",    S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
1526         {"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh,
1527          doff_u32},
1528         {},
1529 };
1530
1531 int wil6210_debugfs_init(struct wil6210_priv *wil)
1532 {
1533         struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
1534                         wil_to_wiphy(wil)->debugfsdir);
1535
1536         if (IS_ERR_OR_NULL(dbg))
1537                 return -ENODEV;
1538
1539         wil_pmc_init(wil);
1540
1541         wil6210_debugfs_init_files(wil, dbg);
1542         wil6210_debugfs_init_isr(wil, dbg);
1543         wil6210_debugfs_init_blobs(wil, dbg);
1544         wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
1545         wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
1546                                     dbg_wil_regs);
1547         wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
1548
1549         wil6210_debugfs_create_pseudo_ISR(wil, dbg);
1550
1551         wil6210_debugfs_create_ITR_CNT(wil, dbg);
1552
1553         return 0;
1554 }
1555
1556 void wil6210_debugfs_remove(struct wil6210_priv *wil)
1557 {
1558         debugfs_remove_recursive(wil->debug);
1559         wil->debug = NULL;
1560
1561         /* free pmc memory without sending command to fw, as it will
1562          * be reset on the way down anyway
1563          */
1564         wil_pmc_free(wil, false);
1565 }