GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / net / wireless / ath / wil6210 / debugfs.c
1 /*
2  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
3  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include <linux/module.h>
19 #include <linux/debugfs.h>
20 #include <linux/seq_file.h>
21 #include <linux/pci.h>
22 #include <linux/rtnetlink.h>
23 #include <linux/power_supply.h>
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_ring_index; /* 24+ for Rx, 0..23 for Tx */
33 static u32 dbg_status_msg_index;
34 /* 0..wil->num_rx_status_rings-1 for Rx, wil->tx_sring_idx for Tx */
35 static u32 dbg_sring_index;
36
37 enum dbg_off_type {
38         doff_u32 = 0,
39         doff_x32 = 1,
40         doff_ulong = 2,
41         doff_io32 = 3,
42         doff_u8 = 4
43 };
44
45 /* offset to "wil" */
46 struct dbg_off {
47         const char *name;
48         umode_t mode;
49         ulong off;
50         enum dbg_off_type type;
51 };
52
53 static void wil_print_desc_edma(struct seq_file *s, struct wil6210_priv *wil,
54                                 struct wil_ring *ring,
55                                 char _s, char _h, int idx)
56 {
57         u8 num_of_descs;
58         bool has_skb = false;
59
60         if (ring->is_rx) {
61                 struct wil_rx_enhanced_desc *rx_d =
62                         (struct wil_rx_enhanced_desc *)
63                         &ring->va[idx].rx.enhanced;
64                 u16 buff_id = le16_to_cpu(rx_d->mac.buff_id);
65
66                 has_skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
67                 seq_printf(s, "%c", (has_skb) ? _h : _s);
68         } else {
69                 struct wil_tx_enhanced_desc *d =
70                         (struct wil_tx_enhanced_desc *)
71                         &ring->va[idx].tx.enhanced;
72
73                 num_of_descs = (u8)d->mac.d[2];
74                 has_skb = ring->ctx[idx].skb;
75                 if (num_of_descs >= 1)
76                         seq_printf(s, "%c", ring->ctx[idx].skb ? _h : _s);
77                 else
78                         /* num_of_descs == 0, it's a frag in a list of descs */
79                         seq_printf(s, "%c", has_skb ? 'h' : _s);
80         }
81 }
82
83 static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil,
84                            const char *name, struct wil_ring *ring,
85                            char _s, char _h)
86 {
87         void __iomem *x = wmi_addr(wil, ring->hwtail);
88         u32 v;
89
90         seq_printf(s, "RING %s = {\n", name);
91         seq_printf(s, "  pa     = %pad\n", &ring->pa);
92         seq_printf(s, "  va     = 0x%p\n", ring->va);
93         seq_printf(s, "  size   = %d\n", ring->size);
94         if (wil->use_enhanced_dma_hw && ring->is_rx)
95                 seq_printf(s, "  swtail = %u\n", *ring->edma_rx_swtail.va);
96         else
97                 seq_printf(s, "  swtail = %d\n", ring->swtail);
98         seq_printf(s, "  swhead = %d\n", ring->swhead);
99         seq_printf(s, "  hwtail = [0x%08x] -> ", ring->hwtail);
100         if (x) {
101                 v = readl(x);
102                 seq_printf(s, "0x%08x = %d\n", v, v);
103         } else {
104                 seq_puts(s, "???\n");
105         }
106
107         if (ring->va && (ring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
108                 uint i;
109
110                 for (i = 0; i < ring->size; i++) {
111                         if ((i % 128) == 0 && i != 0)
112                                 seq_puts(s, "\n");
113                         if (wil->use_enhanced_dma_hw) {
114                                 wil_print_desc_edma(s, wil, ring, _s, _h, i);
115                         } else {
116                                 volatile struct vring_tx_desc *d =
117                                         &ring->va[i].tx.legacy;
118                                 seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
119                                            _s : (ring->ctx[i].skb ? _h : 'h'));
120                         }
121                 }
122                 seq_puts(s, "\n");
123         }
124         seq_puts(s, "}\n");
125 }
126
127 static int wil_ring_debugfs_show(struct seq_file *s, void *data)
128 {
129         uint i;
130         struct wil6210_priv *wil = s->private;
131
132         wil_print_ring(s, wil, "rx", &wil->ring_rx, 'S', '_');
133
134         for (i = 0; i < ARRAY_SIZE(wil->ring_tx); i++) {
135                 struct wil_ring *ring = &wil->ring_tx[i];
136                 struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i];
137
138                 if (ring->va) {
139                         int cid = wil->ring2cid_tid[i][0];
140                         int tid = wil->ring2cid_tid[i][1];
141                         u32 swhead = ring->swhead;
142                         u32 swtail = ring->swtail;
143                         int used = (ring->size + swhead - swtail)
144                                    % ring->size;
145                         int avail = ring->size - used - 1;
146                         char name[10];
147                         char sidle[10];
148                         /* performance monitoring */
149                         cycles_t now = get_cycles();
150                         uint64_t idle = txdata->idle * 100;
151                         uint64_t total = now - txdata->begin;
152
153                         if (total != 0) {
154                                 do_div(idle, total);
155                                 snprintf(sidle, sizeof(sidle), "%3d%%",
156                                          (int)idle);
157                         } else {
158                                 snprintf(sidle, sizeof(sidle), "N/A");
159                         }
160                         txdata->begin = now;
161                         txdata->idle = 0ULL;
162
163                         snprintf(name, sizeof(name), "tx_%2d", i);
164
165                         if (cid < WIL6210_MAX_CID)
166                                 seq_printf(s,
167                                            "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
168                                            wil->sta[cid].addr, cid, tid,
169                                            txdata->dot1x_open ? "+" : "-",
170                                            txdata->agg_wsize,
171                                            txdata->agg_timeout,
172                                            txdata->agg_amsdu ? "+" : "-",
173                                            used, avail, sidle);
174                         else
175                                 seq_printf(s,
176                                            "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
177                                            txdata->dot1x_open ? "+" : "-",
178                                            used, avail, sidle);
179
180                         wil_print_ring(s, wil, name, ring, '_', 'H');
181                 }
182         }
183
184         return 0;
185 }
186
187 static int wil_ring_seq_open(struct inode *inode, struct file *file)
188 {
189         return single_open(file, wil_ring_debugfs_show, inode->i_private);
190 }
191
192 static const struct file_operations fops_ring = {
193         .open           = wil_ring_seq_open,
194         .release        = single_release,
195         .read           = seq_read,
196         .llseek         = seq_lseek,
197 };
198
199 static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil,
200                             struct wil_status_ring *sring)
201 {
202         void __iomem *x = wmi_addr(wil, sring->hwtail);
203         int sring_idx = sring - wil->srings;
204         u32 v;
205
206         seq_printf(s, "Status Ring %s [ %d ] = {\n",
207                    sring->is_rx ? "RX" : "TX", sring_idx);
208         seq_printf(s, "  pa     = %pad\n", &sring->pa);
209         seq_printf(s, "  va     = 0x%pK\n", sring->va);
210         seq_printf(s, "  size   = %d\n", sring->size);
211         seq_printf(s, "  elem_size   = %zu\n", sring->elem_size);
212         seq_printf(s, "  swhead = %d\n", sring->swhead);
213         seq_printf(s, "  hwtail = [0x%08x] -> ", sring->hwtail);
214         if (x) {
215                 v = readl_relaxed(x);
216                 seq_printf(s, "0x%08x = %d\n", v, v);
217         } else {
218                 seq_puts(s, "???\n");
219         }
220         seq_printf(s, "  desc_rdy_pol   = %d\n", sring->desc_rdy_pol);
221
222         if (sring->va && (sring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
223                 uint i;
224
225                 for (i = 0; i < sring->size; i++) {
226                         u32 *sdword_0 =
227                                 (u32 *)(sring->va + (sring->elem_size * i));
228
229                         if ((i % 128) == 0 && i != 0)
230                                 seq_puts(s, "\n");
231                         if (i == sring->swhead)
232                                 seq_printf(s, "%c", (*sdword_0 & BIT(31)) ?
233                                            'X' : 'x');
234                         else
235                                 seq_printf(s, "%c", (*sdword_0 & BIT(31)) ?
236                                            '1' : '0');
237                 }
238                 seq_puts(s, "\n");
239         }
240         seq_puts(s, "}\n");
241 }
242
243 static int wil_srings_debugfs_show(struct seq_file *s, void *data)
244 {
245         struct wil6210_priv *wil = s->private;
246         int i = 0;
247
248         for (i = 0; i < WIL6210_MAX_STATUS_RINGS; i++)
249                 if (wil->srings[i].va)
250                         wil_print_sring(s, wil, &wil->srings[i]);
251
252         return 0;
253 }
254
255 static int wil_srings_seq_open(struct inode *inode, struct file *file)
256 {
257         return single_open(file, wil_srings_debugfs_show, inode->i_private);
258 }
259
260 static const struct file_operations fops_srings = {
261         .open           = wil_srings_seq_open,
262         .release        = single_release,
263         .read           = seq_read,
264         .llseek         = seq_lseek,
265 };
266
267 static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
268                             const char *prefix)
269 {
270         seq_hex_dump(s, prefix, DUMP_PREFIX_NONE, 16, 1, p, len, false);
271 }
272
273 static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,
274                                 void __iomem *off)
275 {
276         struct wil6210_priv *wil = s->private;
277         struct wil6210_mbox_ring r;
278         int rsize;
279         uint i;
280
281         wil_halp_vote(wil);
282
283         wil_memcpy_fromio_32(&r, off, sizeof(r));
284         wil_mbox_ring_le2cpus(&r);
285         /*
286          * we just read memory block from NIC. This memory may be
287          * garbage. Check validity before using it.
288          */
289         rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
290
291         seq_printf(s, "ring %s = {\n", prefix);
292         seq_printf(s, "  base = 0x%08x\n", r.base);
293         seq_printf(s, "  size = 0x%04x bytes -> %d entries\n", r.size, rsize);
294         seq_printf(s, "  tail = 0x%08x\n", r.tail);
295         seq_printf(s, "  head = 0x%08x\n", r.head);
296         seq_printf(s, "  entry size = %d\n", r.entry_size);
297
298         if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
299                 seq_printf(s, "  ??? size is not multiple of %zd, garbage?\n",
300                            sizeof(struct wil6210_mbox_ring_desc));
301                 goto out;
302         }
303
304         if (!wmi_addr(wil, r.base) ||
305             !wmi_addr(wil, r.tail) ||
306             !wmi_addr(wil, r.head)) {
307                 seq_puts(s, "  ??? pointers are garbage?\n");
308                 goto out;
309         }
310
311         for (i = 0; i < rsize; i++) {
312                 struct wil6210_mbox_ring_desc d;
313                 struct wil6210_mbox_hdr hdr;
314                 size_t delta = i * sizeof(d);
315                 void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
316
317                 wil_memcpy_fromio_32(&d, x, sizeof(d));
318
319                 seq_printf(s, "  [%2x] %s %s%s 0x%08x", i,
320                            d.sync ? "F" : "E",
321                            (r.tail - r.base == delta) ? "t" : " ",
322                            (r.head - r.base == delta) ? "h" : " ",
323                            le32_to_cpu(d.addr));
324                 if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
325                         u16 len = le16_to_cpu(hdr.len);
326
327                         seq_printf(s, " -> %04x %04x %04x %02x\n",
328                                    le16_to_cpu(hdr.seq), len,
329                                    le16_to_cpu(hdr.type), hdr.flags);
330                         if (len <= MAX_MBOXITEM_SIZE) {
331                                 unsigned char databuf[MAX_MBOXITEM_SIZE];
332                                 void __iomem *src = wmi_buffer(wil, d.addr) +
333                                         sizeof(struct wil6210_mbox_hdr);
334                                 /*
335                                  * No need to check @src for validity -
336                                  * we already validated @d.addr while
337                                  * reading header
338                                  */
339                                 wil_memcpy_fromio_32(databuf, src, len);
340                                 wil_seq_hexdump(s, databuf, len, "      : ");
341                         }
342                 } else {
343                         seq_puts(s, "\n");
344                 }
345         }
346  out:
347         seq_puts(s, "}\n");
348         wil_halp_unvote(wil);
349 }
350
351 static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
352 {
353         struct wil6210_priv *wil = s->private;
354         int ret;
355
356         ret = wil_pm_runtime_get(wil);
357         if (ret < 0)
358                 return ret;
359
360         wil_print_mbox_ring(s, "tx", wil->csr + HOST_MBOX +
361                        offsetof(struct wil6210_mbox_ctl, tx));
362         wil_print_mbox_ring(s, "rx", wil->csr + HOST_MBOX +
363                        offsetof(struct wil6210_mbox_ctl, rx));
364
365         wil_pm_runtime_put(wil);
366
367         return 0;
368 }
369
370 static int wil_mbox_seq_open(struct inode *inode, struct file *file)
371 {
372         return single_open(file, wil_mbox_debugfs_show, inode->i_private);
373 }
374
375 static const struct file_operations fops_mbox = {
376         .open           = wil_mbox_seq_open,
377         .release        = single_release,
378         .read           = seq_read,
379         .llseek         = seq_lseek,
380 };
381
382 static int wil_debugfs_iomem_x32_set(void *data, u64 val)
383 {
384         struct wil_debugfs_iomem_data *d = (struct
385                                             wil_debugfs_iomem_data *)data;
386         struct wil6210_priv *wil = d->wil;
387         int ret;
388
389         ret = wil_pm_runtime_get(wil);
390         if (ret < 0)
391                 return ret;
392
393         writel(val, (void __iomem *)d->offset);
394         wmb(); /* make sure write propagated to HW */
395
396         wil_pm_runtime_put(wil);
397
398         return 0;
399 }
400
401 static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
402 {
403         struct wil_debugfs_iomem_data *d = (struct
404                                             wil_debugfs_iomem_data *)data;
405         struct wil6210_priv *wil = d->wil;
406         int ret;
407
408         ret = wil_pm_runtime_get(wil);
409         if (ret < 0)
410                 return ret;
411
412         *val = readl((void __iomem *)d->offset);
413
414         wil_pm_runtime_put(wil);
415
416         return 0;
417 }
418
419 DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
420                         wil_debugfs_iomem_x32_set, "0x%08llx\n");
421
422 static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
423                                                    umode_t mode,
424                                                    struct dentry *parent,
425                                                    void *value,
426                                                    struct wil6210_priv *wil)
427 {
428         struct dentry *file;
429         struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[
430                                               wil->dbg_data.iomem_data_count];
431
432         data->wil = wil;
433         data->offset = value;
434
435         file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32);
436         if (!IS_ERR_OR_NULL(file))
437                 wil->dbg_data.iomem_data_count++;
438
439         return file;
440 }
441
442 static int wil_debugfs_ulong_set(void *data, u64 val)
443 {
444         *(ulong *)data = val;
445         return 0;
446 }
447
448 static int wil_debugfs_ulong_get(void *data, u64 *val)
449 {
450         *val = *(ulong *)data;
451         return 0;
452 }
453
454 DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
455                         wil_debugfs_ulong_set, "0x%llx\n");
456
457 static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
458                                                struct dentry *parent,
459                                                ulong *value)
460 {
461         return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
462 }
463
464 /**
465  * wil6210_debugfs_init_offset - create set of debugfs files
466  * @wil - driver's context, used for printing
467  * @dbg - directory on the debugfs, where files will be created
468  * @base - base address used in address calculation
469  * @tbl - table with file descriptions. Should be terminated with empty element.
470  *
471  * Creates files accordingly to the @tbl.
472  */
473 static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
474                                         struct dentry *dbg, void *base,
475                                         const struct dbg_off * const tbl)
476 {
477         int i;
478
479         for (i = 0; tbl[i].name; i++) {
480                 struct dentry *f;
481
482                 switch (tbl[i].type) {
483                 case doff_u32:
484                         f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
485                                                base + tbl[i].off);
486                         break;
487                 case doff_x32:
488                         f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
489                                                base + tbl[i].off);
490                         break;
491                 case doff_ulong:
492                         f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
493                                                      dbg, base + tbl[i].off);
494                         break;
495                 case doff_io32:
496                         f = wil_debugfs_create_iomem_x32(tbl[i].name,
497                                                          tbl[i].mode, dbg,
498                                                          base + tbl[i].off,
499                                                          wil);
500                         break;
501                 case doff_u8:
502                         f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
503                                               base + tbl[i].off);
504                         break;
505                 default:
506                         f = ERR_PTR(-EINVAL);
507                 }
508                 if (IS_ERR_OR_NULL(f))
509                         wil_err(wil, "Create file \"%s\": err %ld\n",
510                                 tbl[i].name, PTR_ERR(f));
511         }
512 }
513
514 static const struct dbg_off isr_off[] = {
515         {"ICC", 0644, offsetof(struct RGF_ICR, ICC), doff_io32},
516         {"ICR", 0644, offsetof(struct RGF_ICR, ICR), doff_io32},
517         {"ICM", 0644, offsetof(struct RGF_ICR, ICM), doff_io32},
518         {"ICS", 0244, offsetof(struct RGF_ICR, ICS), doff_io32},
519         {"IMV", 0644, offsetof(struct RGF_ICR, IMV), doff_io32},
520         {"IMS", 0244, offsetof(struct RGF_ICR, IMS), doff_io32},
521         {"IMC", 0244, offsetof(struct RGF_ICR, IMC), doff_io32},
522         {},
523 };
524
525 static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
526                                       const char *name,
527                                       struct dentry *parent, u32 off)
528 {
529         struct dentry *d = debugfs_create_dir(name, parent);
530
531         if (IS_ERR_OR_NULL(d))
532                 return -ENODEV;
533
534         wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
535                                     isr_off);
536
537         return 0;
538 }
539
540 static const struct dbg_off pseudo_isr_off[] = {
541         {"CAUSE",   0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
542         {"MASK_SW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
543         {"MASK_FW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
544         {},
545 };
546
547 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
548                                              struct dentry *parent)
549 {
550         struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
551
552         if (IS_ERR_OR_NULL(d))
553                 return -ENODEV;
554
555         wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
556                                     pseudo_isr_off);
557
558         return 0;
559 }
560
561 static const struct dbg_off lgc_itr_cnt_off[] = {
562         {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
563         {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
564         {"CTL",  0644, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
565         {},
566 };
567
568 static const struct dbg_off tx_itr_cnt_off[] = {
569         {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
570          doff_io32},
571         {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
572          doff_io32},
573         {"CTL",  0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
574          doff_io32},
575         {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
576          doff_io32},
577         {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
578          doff_io32},
579         {"IDL_CTL",  0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
580          doff_io32},
581         {},
582 };
583
584 static const struct dbg_off rx_itr_cnt_off[] = {
585         {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
586          doff_io32},
587         {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
588          doff_io32},
589         {"CTL",  0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
590          doff_io32},
591         {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
592          doff_io32},
593         {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
594          doff_io32},
595         {"IDL_CTL",  0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
596          doff_io32},
597         {},
598 };
599
600 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
601                                           struct dentry *parent)
602 {
603         struct dentry *d, *dtx, *drx;
604
605         d = debugfs_create_dir("ITR_CNT", parent);
606         if (IS_ERR_OR_NULL(d))
607                 return -ENODEV;
608
609         dtx = debugfs_create_dir("TX", d);
610         drx = debugfs_create_dir("RX", d);
611         if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
612                 return -ENODEV;
613
614         wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
615                                     lgc_itr_cnt_off);
616
617         wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
618                                     tx_itr_cnt_off);
619
620         wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
621                                     rx_itr_cnt_off);
622         return 0;
623 }
624
625 static int wil_memread_debugfs_show(struct seq_file *s, void *data)
626 {
627         struct wil6210_priv *wil = s->private;
628         void __iomem *a;
629         int ret;
630
631         ret = wil_pm_runtime_get(wil);
632         if (ret < 0)
633                 return ret;
634
635         a = wmi_buffer(wil, cpu_to_le32(mem_addr));
636
637         if (a)
638                 seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a));
639         else
640                 seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
641
642         wil_pm_runtime_put(wil);
643
644         return 0;
645 }
646
647 static int wil_memread_seq_open(struct inode *inode, struct file *file)
648 {
649         return single_open(file, wil_memread_debugfs_show, inode->i_private);
650 }
651
652 static const struct file_operations fops_memread = {
653         .open           = wil_memread_seq_open,
654         .release        = single_release,
655         .read           = seq_read,
656         .llseek         = seq_lseek,
657 };
658
659 static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
660                                     size_t count, loff_t *ppos)
661 {
662         enum { max_count = 4096 };
663         struct wil_blob_wrapper *wil_blob = file->private_data;
664         struct wil6210_priv *wil = wil_blob->wil;
665         loff_t aligned_pos, pos = *ppos;
666         size_t available = wil_blob->blob.size;
667         void *buf;
668         size_t unaligned_bytes, aligned_count, ret;
669         int rc;
670
671         if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
672             test_bit(wil_status_suspended, wil_blob->wil->status))
673                 return 0;
674
675         if (pos < 0)
676                 return -EINVAL;
677
678         if (pos >= available || !count)
679                 return 0;
680
681         if (count > available - pos)
682                 count = available - pos;
683         if (count > max_count)
684                 count = max_count;
685
686         /* set pos to 4 bytes aligned */
687         unaligned_bytes = pos % 4;
688         aligned_pos = pos - unaligned_bytes;
689         aligned_count = count + unaligned_bytes;
690
691         buf = kmalloc(aligned_count, GFP_KERNEL);
692         if (!buf)
693                 return -ENOMEM;
694
695         rc = wil_pm_runtime_get(wil);
696         if (rc < 0) {
697                 kfree(buf);
698                 return rc;
699         }
700
701         wil_memcpy_fromio_32(buf, (const void __iomem *)
702                              wil_blob->blob.data + aligned_pos, aligned_count);
703
704         ret = copy_to_user(user_buf, buf + unaligned_bytes, count);
705
706         wil_pm_runtime_put(wil);
707
708         kfree(buf);
709         if (ret == count)
710                 return -EFAULT;
711
712         count -= ret;
713         *ppos = pos + count;
714
715         return count;
716 }
717
718 static const struct file_operations fops_ioblob = {
719         .read =         wil_read_file_ioblob,
720         .open =         simple_open,
721         .llseek =       default_llseek,
722 };
723
724 static
725 struct dentry *wil_debugfs_create_ioblob(const char *name,
726                                          umode_t mode,
727                                          struct dentry *parent,
728                                          struct wil_blob_wrapper *wil_blob)
729 {
730         return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob);
731 }
732
733 /*---write channel 1..4 to rxon for it, 0 to rxoff---*/
734 static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
735                                    size_t len, loff_t *ppos)
736 {
737         struct wil6210_priv *wil = file->private_data;
738         int rc;
739         long channel;
740         bool on;
741
742         char *kbuf = memdup_user_nul(buf, len);
743
744         if (IS_ERR(kbuf))
745                 return PTR_ERR(kbuf);
746         rc = kstrtol(kbuf, 0, &channel);
747         kfree(kbuf);
748         if (rc)
749                 return rc;
750
751         if ((channel < 0) || (channel > 4)) {
752                 wil_err(wil, "Invalid channel %ld\n", channel);
753                 return -EINVAL;
754         }
755         on = !!channel;
756
757         if (on) {
758                 rc = wmi_set_channel(wil, (int)channel);
759                 if (rc)
760                         return rc;
761         }
762
763         rc = wmi_rxon(wil, on);
764         if (rc)
765                 return rc;
766
767         return len;
768 }
769
770 static const struct file_operations fops_rxon = {
771         .write = wil_write_file_rxon,
772         .open  = simple_open,
773 };
774
775 /* block ack control, write:
776  * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
777  * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
778  * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
779  */
780 static ssize_t wil_write_back(struct file *file, const char __user *buf,
781                               size_t len, loff_t *ppos)
782 {
783         struct wil6210_priv *wil = file->private_data;
784         int rc;
785         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
786         char cmd[9];
787         int p1, p2, p3;
788
789         if (!kbuf)
790                 return -ENOMEM;
791
792         rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
793         if (rc != len) {
794                 kfree(kbuf);
795                 return rc >= 0 ? -EIO : rc;
796         }
797
798         kbuf[len] = '\0';
799         rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
800         kfree(kbuf);
801
802         if (rc < 0)
803                 return rc;
804         if (rc < 2)
805                 return -EINVAL;
806
807         if ((strcmp(cmd, "add") == 0) ||
808             (strcmp(cmd, "del_tx") == 0)) {
809                 struct wil_ring_tx_data *txdata;
810
811                 if (p1 < 0 || p1 >= WIL6210_MAX_TX_RINGS) {
812                         wil_err(wil, "BACK: invalid ring id %d\n", p1);
813                         return -EINVAL;
814                 }
815                 txdata = &wil->ring_tx_data[p1];
816                 if (strcmp(cmd, "add") == 0) {
817                         if (rc < 3) {
818                                 wil_err(wil, "BACK: add require at least 2 params\n");
819                                 return -EINVAL;
820                         }
821                         if (rc < 4)
822                                 p3 = 0;
823                         wmi_addba(wil, txdata->mid, p1, p2, p3);
824                 } else {
825                         if (rc < 3)
826                                 p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
827                         wmi_delba_tx(wil, txdata->mid, p1, p2);
828                 }
829         } else if (strcmp(cmd, "del_rx") == 0) {
830                 struct wil_sta_info *sta;
831
832                 if (rc < 3) {
833                         wil_err(wil,
834                                 "BACK: del_rx require at least 2 params\n");
835                         return -EINVAL;
836                 }
837                 if (p1 < 0 || p1 >= WIL6210_MAX_CID) {
838                         wil_err(wil, "BACK: invalid CID %d\n", p1);
839                         return -EINVAL;
840                 }
841                 if (rc < 4)
842                         p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
843                 sta = &wil->sta[p1];
844                 wmi_delba_rx(wil, sta->mid, mk_cidxtid(p1, p2), p3);
845         } else {
846                 wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
847                 return -EINVAL;
848         }
849
850         return len;
851 }
852
853 static ssize_t wil_read_back(struct file *file, char __user *user_buf,
854                              size_t count, loff_t *ppos)
855 {
856         static const char text[] = "block ack control, write:\n"
857         " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
858         "If missing, <timeout> defaults to 0\n"
859         " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
860         " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
861         "If missing, <reason> set to \"STA_LEAVING\" (36)\n";
862
863         return simple_read_from_buffer(user_buf, count, ppos, text,
864                                        sizeof(text));
865 }
866
867 static const struct file_operations fops_back = {
868         .read = wil_read_back,
869         .write = wil_write_back,
870         .open  = simple_open,
871 };
872
873 /* pmc control, write:
874  * - "alloc <num descriptors> <descriptor_size>" to allocate PMC
875  * - "free" to release memory allocated for PMC
876  */
877 static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf,
878                                 size_t len, loff_t *ppos)
879 {
880         struct wil6210_priv *wil = file->private_data;
881         int rc;
882         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
883         char cmd[9];
884         int num_descs, desc_size;
885
886         if (!kbuf)
887                 return -ENOMEM;
888
889         rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
890         if (rc != len) {
891                 kfree(kbuf);
892                 return rc >= 0 ? -EIO : rc;
893         }
894
895         kbuf[len] = '\0';
896         rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size);
897         kfree(kbuf);
898
899         if (rc < 0)
900                 return rc;
901
902         if (rc < 1) {
903                 wil_err(wil, "pmccfg: no params given\n");
904                 return -EINVAL;
905         }
906
907         if (0 == strcmp(cmd, "alloc")) {
908                 if (rc != 3) {
909                         wil_err(wil, "pmccfg: alloc requires 2 params\n");
910                         return -EINVAL;
911                 }
912                 wil_pmc_alloc(wil, num_descs, desc_size);
913         } else if (0 == strcmp(cmd, "free")) {
914                 if (rc != 1) {
915                         wil_err(wil, "pmccfg: free does not have any params\n");
916                         return -EINVAL;
917                 }
918                 wil_pmc_free(wil, true);
919         } else {
920                 wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd);
921                 return -EINVAL;
922         }
923
924         return len;
925 }
926
927 static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf,
928                                size_t count, loff_t *ppos)
929 {
930         struct wil6210_priv *wil = file->private_data;
931         char text[256];
932         char help[] = "pmc control, write:\n"
933         " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
934         " - \"free\" to free memory allocated for pmc\n";
935
936         sprintf(text, "Last command status: %d\n\n%s",
937                 wil_pmc_last_cmd_status(wil),
938                 help);
939
940         return simple_read_from_buffer(user_buf, count, ppos, text,
941                                        strlen(text) + 1);
942 }
943
944 static const struct file_operations fops_pmccfg = {
945         .read = wil_read_pmccfg,
946         .write = wil_write_pmccfg,
947         .open  = simple_open,
948 };
949
950 static const struct file_operations fops_pmcdata = {
951         .open           = simple_open,
952         .read           = wil_pmc_read,
953         .llseek         = wil_pmc_llseek,
954 };
955
956 /*---tx_mgmt---*/
957 /* Write mgmt frame to this file to send it */
958 static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
959                                      size_t len, loff_t *ppos)
960 {
961         struct wil6210_priv *wil = file->private_data;
962         struct wiphy *wiphy = wil_to_wiphy(wil);
963         struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
964         struct cfg80211_mgmt_tx_params params;
965         int rc;
966         void *frame;
967
968         memset(&params, 0, sizeof(params));
969
970         if (!len)
971                 return -EINVAL;
972
973         frame = memdup_user(buf, len);
974         if (IS_ERR(frame))
975                 return PTR_ERR(frame);
976
977         params.buf = frame;
978         params.len = len;
979
980         rc = wil_cfg80211_mgmt_tx(wiphy, wdev, &params, NULL);
981
982         kfree(frame);
983         wil_info(wil, "-> %d\n", rc);
984
985         return len;
986 }
987
988 static const struct file_operations fops_txmgmt = {
989         .write = wil_write_file_txmgmt,
990         .open  = simple_open,
991 };
992
993 /* Write WMI command (w/o mbox header) to this file to send it
994  * WMI starts from wil6210_mbox_hdr_wmi header
995  */
996 static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
997                                   size_t len, loff_t *ppos)
998 {
999         struct wil6210_priv *wil = file->private_data;
1000         struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
1001         struct wmi_cmd_hdr *wmi;
1002         void *cmd;
1003         int cmdlen = len - sizeof(struct wmi_cmd_hdr);
1004         u16 cmdid;
1005         int rc, rc1;
1006
1007         if (cmdlen < 0)
1008                 return -EINVAL;
1009
1010         wmi = kmalloc(len, GFP_KERNEL);
1011         if (!wmi)
1012                 return -ENOMEM;
1013
1014         rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
1015         if (rc < 0) {
1016                 kfree(wmi);
1017                 return rc;
1018         }
1019
1020         cmd = (cmdlen > 0) ? &wmi[1] : NULL;
1021         cmdid = le16_to_cpu(wmi->command_id);
1022
1023         rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen);
1024         kfree(wmi);
1025
1026         wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
1027
1028         return rc;
1029 }
1030
1031 static const struct file_operations fops_wmi = {
1032         .write = wil_write_file_wmi,
1033         .open  = simple_open,
1034 };
1035
1036 static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
1037 {
1038         int i = 0;
1039         int len = skb_headlen(skb);
1040         void *p = skb->data;
1041         int nr_frags = skb_shinfo(skb)->nr_frags;
1042
1043         seq_printf(s, "    len = %d\n", len);
1044         wil_seq_hexdump(s, p, len, "      : ");
1045
1046         if (nr_frags) {
1047                 seq_printf(s, "    nr_frags = %d\n", nr_frags);
1048                 for (i = 0; i < nr_frags; i++) {
1049                         const struct skb_frag_struct *frag =
1050                                         &skb_shinfo(skb)->frags[i];
1051
1052                         len = skb_frag_size(frag);
1053                         p = skb_frag_address_safe(frag);
1054                         seq_printf(s, "    [%2d] : len = %d\n", i, len);
1055                         wil_seq_hexdump(s, p, len, "      : ");
1056                 }
1057         }
1058 }
1059
1060 /*---------Tx/Rx descriptor------------*/
1061 static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
1062 {
1063         struct wil6210_priv *wil = s->private;
1064         struct wil_ring *ring;
1065         bool tx;
1066         int ring_idx = dbg_ring_index;
1067         int txdesc_idx = dbg_txdesc_index;
1068         volatile struct vring_tx_desc *d;
1069         volatile u32 *u;
1070         struct sk_buff *skb;
1071
1072         if (wil->use_enhanced_dma_hw) {
1073                 /* RX ring index == 0 */
1074                 if (ring_idx >= WIL6210_MAX_TX_RINGS) {
1075                         seq_printf(s, "invalid ring index %d\n", ring_idx);
1076                         return 0;
1077                 }
1078                 tx = ring_idx > 0; /* desc ring 0 is reserved for RX */
1079         } else {
1080                 /* RX ring index == WIL6210_MAX_TX_RINGS */
1081                 if (ring_idx > WIL6210_MAX_TX_RINGS) {
1082                         seq_printf(s, "invalid ring index %d\n", ring_idx);
1083                         return 0;
1084                 }
1085                 tx = (ring_idx < WIL6210_MAX_TX_RINGS);
1086         }
1087
1088         ring = tx ? &wil->ring_tx[ring_idx] : &wil->ring_rx;
1089
1090         if (!ring->va) {
1091                 if (tx)
1092                         seq_printf(s, "No Tx[%2d] RING\n", ring_idx);
1093                 else
1094                         seq_puts(s, "No Rx RING\n");
1095                 return 0;
1096         }
1097
1098         if (txdesc_idx >= ring->size) {
1099                 if (tx)
1100                         seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
1101                                    ring_idx, txdesc_idx, ring->size);
1102                 else
1103                         seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
1104                                    txdesc_idx, ring->size);
1105                 return 0;
1106         }
1107
1108         /* use struct vring_tx_desc for Rx as well,
1109          * only field used, .dma.length, is the same
1110          */
1111         d = &ring->va[txdesc_idx].tx.legacy;
1112         u = (volatile u32 *)d;
1113         skb = NULL;
1114
1115         if (wil->use_enhanced_dma_hw) {
1116                 if (tx) {
1117                         skb = ring->ctx[txdesc_idx].skb;
1118                 } else {
1119                         struct wil_rx_enhanced_desc *rx_d =
1120                                 (struct wil_rx_enhanced_desc *)
1121                                 &ring->va[txdesc_idx].rx.enhanced;
1122                         u16 buff_id = le16_to_cpu(rx_d->mac.buff_id);
1123
1124                         if (!wil_val_in_range(buff_id, 0,
1125                                               wil->rx_buff_mgmt.size)) {
1126                                 seq_printf(s, "invalid buff_id %d\n", buff_id);
1127                                 return 0;
1128                         }
1129                         skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
1130                 }
1131         } else {
1132                 skb = ring->ctx[txdesc_idx].skb;
1133         }
1134         if (tx)
1135                 seq_printf(s, "Tx[%2d][%3d] = {\n", ring_idx,
1136                            txdesc_idx);
1137         else
1138                 seq_printf(s, "Rx[%3d] = {\n", txdesc_idx);
1139         seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1140                    u[0], u[1], u[2], u[3]);
1141         seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1142                    u[4], u[5], u[6], u[7]);
1143         seq_printf(s, "  SKB = 0x%p\n", skb);
1144
1145         if (skb) {
1146                 skb_get(skb);
1147                 wil_seq_print_skb(s, skb);
1148                 kfree_skb(skb);
1149         }
1150         seq_puts(s, "}\n");
1151
1152         return 0;
1153 }
1154
1155 static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
1156 {
1157         return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
1158 }
1159
1160 static const struct file_operations fops_txdesc = {
1161         .open           = wil_txdesc_seq_open,
1162         .release        = single_release,
1163         .read           = seq_read,
1164         .llseek         = seq_lseek,
1165 };
1166
1167 /*---------Tx/Rx status message------------*/
1168 static int wil_status_msg_debugfs_show(struct seq_file *s, void *data)
1169 {
1170         struct wil6210_priv *wil = s->private;
1171         int sring_idx = dbg_sring_index;
1172         struct wil_status_ring *sring;
1173         bool tx = sring_idx == wil->tx_sring_idx ? 1 : 0;
1174         u32 status_msg_idx = dbg_status_msg_index;
1175         u32 *u;
1176
1177         if (sring_idx >= WIL6210_MAX_STATUS_RINGS) {
1178                 seq_printf(s, "invalid status ring index %d\n", sring_idx);
1179                 return 0;
1180         }
1181
1182         sring = &wil->srings[sring_idx];
1183
1184         if (!sring->va) {
1185                 seq_printf(s, "No %cX status ring\n", tx ? 'T' : 'R');
1186                 return 0;
1187         }
1188
1189         if (status_msg_idx >= sring->size) {
1190                 seq_printf(s, "%cxDesc index (%d) >= size (%d)\n",
1191                            tx ? 'T' : 'R', status_msg_idx, sring->size);
1192                 return 0;
1193         }
1194
1195         u = sring->va + (sring->elem_size * status_msg_idx);
1196
1197         seq_printf(s, "%cx[%d][%3d] = {\n",
1198                    tx ? 'T' : 'R', sring_idx, status_msg_idx);
1199
1200         seq_printf(s, "  0x%08x 0x%08x 0x%08x 0x%08x\n",
1201                    u[0], u[1], u[2], u[3]);
1202         if (!tx && !wil->use_compressed_rx_status)
1203                 seq_printf(s, "  0x%08x 0x%08x 0x%08x 0x%08x\n",
1204                            u[4], u[5], u[6], u[7]);
1205
1206         seq_puts(s, "}\n");
1207
1208         return 0;
1209 }
1210
1211 static int wil_status_msg_seq_open(struct inode *inode, struct file *file)
1212 {
1213         return single_open(file, wil_status_msg_debugfs_show,
1214                            inode->i_private);
1215 }
1216
1217 static const struct file_operations fops_status_msg = {
1218         .open           = wil_status_msg_seq_open,
1219         .release        = single_release,
1220         .read           = seq_read,
1221         .llseek         = seq_lseek,
1222 };
1223
1224 static int wil_print_rx_buff(struct seq_file *s, struct list_head *lh)
1225 {
1226         struct wil_rx_buff *it;
1227         int i = 0;
1228
1229         list_for_each_entry(it, lh, list) {
1230                 if ((i % 16) == 0 && i != 0)
1231                         seq_puts(s, "\n    ");
1232                 seq_printf(s, "[%4d] ", it->id);
1233                 i++;
1234         }
1235         seq_printf(s, "\nNumber of buffers: %u\n", i);
1236
1237         return i;
1238 }
1239
1240 static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data)
1241 {
1242         struct wil6210_priv *wil = s->private;
1243         struct wil_rx_buff_mgmt *rbm = &wil->rx_buff_mgmt;
1244         int num_active;
1245         int num_free;
1246
1247         if (!rbm->buff_arr)
1248                 return -EINVAL;
1249
1250         seq_printf(s, "  size = %zu\n", rbm->size);
1251         seq_printf(s, "  free_list_empty_cnt = %lu\n",
1252                    rbm->free_list_empty_cnt);
1253
1254         /* Print active list */
1255         seq_puts(s, "  Active list:\n");
1256         num_active = wil_print_rx_buff(s, &rbm->active);
1257         seq_puts(s, "\n  Free list:\n");
1258         num_free = wil_print_rx_buff(s, &rbm->free);
1259
1260         seq_printf(s, "  Total number of buffers: %u\n",
1261                    num_active + num_free);
1262
1263         return 0;
1264 }
1265
1266 static int wil_rx_buff_mgmt_seq_open(struct inode *inode, struct file *file)
1267 {
1268         return single_open(file, wil_rx_buff_mgmt_debugfs_show,
1269                            inode->i_private);
1270 }
1271
1272 static const struct file_operations fops_rx_buff_mgmt = {
1273         .open           = wil_rx_buff_mgmt_seq_open,
1274         .release        = single_release,
1275         .read           = seq_read,
1276         .llseek         = seq_lseek,
1277 };
1278
1279 /*---------beamforming------------*/
1280 static char *wil_bfstatus_str(u32 status)
1281 {
1282         switch (status) {
1283         case 0:
1284                 return "Failed";
1285         case 1:
1286                 return "OK";
1287         case 2:
1288                 return "Retrying";
1289         default:
1290                 return "??";
1291         }
1292 }
1293
1294 static bool is_all_zeros(void * const x_, size_t sz)
1295 {
1296         /* if reply is all-0, ignore this CID */
1297         u32 *x = x_;
1298         int n;
1299
1300         for (n = 0; n < sz / sizeof(*x); n++)
1301                 if (x[n])
1302                         return false;
1303
1304         return true;
1305 }
1306
1307 static int wil_bf_debugfs_show(struct seq_file *s, void *data)
1308 {
1309         int rc;
1310         int i;
1311         struct wil6210_priv *wil = s->private;
1312         struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
1313         struct wmi_notify_req_cmd cmd = {
1314                 .interval_usec = 0,
1315         };
1316         struct {
1317                 struct wmi_cmd_hdr wmi;
1318                 struct wmi_notify_req_done_event evt;
1319         } __packed reply;
1320
1321         memset(&reply, 0, sizeof(reply));
1322
1323         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1324                 u32 status;
1325
1326                 cmd.cid = i;
1327                 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid,
1328                               &cmd, sizeof(cmd),
1329                               WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
1330                               sizeof(reply), 20);
1331                 /* if reply is all-0, ignore this CID */
1332                 if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
1333                         continue;
1334
1335                 status = le32_to_cpu(reply.evt.status);
1336                 seq_printf(s, "CID %d {\n"
1337                            "  TSF = 0x%016llx\n"
1338                            "  TxMCS = %2d TxTpt = %4d\n"
1339                            "  SQI = %4d\n"
1340                            "  RSSI = %4d\n"
1341                            "  Status = 0x%08x %s\n"
1342                            "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
1343                            "  Goodput(rx:tx) %4d:%4d\n"
1344                            "}\n",
1345                            i,
1346                            le64_to_cpu(reply.evt.tsf),
1347                            le16_to_cpu(reply.evt.bf_mcs),
1348                            le32_to_cpu(reply.evt.tx_tpt),
1349                            reply.evt.sqi,
1350                            reply.evt.rssi,
1351                            status, wil_bfstatus_str(status),
1352                            le16_to_cpu(reply.evt.my_rx_sector),
1353                            le16_to_cpu(reply.evt.my_tx_sector),
1354                            le16_to_cpu(reply.evt.other_rx_sector),
1355                            le16_to_cpu(reply.evt.other_tx_sector),
1356                            le32_to_cpu(reply.evt.rx_goodput),
1357                            le32_to_cpu(reply.evt.tx_goodput));
1358         }
1359         return 0;
1360 }
1361
1362 static int wil_bf_seq_open(struct inode *inode, struct file *file)
1363 {
1364         return single_open(file, wil_bf_debugfs_show, inode->i_private);
1365 }
1366
1367 static const struct file_operations fops_bf = {
1368         .open           = wil_bf_seq_open,
1369         .release        = single_release,
1370         .read           = seq_read,
1371         .llseek         = seq_lseek,
1372 };
1373
1374 /*---------temp------------*/
1375 static void print_temp(struct seq_file *s, const char *prefix, s32 t)
1376 {
1377         switch (t) {
1378         case 0:
1379         case ~(u32)0:
1380                 seq_printf(s, "%s N/A\n", prefix);
1381         break;
1382         default:
1383                 seq_printf(s, "%s %s%d.%03d\n", prefix, (t < 0 ? "-" : ""),
1384                            abs(t / 1000), abs(t % 1000));
1385                 break;
1386         }
1387 }
1388
1389 static int wil_temp_debugfs_show(struct seq_file *s, void *data)
1390 {
1391         struct wil6210_priv *wil = s->private;
1392         s32 t_m, t_r;
1393         int rc = wmi_get_temperature(wil, &t_m, &t_r);
1394
1395         if (rc) {
1396                 seq_puts(s, "Failed\n");
1397                 return 0;
1398         }
1399
1400         print_temp(s, "T_mac   =", t_m);
1401         print_temp(s, "T_radio =", t_r);
1402
1403         return 0;
1404 }
1405
1406 static int wil_temp_seq_open(struct inode *inode, struct file *file)
1407 {
1408         return single_open(file, wil_temp_debugfs_show, inode->i_private);
1409 }
1410
1411 static const struct file_operations fops_temp = {
1412         .open           = wil_temp_seq_open,
1413         .release        = single_release,
1414         .read           = seq_read,
1415         .llseek         = seq_lseek,
1416 };
1417
1418 /*---------freq------------*/
1419 static int wil_freq_debugfs_show(struct seq_file *s, void *data)
1420 {
1421         struct wil6210_priv *wil = s->private;
1422         struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
1423         u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
1424
1425         seq_printf(s, "Freq = %d\n", freq);
1426
1427         return 0;
1428 }
1429
1430 static int wil_freq_seq_open(struct inode *inode, struct file *file)
1431 {
1432         return single_open(file, wil_freq_debugfs_show, inode->i_private);
1433 }
1434
1435 static const struct file_operations fops_freq = {
1436         .open           = wil_freq_seq_open,
1437         .release        = single_release,
1438         .read           = seq_read,
1439         .llseek         = seq_lseek,
1440 };
1441
1442 /*---------link------------*/
1443 static int wil_link_debugfs_show(struct seq_file *s, void *data)
1444 {
1445         struct wil6210_priv *wil = s->private;
1446         struct station_info *sinfo;
1447         int i, rc = 0;
1448
1449         sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
1450         if (!sinfo)
1451                 return -ENOMEM;
1452
1453         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1454                 struct wil_sta_info *p = &wil->sta[i];
1455                 char *status = "unknown";
1456                 struct wil6210_vif *vif;
1457                 u8 mid;
1458
1459                 switch (p->status) {
1460                 case wil_sta_unused:
1461                         status = "unused   ";
1462                         break;
1463                 case wil_sta_conn_pending:
1464                         status = "pending  ";
1465                         break;
1466                 case wil_sta_connected:
1467                         status = "connected";
1468                         break;
1469                 }
1470                 mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
1471                 seq_printf(s, "[%d][MID %d] %pM %s\n",
1472                            i, mid, p->addr, status);
1473
1474                 if (p->status != wil_sta_connected)
1475                         continue;
1476
1477                 vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
1478                 if (vif) {
1479                         rc = wil_cid_fill_sinfo(vif, i, sinfo);
1480                         if (rc)
1481                                 goto out;
1482
1483                         seq_printf(s, "  Tx_mcs = %d\n", sinfo->txrate.mcs);
1484                         seq_printf(s, "  Rx_mcs = %d\n", sinfo->rxrate.mcs);
1485                         seq_printf(s, "  SQ     = %d\n", sinfo->signal);
1486                 } else {
1487                         seq_puts(s, "  INVALID MID\n");
1488                 }
1489         }
1490
1491 out:
1492         kfree(sinfo);
1493         return rc;
1494 }
1495
1496 static int wil_link_seq_open(struct inode *inode, struct file *file)
1497 {
1498         return single_open(file, wil_link_debugfs_show, inode->i_private);
1499 }
1500
1501 static const struct file_operations fops_link = {
1502         .open           = wil_link_seq_open,
1503         .release        = single_release,
1504         .read           = seq_read,
1505         .llseek         = seq_lseek,
1506 };
1507
1508 /*---------info------------*/
1509 static int wil_info_debugfs_show(struct seq_file *s, void *data)
1510 {
1511         struct wil6210_priv *wil = s->private;
1512         struct net_device *ndev = wil->main_ndev;
1513         int is_ac = power_supply_is_system_supplied();
1514         int rx = atomic_xchg(&wil->isr_count_rx, 0);
1515         int tx = atomic_xchg(&wil->isr_count_tx, 0);
1516         static ulong rxf_old, txf_old;
1517         ulong rxf = ndev->stats.rx_packets;
1518         ulong txf = ndev->stats.tx_packets;
1519         unsigned int i;
1520
1521         /* >0 : AC; 0 : battery; <0 : error */
1522         seq_printf(s, "AC powered : %d\n", is_ac);
1523         seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
1524         seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
1525         rxf_old = rxf;
1526         txf_old = txf;
1527
1528 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1529         " " __stringify(x) : ""
1530
1531         for (i = 0; i < ndev->num_tx_queues; i++) {
1532                 struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
1533                 unsigned long state = txq->state;
1534
1535                 seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
1536                            CHECK_QSTATE(DRV_XOFF),
1537                            CHECK_QSTATE(STACK_XOFF),
1538                            CHECK_QSTATE(FROZEN)
1539                           );
1540         }
1541 #undef CHECK_QSTATE
1542         return 0;
1543 }
1544
1545 static int wil_info_seq_open(struct inode *inode, struct file *file)
1546 {
1547         return single_open(file, wil_info_debugfs_show, inode->i_private);
1548 }
1549
1550 static const struct file_operations fops_info = {
1551         .open           = wil_info_seq_open,
1552         .release        = single_release,
1553         .read           = seq_read,
1554         .llseek         = seq_lseek,
1555 };
1556
1557 /*---------recovery------------*/
1558 /* mode = [manual|auto]
1559  * state = [idle|pending|running]
1560  */
1561 static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
1562                                       size_t count, loff_t *ppos)
1563 {
1564         struct wil6210_priv *wil = file->private_data;
1565         char buf[80];
1566         int n;
1567         static const char * const sstate[] = {"idle", "pending", "running"};
1568
1569         n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
1570                      no_fw_recovery ? "manual" : "auto",
1571                      sstate[wil->recovery_state]);
1572
1573         n = min_t(int, n, sizeof(buf));
1574
1575         return simple_read_from_buffer(user_buf, count, ppos,
1576                                        buf, n);
1577 }
1578
1579 static ssize_t wil_write_file_recovery(struct file *file,
1580                                        const char __user *buf_,
1581                                        size_t count, loff_t *ppos)
1582 {
1583         struct wil6210_priv *wil = file->private_data;
1584         static const char run_command[] = "run";
1585         char buf[sizeof(run_command) + 1]; /* to detect "runx" */
1586         ssize_t rc;
1587
1588         if (wil->recovery_state != fw_recovery_pending) {
1589                 wil_err(wil, "No recovery pending\n");
1590                 return -EINVAL;
1591         }
1592
1593         if (*ppos != 0) {
1594                 wil_err(wil, "Offset [%d]\n", (int)*ppos);
1595                 return -EINVAL;
1596         }
1597
1598         if (count > sizeof(buf)) {
1599                 wil_err(wil, "Input too long, len = %d\n", (int)count);
1600                 return -EINVAL;
1601         }
1602
1603         rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
1604         if (rc < 0)
1605                 return rc;
1606
1607         buf[rc] = '\0';
1608         if (0 == strcmp(buf, run_command))
1609                 wil_set_recovery_state(wil, fw_recovery_running);
1610         else
1611                 wil_err(wil, "Bad recovery command \"%s\"\n", buf);
1612
1613         return rc;
1614 }
1615
1616 static const struct file_operations fops_recovery = {
1617         .read = wil_read_file_recovery,
1618         .write = wil_write_file_recovery,
1619         .open  = simple_open,
1620 };
1621
1622 /*---------Station matrix------------*/
1623 static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
1624 {
1625         int i;
1626         u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
1627         unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old;
1628         unsigned long long drop_dup_mcast = r->drop_dup_mcast;
1629
1630         seq_printf(s, "([%2d]) 0x%03x [", r->buf_size, r->head_seq_num);
1631         for (i = 0; i < r->buf_size; i++) {
1632                 if (i == index)
1633                         seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
1634                 else
1635                         seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
1636         }
1637         seq_printf(s,
1638                    "] total %llu drop %llu (dup %llu + old %llu + dup mcast %llu) last 0x%03x\n",
1639                    r->total, drop_dup + drop_old + drop_dup_mcast, drop_dup,
1640                    drop_old, drop_dup_mcast, r->ssn_last_drop);
1641 }
1642
1643 static void wil_print_rxtid_crypto(struct seq_file *s, int tid,
1644                                    struct wil_tid_crypto_rx *c)
1645 {
1646         int i;
1647
1648         for (i = 0; i < 4; i++) {
1649                 struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
1650
1651                 if (cc->key_set)
1652                         goto has_keys;
1653         }
1654         return;
1655
1656 has_keys:
1657         if (tid < WIL_STA_TID_NUM)
1658                 seq_printf(s, "  [%2d] PN", tid);
1659         else
1660                 seq_puts(s, "  [GR] PN");
1661
1662         for (i = 0; i < 4; i++) {
1663                 struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
1664
1665                 seq_printf(s, " [%i%s]%6phN", i, cc->key_set ? "+" : "-",
1666                            cc->pn);
1667         }
1668         seq_puts(s, "\n");
1669 }
1670
1671 static int wil_sta_debugfs_show(struct seq_file *s, void *data)
1672 __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1673 {
1674         struct wil6210_priv *wil = s->private;
1675         int i, tid, mcs;
1676
1677         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1678                 struct wil_sta_info *p = &wil->sta[i];
1679                 char *status = "unknown";
1680                 u8 aid = 0;
1681                 u8 mid;
1682
1683                 switch (p->status) {
1684                 case wil_sta_unused:
1685                         status = "unused   ";
1686                         break;
1687                 case wil_sta_conn_pending:
1688                         status = "pending  ";
1689                         break;
1690                 case wil_sta_connected:
1691                         status = "connected";
1692                         aid = p->aid;
1693                         break;
1694                 }
1695                 mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
1696                 seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
1697                            mid, aid);
1698
1699                 if (p->status == wil_sta_connected) {
1700                         spin_lock_bh(&p->tid_rx_lock);
1701                         for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
1702                                 struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
1703                                 struct wil_tid_crypto_rx *c =
1704                                                 &p->tid_crypto_rx[tid];
1705
1706                                 if (r) {
1707                                         seq_printf(s, "  [%2d] ", tid);
1708                                         wil_print_rxtid(s, r);
1709                                 }
1710
1711                                 wil_print_rxtid_crypto(s, tid, c);
1712                         }
1713                         wil_print_rxtid_crypto(s, WIL_STA_TID_NUM,
1714                                                &p->group_crypto_rx);
1715                         spin_unlock_bh(&p->tid_rx_lock);
1716                         seq_printf(s,
1717                                    "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n",
1718                                    p->stats.rx_non_data_frame,
1719                                    p->stats.rx_short_frame,
1720                                    p->stats.rx_large_frame,
1721                                    p->stats.rx_replay);
1722                         seq_printf(s,
1723                                    "mic error %lu, key error %lu, amsdu error %lu, csum error %lu\n",
1724                                    p->stats.rx_mic_error,
1725                                    p->stats.rx_key_error,
1726                                    p->stats.rx_amsdu_error,
1727                                    p->stats.rx_csum_err);
1728
1729                         seq_puts(s, "Rx/MCS:");
1730                         for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
1731                              mcs++)
1732                                 seq_printf(s, " %lld",
1733                                            p->stats.rx_per_mcs[mcs]);
1734                         seq_puts(s, "\n");
1735                 }
1736         }
1737
1738         return 0;
1739 }
1740
1741 static int wil_sta_seq_open(struct inode *inode, struct file *file)
1742 {
1743         return single_open(file, wil_sta_debugfs_show, inode->i_private);
1744 }
1745
1746 static const struct file_operations fops_sta = {
1747         .open           = wil_sta_seq_open,
1748         .release        = single_release,
1749         .read           = seq_read,
1750         .llseek         = seq_lseek,
1751 };
1752
1753 static int wil_mids_debugfs_show(struct seq_file *s, void *data)
1754 {
1755         struct wil6210_priv *wil = s->private;
1756         struct wil6210_vif *vif;
1757         struct net_device *ndev;
1758         int i;
1759
1760         mutex_lock(&wil->vif_mutex);
1761         for (i = 0; i < wil->max_vifs; i++) {
1762                 vif = wil->vifs[i];
1763
1764                 if (vif) {
1765                         ndev = vif_to_ndev(vif);
1766                         seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr,
1767                                    ndev->name);
1768                 } else {
1769                         seq_printf(s, "[%d] unused\n", i);
1770                 }
1771         }
1772         mutex_unlock(&wil->vif_mutex);
1773
1774         return 0;
1775 }
1776
1777 static int wil_mids_seq_open(struct inode *inode, struct file *file)
1778 {
1779         return single_open(file, wil_mids_debugfs_show, inode->i_private);
1780 }
1781
1782 static const struct file_operations fops_mids = {
1783         .open           = wil_mids_seq_open,
1784         .release        = single_release,
1785         .read           = seq_read,
1786         .llseek         = seq_lseek,
1787 };
1788
1789 static int wil_tx_latency_debugfs_show(struct seq_file *s, void *data)
1790 __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1791 {
1792         struct wil6210_priv *wil = s->private;
1793         int i, bin;
1794
1795         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1796                 struct wil_sta_info *p = &wil->sta[i];
1797                 char *status = "unknown";
1798                 u8 aid = 0;
1799                 u8 mid;
1800
1801                 if (!p->tx_latency_bins)
1802                         continue;
1803
1804                 switch (p->status) {
1805                 case wil_sta_unused:
1806                         status = "unused   ";
1807                         break;
1808                 case wil_sta_conn_pending:
1809                         status = "pending  ";
1810                         break;
1811                 case wil_sta_connected:
1812                         status = "connected";
1813                         aid = p->aid;
1814                         break;
1815                 }
1816                 mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
1817                 seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
1818                            mid, aid);
1819
1820                 if (p->status == wil_sta_connected) {
1821                         u64 num_packets = 0;
1822                         u64 tx_latency_avg = p->stats.tx_latency_total_us;
1823
1824                         seq_puts(s, "Tx/Latency bin:");
1825                         for (bin = 0; bin < WIL_NUM_LATENCY_BINS; bin++) {
1826                                 seq_printf(s, " %lld",
1827                                            p->tx_latency_bins[bin]);
1828                                 num_packets += p->tx_latency_bins[bin];
1829                         }
1830                         seq_puts(s, "\n");
1831                         if (!num_packets)
1832                                 continue;
1833                         do_div(tx_latency_avg, num_packets);
1834                         seq_printf(s, "Tx/Latency min/avg/max (us): %d/%lld/%d",
1835                                    p->stats.tx_latency_min_us,
1836                                    tx_latency_avg,
1837                                    p->stats.tx_latency_max_us);
1838
1839                         seq_puts(s, "\n");
1840                 }
1841         }
1842
1843         return 0;
1844 }
1845
1846 static int wil_tx_latency_seq_open(struct inode *inode, struct file *file)
1847 {
1848         return single_open(file, wil_tx_latency_debugfs_show,
1849                            inode->i_private);
1850 }
1851
1852 static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf,
1853                                     size_t len, loff_t *ppos)
1854 {
1855         struct seq_file *s = file->private_data;
1856         struct wil6210_priv *wil = s->private;
1857         int val, rc, i;
1858         bool enable;
1859
1860         rc = kstrtoint_from_user(buf, len, 0, &val);
1861         if (rc) {
1862                 wil_err(wil, "Invalid argument\n");
1863                 return rc;
1864         }
1865         if (val == 1)
1866                 /* default resolution */
1867                 val = 500;
1868         if (val && (val < 50 || val > 1000)) {
1869                 wil_err(wil, "Invalid resolution %d\n", val);
1870                 return -EINVAL;
1871         }
1872
1873         enable = !!val;
1874         if (wil->tx_latency == enable)
1875                 return len;
1876
1877         wil_info(wil, "%s TX latency measurements (resolution %dusec)\n",
1878                  enable ? "Enabling" : "Disabling", val);
1879
1880         if (enable) {
1881                 size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS;
1882
1883                 wil->tx_latency_res = val;
1884                 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1885                         struct wil_sta_info *sta = &wil->sta[i];
1886
1887                         kfree(sta->tx_latency_bins);
1888                         sta->tx_latency_bins = kzalloc(sz, GFP_KERNEL);
1889                         if (!sta->tx_latency_bins)
1890                                 return -ENOMEM;
1891                         sta->stats.tx_latency_min_us = U32_MAX;
1892                         sta->stats.tx_latency_max_us = 0;
1893                         sta->stats.tx_latency_total_us = 0;
1894                 }
1895         }
1896         wil->tx_latency = enable;
1897
1898         return len;
1899 }
1900
1901 static const struct file_operations fops_tx_latency = {
1902         .open           = wil_tx_latency_seq_open,
1903         .release        = single_release,
1904         .read           = seq_read,
1905         .write          = wil_tx_latency_write,
1906         .llseek         = seq_lseek,
1907 };
1908
1909 static void wil_link_stats_print_basic(struct wil6210_vif *vif,
1910                                        struct seq_file *s,
1911                                        struct wmi_link_stats_basic *basic)
1912 {
1913         char per[5] = "?";
1914
1915         if (basic->per_average != 0xff)
1916                 snprintf(per, sizeof(per), "%d%%", basic->per_average);
1917
1918         seq_printf(s, "CID %d {\n"
1919                    "\tTxMCS %d TxTpt %d\n"
1920                    "\tGoodput(rx:tx) %d:%d\n"
1921                    "\tRxBcastFrames %d\n"
1922                    "\tRSSI %d SQI %d SNR %d PER %s\n"
1923                    "\tRx RFC %d Ant num %d\n"
1924                    "\tSectors(rx:tx) my %d:%d peer %d:%d\n"
1925                    "}\n",
1926                    basic->cid,
1927                    basic->bf_mcs, le32_to_cpu(basic->tx_tpt),
1928                    le32_to_cpu(basic->rx_goodput),
1929                    le32_to_cpu(basic->tx_goodput),
1930                    le32_to_cpu(basic->rx_bcast_frames),
1931                    basic->rssi, basic->sqi, basic->snr, per,
1932                    basic->selected_rfc, basic->rx_effective_ant_num,
1933                    basic->my_rx_sector, basic->my_tx_sector,
1934                    basic->other_rx_sector, basic->other_tx_sector);
1935 }
1936
1937 static void wil_link_stats_print_global(struct wil6210_priv *wil,
1938                                         struct seq_file *s,
1939                                         struct wmi_link_stats_global *global)
1940 {
1941         seq_printf(s, "Frames(rx:tx) %d:%d\n"
1942                    "BA Frames(rx:tx) %d:%d\n"
1943                    "Beacons %d\n"
1944                    "Rx Errors (MIC:CRC) %d:%d\n"
1945                    "Tx Errors (no ack) %d\n",
1946                    le32_to_cpu(global->rx_frames),
1947                    le32_to_cpu(global->tx_frames),
1948                    le32_to_cpu(global->rx_ba_frames),
1949                    le32_to_cpu(global->tx_ba_frames),
1950                    le32_to_cpu(global->tx_beacons),
1951                    le32_to_cpu(global->rx_mic_errors),
1952                    le32_to_cpu(global->rx_crc_errors),
1953                    le32_to_cpu(global->tx_fail_no_ack));
1954 }
1955
1956 static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif,
1957                                             struct seq_file *s)
1958 {
1959         struct wil6210_priv *wil = vif_to_wil(vif);
1960         struct wmi_link_stats_basic *stats;
1961         int i;
1962
1963         if (!vif->fw_stats_ready) {
1964                 seq_puts(s, "no statistics\n");
1965                 return;
1966         }
1967
1968         seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf);
1969         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1970                 if (wil->sta[i].status == wil_sta_unused)
1971                         continue;
1972                 if (wil->sta[i].mid != vif->mid)
1973                         continue;
1974
1975                 stats = &wil->sta[i].fw_stats_basic;
1976                 wil_link_stats_print_basic(vif, s, stats);
1977         }
1978 }
1979
1980 static int wil_link_stats_debugfs_show(struct seq_file *s, void *data)
1981 {
1982         struct wil6210_priv *wil = s->private;
1983         struct wil6210_vif *vif;
1984         int i, rc;
1985
1986         rc = mutex_lock_interruptible(&wil->vif_mutex);
1987         if (rc)
1988                 return rc;
1989
1990         /* iterate over all MIDs and show per-cid statistics. Then show the
1991          * global statistics
1992          */
1993         for (i = 0; i < wil->max_vifs; i++) {
1994                 vif = wil->vifs[i];
1995
1996                 seq_printf(s, "MID %d ", i);
1997                 if (!vif) {
1998                         seq_puts(s, "unused\n");
1999                         continue;
2000                 }
2001
2002                 wil_link_stats_debugfs_show_vif(vif, s);
2003         }
2004
2005         mutex_unlock(&wil->vif_mutex);
2006
2007         return 0;
2008 }
2009
2010 static int wil_link_stats_seq_open(struct inode *inode, struct file *file)
2011 {
2012         return single_open(file, wil_link_stats_debugfs_show, inode->i_private);
2013 }
2014
2015 static ssize_t wil_link_stats_write(struct file *file, const char __user *buf,
2016                                     size_t len, loff_t *ppos)
2017 {
2018         struct seq_file *s = file->private_data;
2019         struct wil6210_priv *wil = s->private;
2020         int cid, interval, rc, i;
2021         struct wil6210_vif *vif;
2022         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
2023
2024         if (!kbuf)
2025                 return -ENOMEM;
2026
2027         rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
2028         if (rc != len) {
2029                 kfree(kbuf);
2030                 return rc >= 0 ? -EIO : rc;
2031         }
2032
2033         kbuf[len] = '\0';
2034         /* specify cid (use -1 for all cids) and snapshot interval in ms */
2035         rc = sscanf(kbuf, "%d %d", &cid, &interval);
2036         kfree(kbuf);
2037         if (rc < 0)
2038                 return rc;
2039         if (rc < 2 || interval < 0)
2040                 return -EINVAL;
2041
2042         wil_info(wil, "request link statistics, cid %d interval %d\n",
2043                  cid, interval);
2044
2045         rc = mutex_lock_interruptible(&wil->vif_mutex);
2046         if (rc)
2047                 return rc;
2048
2049         for (i = 0; i < wil->max_vifs; i++) {
2050                 vif = wil->vifs[i];
2051                 if (!vif)
2052                         continue;
2053
2054                 rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_BASIC,
2055                                         (cid == -1 ? 0xff : cid), interval);
2056                 if (rc)
2057                         wil_err(wil, "link statistics failed for mid %d\n", i);
2058         }
2059         mutex_unlock(&wil->vif_mutex);
2060
2061         return len;
2062 }
2063
2064 static const struct file_operations fops_link_stats = {
2065         .open           = wil_link_stats_seq_open,
2066         .release        = single_release,
2067         .read           = seq_read,
2068         .write          = wil_link_stats_write,
2069         .llseek         = seq_lseek,
2070 };
2071
2072 static int
2073 wil_link_stats_global_debugfs_show(struct seq_file *s, void *data)
2074 {
2075         struct wil6210_priv *wil = s->private;
2076
2077         if (!wil->fw_stats_global.ready)
2078                 return 0;
2079
2080         seq_printf(s, "TSF %lld\n", wil->fw_stats_global.tsf);
2081         wil_link_stats_print_global(wil, s, &wil->fw_stats_global.stats);
2082
2083         return 0;
2084 }
2085
2086 static int
2087 wil_link_stats_global_seq_open(struct inode *inode, struct file *file)
2088 {
2089         return single_open(file, wil_link_stats_global_debugfs_show,
2090                            inode->i_private);
2091 }
2092
2093 static ssize_t
2094 wil_link_stats_global_write(struct file *file, const char __user *buf,
2095                             size_t len, loff_t *ppos)
2096 {
2097         struct seq_file *s = file->private_data;
2098         struct wil6210_priv *wil = s->private;
2099         int interval, rc;
2100         struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2101
2102         /* specify snapshot interval in ms */
2103         rc = kstrtoint_from_user(buf, len, 0, &interval);
2104         if (rc || interval < 0) {
2105                 wil_err(wil, "Invalid argument\n");
2106                 return -EINVAL;
2107         }
2108
2109         wil_info(wil, "request global link stats, interval %d\n", interval);
2110
2111         rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_GLOBAL, 0, interval);
2112         if (rc)
2113                 wil_err(wil, "global link stats failed %d\n", rc);
2114
2115         return rc ? rc : len;
2116 }
2117
2118 static const struct file_operations fops_link_stats_global = {
2119         .open           = wil_link_stats_global_seq_open,
2120         .release        = single_release,
2121         .read           = seq_read,
2122         .write          = wil_link_stats_global_write,
2123         .llseek         = seq_lseek,
2124 };
2125
2126 static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
2127                                      size_t count, loff_t *ppos)
2128 {
2129         char buf[80];
2130         int n;
2131
2132         n = snprintf(buf, sizeof(buf),
2133                      "led_id is set to %d, echo 1 to enable, 0 to disable\n",
2134                      led_id);
2135
2136         n = min_t(int, n, sizeof(buf));
2137
2138         return simple_read_from_buffer(user_buf, count, ppos,
2139                                        buf, n);
2140 }
2141
2142 static ssize_t wil_write_file_led_cfg(struct file *file,
2143                                       const char __user *buf_,
2144                                       size_t count, loff_t *ppos)
2145 {
2146         struct wil6210_priv *wil = file->private_data;
2147         int val;
2148         int rc;
2149
2150         rc = kstrtoint_from_user(buf_, count, 0, &val);
2151         if (rc) {
2152                 wil_err(wil, "Invalid argument\n");
2153                 return rc;
2154         }
2155
2156         wil_info(wil, "%s led %d\n", val ? "Enabling" : "Disabling", led_id);
2157         rc = wmi_led_cfg(wil, val);
2158         if (rc) {
2159                 wil_info(wil, "%s led %d failed\n",
2160                          val ? "Enabling" : "Disabling", led_id);
2161                 return rc;
2162         }
2163
2164         return count;
2165 }
2166
2167 static const struct file_operations fops_led_cfg = {
2168         .read = wil_read_file_led_cfg,
2169         .write = wil_write_file_led_cfg,
2170         .open  = simple_open,
2171 };
2172
2173 /* led_blink_time, write:
2174  * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
2175  */
2176 static ssize_t wil_write_led_blink_time(struct file *file,
2177                                         const char __user *buf,
2178                                         size_t len, loff_t *ppos)
2179 {
2180         int rc;
2181         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
2182
2183         if (!kbuf)
2184                 return -ENOMEM;
2185
2186         rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
2187         if (rc != len) {
2188                 kfree(kbuf);
2189                 return rc >= 0 ? -EIO : rc;
2190         }
2191
2192         kbuf[len] = '\0';
2193         rc = sscanf(kbuf, "%d %d %d %d %d %d",
2194                     &led_blink_time[WIL_LED_TIME_SLOW].on_ms,
2195                     &led_blink_time[WIL_LED_TIME_SLOW].off_ms,
2196                     &led_blink_time[WIL_LED_TIME_MED].on_ms,
2197                     &led_blink_time[WIL_LED_TIME_MED].off_ms,
2198                     &led_blink_time[WIL_LED_TIME_FAST].on_ms,
2199                     &led_blink_time[WIL_LED_TIME_FAST].off_ms);
2200         kfree(kbuf);
2201
2202         if (rc < 0)
2203                 return rc;
2204         if (rc < 6)
2205                 return -EINVAL;
2206
2207         return len;
2208 }
2209
2210 static ssize_t wil_read_led_blink_time(struct file *file, char __user *user_buf,
2211                                        size_t count, loff_t *ppos)
2212 {
2213         static char text[400];
2214
2215         snprintf(text, sizeof(text),
2216                  "To set led blink on/off time variables write:\n"
2217                  "<blink_on_slow> <blink_off_slow> <blink_on_med> "
2218                  "<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
2219                  "The current values are:\n"
2220                  "%d %d %d %d %d %d\n",
2221                  led_blink_time[WIL_LED_TIME_SLOW].on_ms,
2222                  led_blink_time[WIL_LED_TIME_SLOW].off_ms,
2223                  led_blink_time[WIL_LED_TIME_MED].on_ms,
2224                  led_blink_time[WIL_LED_TIME_MED].off_ms,
2225                  led_blink_time[WIL_LED_TIME_FAST].on_ms,
2226                  led_blink_time[WIL_LED_TIME_FAST].off_ms);
2227
2228         return simple_read_from_buffer(user_buf, count, ppos, text,
2229                                        sizeof(text));
2230 }
2231
2232 static const struct file_operations fops_led_blink_time = {
2233         .read = wil_read_led_blink_time,
2234         .write = wil_write_led_blink_time,
2235         .open  = simple_open,
2236 };
2237
2238 /*---------FW capabilities------------*/
2239 static int wil_fw_capabilities_debugfs_show(struct seq_file *s, void *data)
2240 {
2241         struct wil6210_priv *wil = s->private;
2242
2243         seq_printf(s, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX,
2244                    wil->fw_capabilities);
2245
2246         return 0;
2247 }
2248
2249 static int wil_fw_capabilities_seq_open(struct inode *inode, struct file *file)
2250 {
2251         return single_open(file, wil_fw_capabilities_debugfs_show,
2252                            inode->i_private);
2253 }
2254
2255 static const struct file_operations fops_fw_capabilities = {
2256         .open           = wil_fw_capabilities_seq_open,
2257         .release        = single_release,
2258         .read           = seq_read,
2259         .llseek         = seq_lseek,
2260 };
2261
2262 /*---------FW version------------*/
2263 static int wil_fw_version_debugfs_show(struct seq_file *s, void *data)
2264 {
2265         struct wil6210_priv *wil = s->private;
2266
2267         if (wil->fw_version[0])
2268                 seq_printf(s, "%s\n", wil->fw_version);
2269         else
2270                 seq_puts(s, "N/A\n");
2271
2272         return 0;
2273 }
2274
2275 static int wil_fw_version_seq_open(struct inode *inode, struct file *file)
2276 {
2277         return single_open(file, wil_fw_version_debugfs_show,
2278                            inode->i_private);
2279 }
2280
2281 static const struct file_operations fops_fw_version = {
2282         .open           = wil_fw_version_seq_open,
2283         .release        = single_release,
2284         .read           = seq_read,
2285         .llseek         = seq_lseek,
2286 };
2287
2288 /*---------suspend_stats---------*/
2289 static ssize_t wil_write_suspend_stats(struct file *file,
2290                                        const char __user *buf,
2291                                        size_t len, loff_t *ppos)
2292 {
2293         struct wil6210_priv *wil = file->private_data;
2294
2295         memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
2296
2297         return len;
2298 }
2299
2300 static ssize_t wil_read_suspend_stats(struct file *file,
2301                                       char __user *user_buf,
2302                                       size_t count, loff_t *ppos)
2303 {
2304         struct wil6210_priv *wil = file->private_data;
2305         char *text;
2306         int n, ret, text_size = 500;
2307
2308         text = kmalloc(text_size, GFP_KERNEL);
2309         if (!text)
2310                 return -ENOMEM;
2311
2312         n = snprintf(text, text_size,
2313                      "Radio on suspend statistics:\n"
2314                      "successful suspends:%ld failed suspends:%ld\n"
2315                      "successful resumes:%ld failed resumes:%ld\n"
2316                      "rejected by device:%ld\n"
2317                      "Radio off suspend statistics:\n"
2318                      "successful suspends:%ld failed suspends:%ld\n"
2319                      "successful resumes:%ld failed resumes:%ld\n"
2320                      "General statistics:\n"
2321                      "rejected by host:%ld\n",
2322                      wil->suspend_stats.r_on.successful_suspends,
2323                      wil->suspend_stats.r_on.failed_suspends,
2324                      wil->suspend_stats.r_on.successful_resumes,
2325                      wil->suspend_stats.r_on.failed_resumes,
2326                      wil->suspend_stats.rejected_by_device,
2327                      wil->suspend_stats.r_off.successful_suspends,
2328                      wil->suspend_stats.r_off.failed_suspends,
2329                      wil->suspend_stats.r_off.successful_resumes,
2330                      wil->suspend_stats.r_off.failed_resumes,
2331                      wil->suspend_stats.rejected_by_host);
2332
2333         n = min_t(int, n, text_size);
2334
2335         ret = simple_read_from_buffer(user_buf, count, ppos, text, n);
2336
2337         kfree(text);
2338
2339         return ret;
2340 }
2341
2342 static const struct file_operations fops_suspend_stats = {
2343         .read = wil_read_suspend_stats,
2344         .write = wil_write_suspend_stats,
2345         .open  = simple_open,
2346 };
2347
2348 /*---------compressed_rx_status---------*/
2349 static ssize_t wil_compressed_rx_status_write(struct file *file,
2350                                               const char __user *buf,
2351                                               size_t len, loff_t *ppos)
2352 {
2353         struct seq_file *s = file->private_data;
2354         struct wil6210_priv *wil = s->private;
2355         int compressed_rx_status;
2356         int rc;
2357
2358         rc = kstrtoint_from_user(buf, len, 0, &compressed_rx_status);
2359         if (rc) {
2360                 wil_err(wil, "Invalid argument\n");
2361                 return rc;
2362         }
2363
2364         if (wil_has_active_ifaces(wil, true, false)) {
2365                 wil_err(wil, "cannot change edma config after iface is up\n");
2366                 return -EPERM;
2367         }
2368
2369         wil_info(wil, "%sable compressed_rx_status\n",
2370                  compressed_rx_status ? "En" : "Dis");
2371
2372         wil->use_compressed_rx_status = compressed_rx_status;
2373
2374         return len;
2375 }
2376
2377 static int
2378 wil_compressed_rx_status_show(struct seq_file *s, void *data)
2379 {
2380         struct wil6210_priv *wil = s->private;
2381
2382         seq_printf(s, "%d\n", wil->use_compressed_rx_status);
2383
2384         return 0;
2385 }
2386
2387 static int
2388 wil_compressed_rx_status_seq_open(struct inode *inode, struct file *file)
2389 {
2390         return single_open(file, wil_compressed_rx_status_show,
2391                            inode->i_private);
2392 }
2393
2394 static const struct file_operations fops_compressed_rx_status = {
2395         .open  = wil_compressed_rx_status_seq_open,
2396         .release = single_release,
2397         .read = seq_read,
2398         .write = wil_compressed_rx_status_write,
2399         .llseek = seq_lseek,
2400 };
2401
2402 /*----------------*/
2403 static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
2404                                        struct dentry *dbg)
2405 {
2406         int i;
2407         char name[32];
2408
2409         for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
2410                 struct wil_blob_wrapper *wil_blob = &wil->blobs[i];
2411                 struct debugfs_blob_wrapper *blob = &wil_blob->blob;
2412                 const struct fw_map *map = &fw_mapping[i];
2413
2414                 if (!map->name)
2415                         continue;
2416
2417                 wil_blob->wil = wil;
2418                 blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
2419                 blob->size = map->to - map->from;
2420                 snprintf(name, sizeof(name), "blob_%s", map->name);
2421                 wil_debugfs_create_ioblob(name, 0444, dbg, wil_blob);
2422         }
2423 }
2424
2425 /* misc files */
2426 static const struct {
2427         const char *name;
2428         umode_t mode;
2429         const struct file_operations *fops;
2430 } dbg_files[] = {
2431         {"mbox",        0444,           &fops_mbox},
2432         {"rings",       0444,           &fops_ring},
2433         {"stations", 0444,              &fops_sta},
2434         {"mids",        0444,           &fops_mids},
2435         {"desc",        0444,           &fops_txdesc},
2436         {"bf",          0444,           &fops_bf},
2437         {"mem_val",     0644,           &fops_memread},
2438         {"rxon",        0244,           &fops_rxon},
2439         {"tx_mgmt",     0244,           &fops_txmgmt},
2440         {"wmi_send", 0244,              &fops_wmi},
2441         {"back",        0644,           &fops_back},
2442         {"pmccfg",      0644,           &fops_pmccfg},
2443         {"pmcdata",     0444,           &fops_pmcdata},
2444         {"temp",        0444,           &fops_temp},
2445         {"freq",        0444,           &fops_freq},
2446         {"link",        0444,           &fops_link},
2447         {"info",        0444,           &fops_info},
2448         {"recovery", 0644,              &fops_recovery},
2449         {"led_cfg",     0644,           &fops_led_cfg},
2450         {"led_blink_time",      0644,   &fops_led_blink_time},
2451         {"fw_capabilities",     0444,   &fops_fw_capabilities},
2452         {"fw_version",  0444,           &fops_fw_version},
2453         {"suspend_stats",       0644,   &fops_suspend_stats},
2454         {"compressed_rx_status", 0644,  &fops_compressed_rx_status},
2455         {"srings",      0444,           &fops_srings},
2456         {"status_msg",  0444,           &fops_status_msg},
2457         {"rx_buff_mgmt",        0444,   &fops_rx_buff_mgmt},
2458         {"tx_latency",  0644,           &fops_tx_latency},
2459         {"link_stats",  0644,           &fops_link_stats},
2460         {"link_stats_global",   0644,   &fops_link_stats_global},
2461 };
2462
2463 static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
2464                                        struct dentry *dbg)
2465 {
2466         int i;
2467
2468         for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
2469                 debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
2470                                     wil, dbg_files[i].fops);
2471 }
2472
2473 /* interrupt control blocks */
2474 static const struct {
2475         const char *name;
2476         u32 icr_off;
2477 } dbg_icr[] = {
2478         {"USER_ICR",            HOSTADDR(RGF_USER_USER_ICR)},
2479         {"DMA_EP_TX_ICR",       HOSTADDR(RGF_DMA_EP_TX_ICR)},
2480         {"DMA_EP_RX_ICR",       HOSTADDR(RGF_DMA_EP_RX_ICR)},
2481         {"DMA_EP_MISC_ICR",     HOSTADDR(RGF_DMA_EP_MISC_ICR)},
2482 };
2483
2484 static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
2485                                      struct dentry *dbg)
2486 {
2487         int i;
2488
2489         for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
2490                 wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
2491                                            dbg_icr[i].icr_off);
2492 }
2493
2494 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
2495         offsetof(struct wil6210_priv, name), type}
2496
2497 /* fields in struct wil6210_priv */
2498 static const struct dbg_off dbg_wil_off[] = {
2499         WIL_FIELD(status[0],    0644,   doff_ulong),
2500         WIL_FIELD(hw_version,   0444,   doff_x32),
2501         WIL_FIELD(recovery_count, 0444, doff_u32),
2502         WIL_FIELD(discovery_mode, 0644, doff_u8),
2503         WIL_FIELD(chip_revision, 0444,  doff_u8),
2504         WIL_FIELD(abft_len, 0644,               doff_u8),
2505         WIL_FIELD(wakeup_trigger, 0644,         doff_u8),
2506         WIL_FIELD(ring_idle_trsh, 0644, doff_u32),
2507         WIL_FIELD(num_rx_status_rings, 0644,    doff_u8),
2508         WIL_FIELD(rx_status_ring_order, 0644,   doff_u32),
2509         WIL_FIELD(tx_status_ring_order, 0644,   doff_u32),
2510         WIL_FIELD(rx_buff_id_count, 0644,       doff_u32),
2511         WIL_FIELD(amsdu_en, 0644,       doff_u8),
2512         {},
2513 };
2514
2515 static const struct dbg_off dbg_wil_regs[] = {
2516         {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
2517                 doff_io32},
2518         {"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
2519         {},
2520 };
2521
2522 /* static parameters */
2523 static const struct dbg_off dbg_statics[] = {
2524         {"desc_index",  0644, (ulong)&dbg_txdesc_index, doff_u32},
2525         {"ring_index",  0644, (ulong)&dbg_ring_index, doff_u32},
2526         {"mem_addr",    0644, (ulong)&mem_addr, doff_u32},
2527         {"led_polarity", 0644, (ulong)&led_polarity, doff_u8},
2528         {"status_index", 0644, (ulong)&dbg_status_msg_index, doff_u32},
2529         {"sring_index", 0644, (ulong)&dbg_sring_index, doff_u32},
2530         {},
2531 };
2532
2533 static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) +
2534                                 ARRAY_SIZE(dbg_wil_regs) - 1 +
2535                                 ARRAY_SIZE(pseudo_isr_off) - 1 +
2536                                 ARRAY_SIZE(lgc_itr_cnt_off) - 1 +
2537                                 ARRAY_SIZE(tx_itr_cnt_off) - 1 +
2538                                 ARRAY_SIZE(rx_itr_cnt_off) - 1;
2539
2540 int wil6210_debugfs_init(struct wil6210_priv *wil)
2541 {
2542         struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
2543                         wil_to_wiphy(wil)->debugfsdir);
2544         if (IS_ERR_OR_NULL(dbg))
2545                 return -ENODEV;
2546
2547         wil->dbg_data.data_arr = kcalloc(dbg_off_count,
2548                                          sizeof(struct wil_debugfs_iomem_data),
2549                                          GFP_KERNEL);
2550         if (!wil->dbg_data.data_arr) {
2551                 debugfs_remove_recursive(dbg);
2552                 wil->debug = NULL;
2553                 return -ENOMEM;
2554         }
2555
2556         wil->dbg_data.iomem_data_count = 0;
2557
2558         wil_pmc_init(wil);
2559
2560         wil6210_debugfs_init_files(wil, dbg);
2561         wil6210_debugfs_init_isr(wil, dbg);
2562         wil6210_debugfs_init_blobs(wil, dbg);
2563         wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
2564         wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
2565                                     dbg_wil_regs);
2566         wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
2567
2568         wil6210_debugfs_create_pseudo_ISR(wil, dbg);
2569
2570         wil6210_debugfs_create_ITR_CNT(wil, dbg);
2571
2572         return 0;
2573 }
2574
2575 void wil6210_debugfs_remove(struct wil6210_priv *wil)
2576 {
2577         int i;
2578
2579         debugfs_remove_recursive(wil->debug);
2580         wil->debug = NULL;
2581
2582         kfree(wil->dbg_data.data_arr);
2583         for (i = 0; i < ARRAY_SIZE(wil->sta); i++)
2584                 kfree(wil->sta[i].tx_latency_bins);
2585
2586         /* free pmc memory without sending command to fw, as it will
2587          * be reset on the way down anyway
2588          */
2589         wil_pmc_free(wil, false);
2590 }