GNU Linux-libre 4.19.264-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 rc1;
1006
1007         if (cmdlen < 0 || *ppos != 0)
1008                 return -EINVAL;
1009
1010         wmi = memdup_user(buf, len);
1011         if (IS_ERR(wmi))
1012                 return PTR_ERR(wmi);
1013
1014         cmd = (cmdlen > 0) ? &wmi[1] : NULL;
1015         cmdid = le16_to_cpu(wmi->command_id);
1016
1017         rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen);
1018         kfree(wmi);
1019
1020         wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
1021
1022         return len;
1023 }
1024
1025 static const struct file_operations fops_wmi = {
1026         .write = wil_write_file_wmi,
1027         .open  = simple_open,
1028 };
1029
1030 static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
1031 {
1032         int i = 0;
1033         int len = skb_headlen(skb);
1034         void *p = skb->data;
1035         int nr_frags = skb_shinfo(skb)->nr_frags;
1036
1037         seq_printf(s, "    len = %d\n", len);
1038         wil_seq_hexdump(s, p, len, "      : ");
1039
1040         if (nr_frags) {
1041                 seq_printf(s, "    nr_frags = %d\n", nr_frags);
1042                 for (i = 0; i < nr_frags; i++) {
1043                         const struct skb_frag_struct *frag =
1044                                         &skb_shinfo(skb)->frags[i];
1045
1046                         len = skb_frag_size(frag);
1047                         p = skb_frag_address_safe(frag);
1048                         seq_printf(s, "    [%2d] : len = %d\n", i, len);
1049                         wil_seq_hexdump(s, p, len, "      : ");
1050                 }
1051         }
1052 }
1053
1054 /*---------Tx/Rx descriptor------------*/
1055 static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
1056 {
1057         struct wil6210_priv *wil = s->private;
1058         struct wil_ring *ring;
1059         bool tx;
1060         int ring_idx = dbg_ring_index;
1061         int txdesc_idx = dbg_txdesc_index;
1062         volatile struct vring_tx_desc *d;
1063         volatile u32 *u;
1064         struct sk_buff *skb;
1065
1066         if (wil->use_enhanced_dma_hw) {
1067                 /* RX ring index == 0 */
1068                 if (ring_idx >= WIL6210_MAX_TX_RINGS) {
1069                         seq_printf(s, "invalid ring index %d\n", ring_idx);
1070                         return 0;
1071                 }
1072                 tx = ring_idx > 0; /* desc ring 0 is reserved for RX */
1073         } else {
1074                 /* RX ring index == WIL6210_MAX_TX_RINGS */
1075                 if (ring_idx > WIL6210_MAX_TX_RINGS) {
1076                         seq_printf(s, "invalid ring index %d\n", ring_idx);
1077                         return 0;
1078                 }
1079                 tx = (ring_idx < WIL6210_MAX_TX_RINGS);
1080         }
1081
1082         ring = tx ? &wil->ring_tx[ring_idx] : &wil->ring_rx;
1083
1084         if (!ring->va) {
1085                 if (tx)
1086                         seq_printf(s, "No Tx[%2d] RING\n", ring_idx);
1087                 else
1088                         seq_puts(s, "No Rx RING\n");
1089                 return 0;
1090         }
1091
1092         if (txdesc_idx >= ring->size) {
1093                 if (tx)
1094                         seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
1095                                    ring_idx, txdesc_idx, ring->size);
1096                 else
1097                         seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
1098                                    txdesc_idx, ring->size);
1099                 return 0;
1100         }
1101
1102         /* use struct vring_tx_desc for Rx as well,
1103          * only field used, .dma.length, is the same
1104          */
1105         d = &ring->va[txdesc_idx].tx.legacy;
1106         u = (volatile u32 *)d;
1107         skb = NULL;
1108
1109         if (wil->use_enhanced_dma_hw) {
1110                 if (tx) {
1111                         skb = ring->ctx[txdesc_idx].skb;
1112                 } else {
1113                         struct wil_rx_enhanced_desc *rx_d =
1114                                 (struct wil_rx_enhanced_desc *)
1115                                 &ring->va[txdesc_idx].rx.enhanced;
1116                         u16 buff_id = le16_to_cpu(rx_d->mac.buff_id);
1117
1118                         if (!wil_val_in_range(buff_id, 0,
1119                                               wil->rx_buff_mgmt.size)) {
1120                                 seq_printf(s, "invalid buff_id %d\n", buff_id);
1121                                 return 0;
1122                         }
1123                         skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
1124                 }
1125         } else {
1126                 skb = ring->ctx[txdesc_idx].skb;
1127         }
1128         if (tx)
1129                 seq_printf(s, "Tx[%2d][%3d] = {\n", ring_idx,
1130                            txdesc_idx);
1131         else
1132                 seq_printf(s, "Rx[%3d] = {\n", txdesc_idx);
1133         seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1134                    u[0], u[1], u[2], u[3]);
1135         seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1136                    u[4], u[5], u[6], u[7]);
1137         seq_printf(s, "  SKB = 0x%p\n", skb);
1138
1139         if (skb) {
1140                 skb_get(skb);
1141                 wil_seq_print_skb(s, skb);
1142                 kfree_skb(skb);
1143         }
1144         seq_puts(s, "}\n");
1145
1146         return 0;
1147 }
1148
1149 static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
1150 {
1151         return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
1152 }
1153
1154 static const struct file_operations fops_txdesc = {
1155         .open           = wil_txdesc_seq_open,
1156         .release        = single_release,
1157         .read           = seq_read,
1158         .llseek         = seq_lseek,
1159 };
1160
1161 /*---------Tx/Rx status message------------*/
1162 static int wil_status_msg_debugfs_show(struct seq_file *s, void *data)
1163 {
1164         struct wil6210_priv *wil = s->private;
1165         int sring_idx = dbg_sring_index;
1166         struct wil_status_ring *sring;
1167         bool tx = sring_idx == wil->tx_sring_idx ? 1 : 0;
1168         u32 status_msg_idx = dbg_status_msg_index;
1169         u32 *u;
1170
1171         if (sring_idx >= WIL6210_MAX_STATUS_RINGS) {
1172                 seq_printf(s, "invalid status ring index %d\n", sring_idx);
1173                 return 0;
1174         }
1175
1176         sring = &wil->srings[sring_idx];
1177
1178         if (!sring->va) {
1179                 seq_printf(s, "No %cX status ring\n", tx ? 'T' : 'R');
1180                 return 0;
1181         }
1182
1183         if (status_msg_idx >= sring->size) {
1184                 seq_printf(s, "%cxDesc index (%d) >= size (%d)\n",
1185                            tx ? 'T' : 'R', status_msg_idx, sring->size);
1186                 return 0;
1187         }
1188
1189         u = sring->va + (sring->elem_size * status_msg_idx);
1190
1191         seq_printf(s, "%cx[%d][%3d] = {\n",
1192                    tx ? 'T' : 'R', sring_idx, status_msg_idx);
1193
1194         seq_printf(s, "  0x%08x 0x%08x 0x%08x 0x%08x\n",
1195                    u[0], u[1], u[2], u[3]);
1196         if (!tx && !wil->use_compressed_rx_status)
1197                 seq_printf(s, "  0x%08x 0x%08x 0x%08x 0x%08x\n",
1198                            u[4], u[5], u[6], u[7]);
1199
1200         seq_puts(s, "}\n");
1201
1202         return 0;
1203 }
1204
1205 static int wil_status_msg_seq_open(struct inode *inode, struct file *file)
1206 {
1207         return single_open(file, wil_status_msg_debugfs_show,
1208                            inode->i_private);
1209 }
1210
1211 static const struct file_operations fops_status_msg = {
1212         .open           = wil_status_msg_seq_open,
1213         .release        = single_release,
1214         .read           = seq_read,
1215         .llseek         = seq_lseek,
1216 };
1217
1218 static int wil_print_rx_buff(struct seq_file *s, struct list_head *lh)
1219 {
1220         struct wil_rx_buff *it;
1221         int i = 0;
1222
1223         list_for_each_entry(it, lh, list) {
1224                 if ((i % 16) == 0 && i != 0)
1225                         seq_puts(s, "\n    ");
1226                 seq_printf(s, "[%4d] ", it->id);
1227                 i++;
1228         }
1229         seq_printf(s, "\nNumber of buffers: %u\n", i);
1230
1231         return i;
1232 }
1233
1234 static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data)
1235 {
1236         struct wil6210_priv *wil = s->private;
1237         struct wil_rx_buff_mgmt *rbm = &wil->rx_buff_mgmt;
1238         int num_active;
1239         int num_free;
1240
1241         if (!rbm->buff_arr)
1242                 return -EINVAL;
1243
1244         seq_printf(s, "  size = %zu\n", rbm->size);
1245         seq_printf(s, "  free_list_empty_cnt = %lu\n",
1246                    rbm->free_list_empty_cnt);
1247
1248         /* Print active list */
1249         seq_puts(s, "  Active list:\n");
1250         num_active = wil_print_rx_buff(s, &rbm->active);
1251         seq_puts(s, "\n  Free list:\n");
1252         num_free = wil_print_rx_buff(s, &rbm->free);
1253
1254         seq_printf(s, "  Total number of buffers: %u\n",
1255                    num_active + num_free);
1256
1257         return 0;
1258 }
1259
1260 static int wil_rx_buff_mgmt_seq_open(struct inode *inode, struct file *file)
1261 {
1262         return single_open(file, wil_rx_buff_mgmt_debugfs_show,
1263                            inode->i_private);
1264 }
1265
1266 static const struct file_operations fops_rx_buff_mgmt = {
1267         .open           = wil_rx_buff_mgmt_seq_open,
1268         .release        = single_release,
1269         .read           = seq_read,
1270         .llseek         = seq_lseek,
1271 };
1272
1273 /*---------beamforming------------*/
1274 static char *wil_bfstatus_str(u32 status)
1275 {
1276         switch (status) {
1277         case 0:
1278                 return "Failed";
1279         case 1:
1280                 return "OK";
1281         case 2:
1282                 return "Retrying";
1283         default:
1284                 return "??";
1285         }
1286 }
1287
1288 static bool is_all_zeros(void * const x_, size_t sz)
1289 {
1290         /* if reply is all-0, ignore this CID */
1291         u32 *x = x_;
1292         int n;
1293
1294         for (n = 0; n < sz / sizeof(*x); n++)
1295                 if (x[n])
1296                         return false;
1297
1298         return true;
1299 }
1300
1301 static int wil_bf_debugfs_show(struct seq_file *s, void *data)
1302 {
1303         int rc;
1304         int i;
1305         struct wil6210_priv *wil = s->private;
1306         struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
1307         struct wmi_notify_req_cmd cmd = {
1308                 .interval_usec = 0,
1309         };
1310         struct {
1311                 struct wmi_cmd_hdr wmi;
1312                 struct wmi_notify_req_done_event evt;
1313         } __packed reply;
1314
1315         memset(&reply, 0, sizeof(reply));
1316
1317         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1318                 u32 status;
1319
1320                 cmd.cid = i;
1321                 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid,
1322                               &cmd, sizeof(cmd),
1323                               WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
1324                               sizeof(reply), 20);
1325                 /* if reply is all-0, ignore this CID */
1326                 if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
1327                         continue;
1328
1329                 status = le32_to_cpu(reply.evt.status);
1330                 seq_printf(s, "CID %d {\n"
1331                            "  TSF = 0x%016llx\n"
1332                            "  TxMCS = %2d TxTpt = %4d\n"
1333                            "  SQI = %4d\n"
1334                            "  RSSI = %4d\n"
1335                            "  Status = 0x%08x %s\n"
1336                            "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
1337                            "  Goodput(rx:tx) %4d:%4d\n"
1338                            "}\n",
1339                            i,
1340                            le64_to_cpu(reply.evt.tsf),
1341                            le16_to_cpu(reply.evt.bf_mcs),
1342                            le32_to_cpu(reply.evt.tx_tpt),
1343                            reply.evt.sqi,
1344                            reply.evt.rssi,
1345                            status, wil_bfstatus_str(status),
1346                            le16_to_cpu(reply.evt.my_rx_sector),
1347                            le16_to_cpu(reply.evt.my_tx_sector),
1348                            le16_to_cpu(reply.evt.other_rx_sector),
1349                            le16_to_cpu(reply.evt.other_tx_sector),
1350                            le32_to_cpu(reply.evt.rx_goodput),
1351                            le32_to_cpu(reply.evt.tx_goodput));
1352         }
1353         return 0;
1354 }
1355
1356 static int wil_bf_seq_open(struct inode *inode, struct file *file)
1357 {
1358         return single_open(file, wil_bf_debugfs_show, inode->i_private);
1359 }
1360
1361 static const struct file_operations fops_bf = {
1362         .open           = wil_bf_seq_open,
1363         .release        = single_release,
1364         .read           = seq_read,
1365         .llseek         = seq_lseek,
1366 };
1367
1368 /*---------temp------------*/
1369 static void print_temp(struct seq_file *s, const char *prefix, s32 t)
1370 {
1371         switch (t) {
1372         case 0:
1373         case ~(u32)0:
1374                 seq_printf(s, "%s N/A\n", prefix);
1375         break;
1376         default:
1377                 seq_printf(s, "%s %s%d.%03d\n", prefix, (t < 0 ? "-" : ""),
1378                            abs(t / 1000), abs(t % 1000));
1379                 break;
1380         }
1381 }
1382
1383 static int wil_temp_debugfs_show(struct seq_file *s, void *data)
1384 {
1385         struct wil6210_priv *wil = s->private;
1386         s32 t_m, t_r;
1387         int rc = wmi_get_temperature(wil, &t_m, &t_r);
1388
1389         if (rc) {
1390                 seq_puts(s, "Failed\n");
1391                 return 0;
1392         }
1393
1394         print_temp(s, "T_mac   =", t_m);
1395         print_temp(s, "T_radio =", t_r);
1396
1397         return 0;
1398 }
1399
1400 static int wil_temp_seq_open(struct inode *inode, struct file *file)
1401 {
1402         return single_open(file, wil_temp_debugfs_show, inode->i_private);
1403 }
1404
1405 static const struct file_operations fops_temp = {
1406         .open           = wil_temp_seq_open,
1407         .release        = single_release,
1408         .read           = seq_read,
1409         .llseek         = seq_lseek,
1410 };
1411
1412 /*---------freq------------*/
1413 static int wil_freq_debugfs_show(struct seq_file *s, void *data)
1414 {
1415         struct wil6210_priv *wil = s->private;
1416         struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
1417         u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
1418
1419         seq_printf(s, "Freq = %d\n", freq);
1420
1421         return 0;
1422 }
1423
1424 static int wil_freq_seq_open(struct inode *inode, struct file *file)
1425 {
1426         return single_open(file, wil_freq_debugfs_show, inode->i_private);
1427 }
1428
1429 static const struct file_operations fops_freq = {
1430         .open           = wil_freq_seq_open,
1431         .release        = single_release,
1432         .read           = seq_read,
1433         .llseek         = seq_lseek,
1434 };
1435
1436 /*---------link------------*/
1437 static int wil_link_debugfs_show(struct seq_file *s, void *data)
1438 {
1439         struct wil6210_priv *wil = s->private;
1440         struct station_info *sinfo;
1441         int i, rc = 0;
1442
1443         sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
1444         if (!sinfo)
1445                 return -ENOMEM;
1446
1447         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1448                 struct wil_sta_info *p = &wil->sta[i];
1449                 char *status = "unknown";
1450                 struct wil6210_vif *vif;
1451                 u8 mid;
1452
1453                 switch (p->status) {
1454                 case wil_sta_unused:
1455                         status = "unused   ";
1456                         break;
1457                 case wil_sta_conn_pending:
1458                         status = "pending  ";
1459                         break;
1460                 case wil_sta_connected:
1461                         status = "connected";
1462                         break;
1463                 }
1464                 mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
1465                 seq_printf(s, "[%d][MID %d] %pM %s\n",
1466                            i, mid, p->addr, status);
1467
1468                 if (p->status != wil_sta_connected)
1469                         continue;
1470
1471                 vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
1472                 if (vif) {
1473                         rc = wil_cid_fill_sinfo(vif, i, sinfo);
1474                         if (rc)
1475                                 goto out;
1476
1477                         seq_printf(s, "  Tx_mcs = %d\n", sinfo->txrate.mcs);
1478                         seq_printf(s, "  Rx_mcs = %d\n", sinfo->rxrate.mcs);
1479                         seq_printf(s, "  SQ     = %d\n", sinfo->signal);
1480                 } else {
1481                         seq_puts(s, "  INVALID MID\n");
1482                 }
1483         }
1484
1485 out:
1486         kfree(sinfo);
1487         return rc;
1488 }
1489
1490 static int wil_link_seq_open(struct inode *inode, struct file *file)
1491 {
1492         return single_open(file, wil_link_debugfs_show, inode->i_private);
1493 }
1494
1495 static const struct file_operations fops_link = {
1496         .open           = wil_link_seq_open,
1497         .release        = single_release,
1498         .read           = seq_read,
1499         .llseek         = seq_lseek,
1500 };
1501
1502 /*---------info------------*/
1503 static int wil_info_debugfs_show(struct seq_file *s, void *data)
1504 {
1505         struct wil6210_priv *wil = s->private;
1506         struct net_device *ndev = wil->main_ndev;
1507         int is_ac = power_supply_is_system_supplied();
1508         int rx = atomic_xchg(&wil->isr_count_rx, 0);
1509         int tx = atomic_xchg(&wil->isr_count_tx, 0);
1510         static ulong rxf_old, txf_old;
1511         ulong rxf = ndev->stats.rx_packets;
1512         ulong txf = ndev->stats.tx_packets;
1513         unsigned int i;
1514
1515         /* >0 : AC; 0 : battery; <0 : error */
1516         seq_printf(s, "AC powered : %d\n", is_ac);
1517         seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
1518         seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
1519         rxf_old = rxf;
1520         txf_old = txf;
1521
1522 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1523         " " __stringify(x) : ""
1524
1525         for (i = 0; i < ndev->num_tx_queues; i++) {
1526                 struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
1527                 unsigned long state = txq->state;
1528
1529                 seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
1530                            CHECK_QSTATE(DRV_XOFF),
1531                            CHECK_QSTATE(STACK_XOFF),
1532                            CHECK_QSTATE(FROZEN)
1533                           );
1534         }
1535 #undef CHECK_QSTATE
1536         return 0;
1537 }
1538
1539 static int wil_info_seq_open(struct inode *inode, struct file *file)
1540 {
1541         return single_open(file, wil_info_debugfs_show, inode->i_private);
1542 }
1543
1544 static const struct file_operations fops_info = {
1545         .open           = wil_info_seq_open,
1546         .release        = single_release,
1547         .read           = seq_read,
1548         .llseek         = seq_lseek,
1549 };
1550
1551 /*---------recovery------------*/
1552 /* mode = [manual|auto]
1553  * state = [idle|pending|running]
1554  */
1555 static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
1556                                       size_t count, loff_t *ppos)
1557 {
1558         struct wil6210_priv *wil = file->private_data;
1559         char buf[80];
1560         int n;
1561         static const char * const sstate[] = {"idle", "pending", "running"};
1562
1563         n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
1564                      no_fw_recovery ? "manual" : "auto",
1565                      sstate[wil->recovery_state]);
1566
1567         n = min_t(int, n, sizeof(buf));
1568
1569         return simple_read_from_buffer(user_buf, count, ppos,
1570                                        buf, n);
1571 }
1572
1573 static ssize_t wil_write_file_recovery(struct file *file,
1574                                        const char __user *buf_,
1575                                        size_t count, loff_t *ppos)
1576 {
1577         struct wil6210_priv *wil = file->private_data;
1578         static const char run_command[] = "run";
1579         char buf[sizeof(run_command) + 1]; /* to detect "runx" */
1580         ssize_t rc;
1581
1582         if (wil->recovery_state != fw_recovery_pending) {
1583                 wil_err(wil, "No recovery pending\n");
1584                 return -EINVAL;
1585         }
1586
1587         if (*ppos != 0) {
1588                 wil_err(wil, "Offset [%d]\n", (int)*ppos);
1589                 return -EINVAL;
1590         }
1591
1592         if (count > sizeof(buf)) {
1593                 wil_err(wil, "Input too long, len = %d\n", (int)count);
1594                 return -EINVAL;
1595         }
1596
1597         rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
1598         if (rc < 0)
1599                 return rc;
1600
1601         buf[rc] = '\0';
1602         if (0 == strcmp(buf, run_command))
1603                 wil_set_recovery_state(wil, fw_recovery_running);
1604         else
1605                 wil_err(wil, "Bad recovery command \"%s\"\n", buf);
1606
1607         return rc;
1608 }
1609
1610 static const struct file_operations fops_recovery = {
1611         .read = wil_read_file_recovery,
1612         .write = wil_write_file_recovery,
1613         .open  = simple_open,
1614 };
1615
1616 /*---------Station matrix------------*/
1617 static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
1618 {
1619         int i;
1620         u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
1621         unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old;
1622         unsigned long long drop_dup_mcast = r->drop_dup_mcast;
1623
1624         seq_printf(s, "([%2d]) 0x%03x [", r->buf_size, r->head_seq_num);
1625         for (i = 0; i < r->buf_size; i++) {
1626                 if (i == index)
1627                         seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
1628                 else
1629                         seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
1630         }
1631         seq_printf(s,
1632                    "] total %llu drop %llu (dup %llu + old %llu + dup mcast %llu) last 0x%03x\n",
1633                    r->total, drop_dup + drop_old + drop_dup_mcast, drop_dup,
1634                    drop_old, drop_dup_mcast, r->ssn_last_drop);
1635 }
1636
1637 static void wil_print_rxtid_crypto(struct seq_file *s, int tid,
1638                                    struct wil_tid_crypto_rx *c)
1639 {
1640         int i;
1641
1642         for (i = 0; i < 4; i++) {
1643                 struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
1644
1645                 if (cc->key_set)
1646                         goto has_keys;
1647         }
1648         return;
1649
1650 has_keys:
1651         if (tid < WIL_STA_TID_NUM)
1652                 seq_printf(s, "  [%2d] PN", tid);
1653         else
1654                 seq_puts(s, "  [GR] PN");
1655
1656         for (i = 0; i < 4; i++) {
1657                 struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
1658
1659                 seq_printf(s, " [%i%s]%6phN", i, cc->key_set ? "+" : "-",
1660                            cc->pn);
1661         }
1662         seq_puts(s, "\n");
1663 }
1664
1665 static int wil_sta_debugfs_show(struct seq_file *s, void *data)
1666 __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1667 {
1668         struct wil6210_priv *wil = s->private;
1669         int i, tid, mcs;
1670
1671         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1672                 struct wil_sta_info *p = &wil->sta[i];
1673                 char *status = "unknown";
1674                 u8 aid = 0;
1675                 u8 mid;
1676
1677                 switch (p->status) {
1678                 case wil_sta_unused:
1679                         status = "unused   ";
1680                         break;
1681                 case wil_sta_conn_pending:
1682                         status = "pending  ";
1683                         break;
1684                 case wil_sta_connected:
1685                         status = "connected";
1686                         aid = p->aid;
1687                         break;
1688                 }
1689                 mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
1690                 seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
1691                            mid, aid);
1692
1693                 if (p->status == wil_sta_connected) {
1694                         spin_lock_bh(&p->tid_rx_lock);
1695                         for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
1696                                 struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
1697                                 struct wil_tid_crypto_rx *c =
1698                                                 &p->tid_crypto_rx[tid];
1699
1700                                 if (r) {
1701                                         seq_printf(s, "  [%2d] ", tid);
1702                                         wil_print_rxtid(s, r);
1703                                 }
1704
1705                                 wil_print_rxtid_crypto(s, tid, c);
1706                         }
1707                         wil_print_rxtid_crypto(s, WIL_STA_TID_NUM,
1708                                                &p->group_crypto_rx);
1709                         spin_unlock_bh(&p->tid_rx_lock);
1710                         seq_printf(s,
1711                                    "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n",
1712                                    p->stats.rx_non_data_frame,
1713                                    p->stats.rx_short_frame,
1714                                    p->stats.rx_large_frame,
1715                                    p->stats.rx_replay);
1716                         seq_printf(s,
1717                                    "mic error %lu, key error %lu, amsdu error %lu, csum error %lu\n",
1718                                    p->stats.rx_mic_error,
1719                                    p->stats.rx_key_error,
1720                                    p->stats.rx_amsdu_error,
1721                                    p->stats.rx_csum_err);
1722
1723                         seq_puts(s, "Rx/MCS:");
1724                         for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
1725                              mcs++)
1726                                 seq_printf(s, " %lld",
1727                                            p->stats.rx_per_mcs[mcs]);
1728                         seq_puts(s, "\n");
1729                 }
1730         }
1731
1732         return 0;
1733 }
1734
1735 static int wil_sta_seq_open(struct inode *inode, struct file *file)
1736 {
1737         return single_open(file, wil_sta_debugfs_show, inode->i_private);
1738 }
1739
1740 static const struct file_operations fops_sta = {
1741         .open           = wil_sta_seq_open,
1742         .release        = single_release,
1743         .read           = seq_read,
1744         .llseek         = seq_lseek,
1745 };
1746
1747 static int wil_mids_debugfs_show(struct seq_file *s, void *data)
1748 {
1749         struct wil6210_priv *wil = s->private;
1750         struct wil6210_vif *vif;
1751         struct net_device *ndev;
1752         int i;
1753
1754         mutex_lock(&wil->vif_mutex);
1755         for (i = 0; i < wil->max_vifs; i++) {
1756                 vif = wil->vifs[i];
1757
1758                 if (vif) {
1759                         ndev = vif_to_ndev(vif);
1760                         seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr,
1761                                    ndev->name);
1762                 } else {
1763                         seq_printf(s, "[%d] unused\n", i);
1764                 }
1765         }
1766         mutex_unlock(&wil->vif_mutex);
1767
1768         return 0;
1769 }
1770
1771 static int wil_mids_seq_open(struct inode *inode, struct file *file)
1772 {
1773         return single_open(file, wil_mids_debugfs_show, inode->i_private);
1774 }
1775
1776 static const struct file_operations fops_mids = {
1777         .open           = wil_mids_seq_open,
1778         .release        = single_release,
1779         .read           = seq_read,
1780         .llseek         = seq_lseek,
1781 };
1782
1783 static int wil_tx_latency_debugfs_show(struct seq_file *s, void *data)
1784 __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1785 {
1786         struct wil6210_priv *wil = s->private;
1787         int i, bin;
1788
1789         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1790                 struct wil_sta_info *p = &wil->sta[i];
1791                 char *status = "unknown";
1792                 u8 aid = 0;
1793                 u8 mid;
1794
1795                 if (!p->tx_latency_bins)
1796                         continue;
1797
1798                 switch (p->status) {
1799                 case wil_sta_unused:
1800                         status = "unused   ";
1801                         break;
1802                 case wil_sta_conn_pending:
1803                         status = "pending  ";
1804                         break;
1805                 case wil_sta_connected:
1806                         status = "connected";
1807                         aid = p->aid;
1808                         break;
1809                 }
1810                 mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
1811                 seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
1812                            mid, aid);
1813
1814                 if (p->status == wil_sta_connected) {
1815                         u64 num_packets = 0;
1816                         u64 tx_latency_avg = p->stats.tx_latency_total_us;
1817
1818                         seq_puts(s, "Tx/Latency bin:");
1819                         for (bin = 0; bin < WIL_NUM_LATENCY_BINS; bin++) {
1820                                 seq_printf(s, " %lld",
1821                                            p->tx_latency_bins[bin]);
1822                                 num_packets += p->tx_latency_bins[bin];
1823                         }
1824                         seq_puts(s, "\n");
1825                         if (!num_packets)
1826                                 continue;
1827                         do_div(tx_latency_avg, num_packets);
1828                         seq_printf(s, "Tx/Latency min/avg/max (us): %d/%lld/%d",
1829                                    p->stats.tx_latency_min_us,
1830                                    tx_latency_avg,
1831                                    p->stats.tx_latency_max_us);
1832
1833                         seq_puts(s, "\n");
1834                 }
1835         }
1836
1837         return 0;
1838 }
1839
1840 static int wil_tx_latency_seq_open(struct inode *inode, struct file *file)
1841 {
1842         return single_open(file, wil_tx_latency_debugfs_show,
1843                            inode->i_private);
1844 }
1845
1846 static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf,
1847                                     size_t len, loff_t *ppos)
1848 {
1849         struct seq_file *s = file->private_data;
1850         struct wil6210_priv *wil = s->private;
1851         int val, rc, i;
1852         bool enable;
1853
1854         rc = kstrtoint_from_user(buf, len, 0, &val);
1855         if (rc) {
1856                 wil_err(wil, "Invalid argument\n");
1857                 return rc;
1858         }
1859         if (val == 1)
1860                 /* default resolution */
1861                 val = 500;
1862         if (val && (val < 50 || val > 1000)) {
1863                 wil_err(wil, "Invalid resolution %d\n", val);
1864                 return -EINVAL;
1865         }
1866
1867         enable = !!val;
1868         if (wil->tx_latency == enable)
1869                 return len;
1870
1871         wil_info(wil, "%s TX latency measurements (resolution %dusec)\n",
1872                  enable ? "Enabling" : "Disabling", val);
1873
1874         if (enable) {
1875                 size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS;
1876
1877                 wil->tx_latency_res = val;
1878                 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1879                         struct wil_sta_info *sta = &wil->sta[i];
1880
1881                         kfree(sta->tx_latency_bins);
1882                         sta->tx_latency_bins = kzalloc(sz, GFP_KERNEL);
1883                         if (!sta->tx_latency_bins)
1884                                 return -ENOMEM;
1885                         sta->stats.tx_latency_min_us = U32_MAX;
1886                         sta->stats.tx_latency_max_us = 0;
1887                         sta->stats.tx_latency_total_us = 0;
1888                 }
1889         }
1890         wil->tx_latency = enable;
1891
1892         return len;
1893 }
1894
1895 static const struct file_operations fops_tx_latency = {
1896         .open           = wil_tx_latency_seq_open,
1897         .release        = single_release,
1898         .read           = seq_read,
1899         .write          = wil_tx_latency_write,
1900         .llseek         = seq_lseek,
1901 };
1902
1903 static void wil_link_stats_print_basic(struct wil6210_vif *vif,
1904                                        struct seq_file *s,
1905                                        struct wmi_link_stats_basic *basic)
1906 {
1907         char per[5] = "?";
1908
1909         if (basic->per_average != 0xff)
1910                 snprintf(per, sizeof(per), "%d%%", basic->per_average);
1911
1912         seq_printf(s, "CID %d {\n"
1913                    "\tTxMCS %d TxTpt %d\n"
1914                    "\tGoodput(rx:tx) %d:%d\n"
1915                    "\tRxBcastFrames %d\n"
1916                    "\tRSSI %d SQI %d SNR %d PER %s\n"
1917                    "\tRx RFC %d Ant num %d\n"
1918                    "\tSectors(rx:tx) my %d:%d peer %d:%d\n"
1919                    "}\n",
1920                    basic->cid,
1921                    basic->bf_mcs, le32_to_cpu(basic->tx_tpt),
1922                    le32_to_cpu(basic->rx_goodput),
1923                    le32_to_cpu(basic->tx_goodput),
1924                    le32_to_cpu(basic->rx_bcast_frames),
1925                    basic->rssi, basic->sqi, basic->snr, per,
1926                    basic->selected_rfc, basic->rx_effective_ant_num,
1927                    basic->my_rx_sector, basic->my_tx_sector,
1928                    basic->other_rx_sector, basic->other_tx_sector);
1929 }
1930
1931 static void wil_link_stats_print_global(struct wil6210_priv *wil,
1932                                         struct seq_file *s,
1933                                         struct wmi_link_stats_global *global)
1934 {
1935         seq_printf(s, "Frames(rx:tx) %d:%d\n"
1936                    "BA Frames(rx:tx) %d:%d\n"
1937                    "Beacons %d\n"
1938                    "Rx Errors (MIC:CRC) %d:%d\n"
1939                    "Tx Errors (no ack) %d\n",
1940                    le32_to_cpu(global->rx_frames),
1941                    le32_to_cpu(global->tx_frames),
1942                    le32_to_cpu(global->rx_ba_frames),
1943                    le32_to_cpu(global->tx_ba_frames),
1944                    le32_to_cpu(global->tx_beacons),
1945                    le32_to_cpu(global->rx_mic_errors),
1946                    le32_to_cpu(global->rx_crc_errors),
1947                    le32_to_cpu(global->tx_fail_no_ack));
1948 }
1949
1950 static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif,
1951                                             struct seq_file *s)
1952 {
1953         struct wil6210_priv *wil = vif_to_wil(vif);
1954         struct wmi_link_stats_basic *stats;
1955         int i;
1956
1957         if (!vif->fw_stats_ready) {
1958                 seq_puts(s, "no statistics\n");
1959                 return;
1960         }
1961
1962         seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf);
1963         for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1964                 if (wil->sta[i].status == wil_sta_unused)
1965                         continue;
1966                 if (wil->sta[i].mid != vif->mid)
1967                         continue;
1968
1969                 stats = &wil->sta[i].fw_stats_basic;
1970                 wil_link_stats_print_basic(vif, s, stats);
1971         }
1972 }
1973
1974 static int wil_link_stats_debugfs_show(struct seq_file *s, void *data)
1975 {
1976         struct wil6210_priv *wil = s->private;
1977         struct wil6210_vif *vif;
1978         int i, rc;
1979
1980         rc = mutex_lock_interruptible(&wil->vif_mutex);
1981         if (rc)
1982                 return rc;
1983
1984         /* iterate over all MIDs and show per-cid statistics. Then show the
1985          * global statistics
1986          */
1987         for (i = 0; i < wil->max_vifs; i++) {
1988                 vif = wil->vifs[i];
1989
1990                 seq_printf(s, "MID %d ", i);
1991                 if (!vif) {
1992                         seq_puts(s, "unused\n");
1993                         continue;
1994                 }
1995
1996                 wil_link_stats_debugfs_show_vif(vif, s);
1997         }
1998
1999         mutex_unlock(&wil->vif_mutex);
2000
2001         return 0;
2002 }
2003
2004 static int wil_link_stats_seq_open(struct inode *inode, struct file *file)
2005 {
2006         return single_open(file, wil_link_stats_debugfs_show, inode->i_private);
2007 }
2008
2009 static ssize_t wil_link_stats_write(struct file *file, const char __user *buf,
2010                                     size_t len, loff_t *ppos)
2011 {
2012         struct seq_file *s = file->private_data;
2013         struct wil6210_priv *wil = s->private;
2014         int cid, interval, rc, i;
2015         struct wil6210_vif *vif;
2016         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
2017
2018         if (!kbuf)
2019                 return -ENOMEM;
2020
2021         rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
2022         if (rc != len) {
2023                 kfree(kbuf);
2024                 return rc >= 0 ? -EIO : rc;
2025         }
2026
2027         kbuf[len] = '\0';
2028         /* specify cid (use -1 for all cids) and snapshot interval in ms */
2029         rc = sscanf(kbuf, "%d %d", &cid, &interval);
2030         kfree(kbuf);
2031         if (rc < 0)
2032                 return rc;
2033         if (rc < 2 || interval < 0)
2034                 return -EINVAL;
2035
2036         wil_info(wil, "request link statistics, cid %d interval %d\n",
2037                  cid, interval);
2038
2039         rc = mutex_lock_interruptible(&wil->vif_mutex);
2040         if (rc)
2041                 return rc;
2042
2043         for (i = 0; i < wil->max_vifs; i++) {
2044                 vif = wil->vifs[i];
2045                 if (!vif)
2046                         continue;
2047
2048                 rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_BASIC,
2049                                         (cid == -1 ? 0xff : cid), interval);
2050                 if (rc)
2051                         wil_err(wil, "link statistics failed for mid %d\n", i);
2052         }
2053         mutex_unlock(&wil->vif_mutex);
2054
2055         return len;
2056 }
2057
2058 static const struct file_operations fops_link_stats = {
2059         .open           = wil_link_stats_seq_open,
2060         .release        = single_release,
2061         .read           = seq_read,
2062         .write          = wil_link_stats_write,
2063         .llseek         = seq_lseek,
2064 };
2065
2066 static int
2067 wil_link_stats_global_debugfs_show(struct seq_file *s, void *data)
2068 {
2069         struct wil6210_priv *wil = s->private;
2070
2071         if (!wil->fw_stats_global.ready)
2072                 return 0;
2073
2074         seq_printf(s, "TSF %lld\n", wil->fw_stats_global.tsf);
2075         wil_link_stats_print_global(wil, s, &wil->fw_stats_global.stats);
2076
2077         return 0;
2078 }
2079
2080 static int
2081 wil_link_stats_global_seq_open(struct inode *inode, struct file *file)
2082 {
2083         return single_open(file, wil_link_stats_global_debugfs_show,
2084                            inode->i_private);
2085 }
2086
2087 static ssize_t
2088 wil_link_stats_global_write(struct file *file, const char __user *buf,
2089                             size_t len, loff_t *ppos)
2090 {
2091         struct seq_file *s = file->private_data;
2092         struct wil6210_priv *wil = s->private;
2093         int interval, rc;
2094         struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2095
2096         /* specify snapshot interval in ms */
2097         rc = kstrtoint_from_user(buf, len, 0, &interval);
2098         if (rc || interval < 0) {
2099                 wil_err(wil, "Invalid argument\n");
2100                 return -EINVAL;
2101         }
2102
2103         wil_info(wil, "request global link stats, interval %d\n", interval);
2104
2105         rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_GLOBAL, 0, interval);
2106         if (rc)
2107                 wil_err(wil, "global link stats failed %d\n", rc);
2108
2109         return rc ? rc : len;
2110 }
2111
2112 static const struct file_operations fops_link_stats_global = {
2113         .open           = wil_link_stats_global_seq_open,
2114         .release        = single_release,
2115         .read           = seq_read,
2116         .write          = wil_link_stats_global_write,
2117         .llseek         = seq_lseek,
2118 };
2119
2120 static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
2121                                      size_t count, loff_t *ppos)
2122 {
2123         char buf[80];
2124         int n;
2125
2126         n = snprintf(buf, sizeof(buf),
2127                      "led_id is set to %d, echo 1 to enable, 0 to disable\n",
2128                      led_id);
2129
2130         n = min_t(int, n, sizeof(buf));
2131
2132         return simple_read_from_buffer(user_buf, count, ppos,
2133                                        buf, n);
2134 }
2135
2136 static ssize_t wil_write_file_led_cfg(struct file *file,
2137                                       const char __user *buf_,
2138                                       size_t count, loff_t *ppos)
2139 {
2140         struct wil6210_priv *wil = file->private_data;
2141         int val;
2142         int rc;
2143
2144         rc = kstrtoint_from_user(buf_, count, 0, &val);
2145         if (rc) {
2146                 wil_err(wil, "Invalid argument\n");
2147                 return rc;
2148         }
2149
2150         wil_info(wil, "%s led %d\n", val ? "Enabling" : "Disabling", led_id);
2151         rc = wmi_led_cfg(wil, val);
2152         if (rc) {
2153                 wil_info(wil, "%s led %d failed\n",
2154                          val ? "Enabling" : "Disabling", led_id);
2155                 return rc;
2156         }
2157
2158         return count;
2159 }
2160
2161 static const struct file_operations fops_led_cfg = {
2162         .read = wil_read_file_led_cfg,
2163         .write = wil_write_file_led_cfg,
2164         .open  = simple_open,
2165 };
2166
2167 /* led_blink_time, write:
2168  * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
2169  */
2170 static ssize_t wil_write_led_blink_time(struct file *file,
2171                                         const char __user *buf,
2172                                         size_t len, loff_t *ppos)
2173 {
2174         int rc;
2175         char *kbuf = kmalloc(len + 1, GFP_KERNEL);
2176
2177         if (!kbuf)
2178                 return -ENOMEM;
2179
2180         rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
2181         if (rc != len) {
2182                 kfree(kbuf);
2183                 return rc >= 0 ? -EIO : rc;
2184         }
2185
2186         kbuf[len] = '\0';
2187         rc = sscanf(kbuf, "%d %d %d %d %d %d",
2188                     &led_blink_time[WIL_LED_TIME_SLOW].on_ms,
2189                     &led_blink_time[WIL_LED_TIME_SLOW].off_ms,
2190                     &led_blink_time[WIL_LED_TIME_MED].on_ms,
2191                     &led_blink_time[WIL_LED_TIME_MED].off_ms,
2192                     &led_blink_time[WIL_LED_TIME_FAST].on_ms,
2193                     &led_blink_time[WIL_LED_TIME_FAST].off_ms);
2194         kfree(kbuf);
2195
2196         if (rc < 0)
2197                 return rc;
2198         if (rc < 6)
2199                 return -EINVAL;
2200
2201         return len;
2202 }
2203
2204 static ssize_t wil_read_led_blink_time(struct file *file, char __user *user_buf,
2205                                        size_t count, loff_t *ppos)
2206 {
2207         static char text[400];
2208
2209         snprintf(text, sizeof(text),
2210                  "To set led blink on/off time variables write:\n"
2211                  "<blink_on_slow> <blink_off_slow> <blink_on_med> "
2212                  "<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
2213                  "The current values are:\n"
2214                  "%d %d %d %d %d %d\n",
2215                  led_blink_time[WIL_LED_TIME_SLOW].on_ms,
2216                  led_blink_time[WIL_LED_TIME_SLOW].off_ms,
2217                  led_blink_time[WIL_LED_TIME_MED].on_ms,
2218                  led_blink_time[WIL_LED_TIME_MED].off_ms,
2219                  led_blink_time[WIL_LED_TIME_FAST].on_ms,
2220                  led_blink_time[WIL_LED_TIME_FAST].off_ms);
2221
2222         return simple_read_from_buffer(user_buf, count, ppos, text,
2223                                        sizeof(text));
2224 }
2225
2226 static const struct file_operations fops_led_blink_time = {
2227         .read = wil_read_led_blink_time,
2228         .write = wil_write_led_blink_time,
2229         .open  = simple_open,
2230 };
2231
2232 /*---------FW capabilities------------*/
2233 static int wil_fw_capabilities_debugfs_show(struct seq_file *s, void *data)
2234 {
2235         struct wil6210_priv *wil = s->private;
2236
2237         seq_printf(s, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX,
2238                    wil->fw_capabilities);
2239
2240         return 0;
2241 }
2242
2243 static int wil_fw_capabilities_seq_open(struct inode *inode, struct file *file)
2244 {
2245         return single_open(file, wil_fw_capabilities_debugfs_show,
2246                            inode->i_private);
2247 }
2248
2249 static const struct file_operations fops_fw_capabilities = {
2250         .open           = wil_fw_capabilities_seq_open,
2251         .release        = single_release,
2252         .read           = seq_read,
2253         .llseek         = seq_lseek,
2254 };
2255
2256 /*---------FW version------------*/
2257 static int wil_fw_version_debugfs_show(struct seq_file *s, void *data)
2258 {
2259         struct wil6210_priv *wil = s->private;
2260
2261         if (wil->fw_version[0])
2262                 seq_printf(s, "%s\n", wil->fw_version);
2263         else
2264                 seq_puts(s, "N/A\n");
2265
2266         return 0;
2267 }
2268
2269 static int wil_fw_version_seq_open(struct inode *inode, struct file *file)
2270 {
2271         return single_open(file, wil_fw_version_debugfs_show,
2272                            inode->i_private);
2273 }
2274
2275 static const struct file_operations fops_fw_version = {
2276         .open           = wil_fw_version_seq_open,
2277         .release        = single_release,
2278         .read           = seq_read,
2279         .llseek         = seq_lseek,
2280 };
2281
2282 /*---------suspend_stats---------*/
2283 static ssize_t wil_write_suspend_stats(struct file *file,
2284                                        const char __user *buf,
2285                                        size_t len, loff_t *ppos)
2286 {
2287         struct wil6210_priv *wil = file->private_data;
2288
2289         memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
2290
2291         return len;
2292 }
2293
2294 static ssize_t wil_read_suspend_stats(struct file *file,
2295                                       char __user *user_buf,
2296                                       size_t count, loff_t *ppos)
2297 {
2298         struct wil6210_priv *wil = file->private_data;
2299         char *text;
2300         int n, ret, text_size = 500;
2301
2302         text = kmalloc(text_size, GFP_KERNEL);
2303         if (!text)
2304                 return -ENOMEM;
2305
2306         n = snprintf(text, text_size,
2307                      "Radio on suspend statistics:\n"
2308                      "successful suspends:%ld failed suspends:%ld\n"
2309                      "successful resumes:%ld failed resumes:%ld\n"
2310                      "rejected by device:%ld\n"
2311                      "Radio off suspend statistics:\n"
2312                      "successful suspends:%ld failed suspends:%ld\n"
2313                      "successful resumes:%ld failed resumes:%ld\n"
2314                      "General statistics:\n"
2315                      "rejected by host:%ld\n",
2316                      wil->suspend_stats.r_on.successful_suspends,
2317                      wil->suspend_stats.r_on.failed_suspends,
2318                      wil->suspend_stats.r_on.successful_resumes,
2319                      wil->suspend_stats.r_on.failed_resumes,
2320                      wil->suspend_stats.rejected_by_device,
2321                      wil->suspend_stats.r_off.successful_suspends,
2322                      wil->suspend_stats.r_off.failed_suspends,
2323                      wil->suspend_stats.r_off.successful_resumes,
2324                      wil->suspend_stats.r_off.failed_resumes,
2325                      wil->suspend_stats.rejected_by_host);
2326
2327         n = min_t(int, n, text_size);
2328
2329         ret = simple_read_from_buffer(user_buf, count, ppos, text, n);
2330
2331         kfree(text);
2332
2333         return ret;
2334 }
2335
2336 static const struct file_operations fops_suspend_stats = {
2337         .read = wil_read_suspend_stats,
2338         .write = wil_write_suspend_stats,
2339         .open  = simple_open,
2340 };
2341
2342 /*---------compressed_rx_status---------*/
2343 static ssize_t wil_compressed_rx_status_write(struct file *file,
2344                                               const char __user *buf,
2345                                               size_t len, loff_t *ppos)
2346 {
2347         struct seq_file *s = file->private_data;
2348         struct wil6210_priv *wil = s->private;
2349         int compressed_rx_status;
2350         int rc;
2351
2352         rc = kstrtoint_from_user(buf, len, 0, &compressed_rx_status);
2353         if (rc) {
2354                 wil_err(wil, "Invalid argument\n");
2355                 return rc;
2356         }
2357
2358         if (wil_has_active_ifaces(wil, true, false)) {
2359                 wil_err(wil, "cannot change edma config after iface is up\n");
2360                 return -EPERM;
2361         }
2362
2363         wil_info(wil, "%sable compressed_rx_status\n",
2364                  compressed_rx_status ? "En" : "Dis");
2365
2366         wil->use_compressed_rx_status = compressed_rx_status;
2367
2368         return len;
2369 }
2370
2371 static int
2372 wil_compressed_rx_status_show(struct seq_file *s, void *data)
2373 {
2374         struct wil6210_priv *wil = s->private;
2375
2376         seq_printf(s, "%d\n", wil->use_compressed_rx_status);
2377
2378         return 0;
2379 }
2380
2381 static int
2382 wil_compressed_rx_status_seq_open(struct inode *inode, struct file *file)
2383 {
2384         return single_open(file, wil_compressed_rx_status_show,
2385                            inode->i_private);
2386 }
2387
2388 static const struct file_operations fops_compressed_rx_status = {
2389         .open  = wil_compressed_rx_status_seq_open,
2390         .release = single_release,
2391         .read = seq_read,
2392         .write = wil_compressed_rx_status_write,
2393         .llseek = seq_lseek,
2394 };
2395
2396 /*----------------*/
2397 static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
2398                                        struct dentry *dbg)
2399 {
2400         int i;
2401         char name[32];
2402
2403         for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
2404                 struct wil_blob_wrapper *wil_blob = &wil->blobs[i];
2405                 struct debugfs_blob_wrapper *blob = &wil_blob->blob;
2406                 const struct fw_map *map = &fw_mapping[i];
2407
2408                 if (!map->name)
2409                         continue;
2410
2411                 wil_blob->wil = wil;
2412                 blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
2413                 blob->size = map->to - map->from;
2414                 snprintf(name, sizeof(name), "blob_%s", map->name);
2415                 wil_debugfs_create_ioblob(name, 0444, dbg, wil_blob);
2416         }
2417 }
2418
2419 /* misc files */
2420 static const struct {
2421         const char *name;
2422         umode_t mode;
2423         const struct file_operations *fops;
2424 } dbg_files[] = {
2425         {"mbox",        0444,           &fops_mbox},
2426         {"rings",       0444,           &fops_ring},
2427         {"stations", 0444,              &fops_sta},
2428         {"mids",        0444,           &fops_mids},
2429         {"desc",        0444,           &fops_txdesc},
2430         {"bf",          0444,           &fops_bf},
2431         {"mem_val",     0644,           &fops_memread},
2432         {"rxon",        0244,           &fops_rxon},
2433         {"tx_mgmt",     0244,           &fops_txmgmt},
2434         {"wmi_send", 0244,              &fops_wmi},
2435         {"back",        0644,           &fops_back},
2436         {"pmccfg",      0644,           &fops_pmccfg},
2437         {"pmcdata",     0444,           &fops_pmcdata},
2438         {"temp",        0444,           &fops_temp},
2439         {"freq",        0444,           &fops_freq},
2440         {"link",        0444,           &fops_link},
2441         {"info",        0444,           &fops_info},
2442         {"recovery", 0644,              &fops_recovery},
2443         {"led_cfg",     0644,           &fops_led_cfg},
2444         {"led_blink_time",      0644,   &fops_led_blink_time},
2445         {"fw_capabilities",     0444,   &fops_fw_capabilities},
2446         {"fw_version",  0444,           &fops_fw_version},
2447         {"suspend_stats",       0644,   &fops_suspend_stats},
2448         {"compressed_rx_status", 0644,  &fops_compressed_rx_status},
2449         {"srings",      0444,           &fops_srings},
2450         {"status_msg",  0444,           &fops_status_msg},
2451         {"rx_buff_mgmt",        0444,   &fops_rx_buff_mgmt},
2452         {"tx_latency",  0644,           &fops_tx_latency},
2453         {"link_stats",  0644,           &fops_link_stats},
2454         {"link_stats_global",   0644,   &fops_link_stats_global},
2455 };
2456
2457 static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
2458                                        struct dentry *dbg)
2459 {
2460         int i;
2461
2462         for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
2463                 debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
2464                                     wil, dbg_files[i].fops);
2465 }
2466
2467 /* interrupt control blocks */
2468 static const struct {
2469         const char *name;
2470         u32 icr_off;
2471 } dbg_icr[] = {
2472         {"USER_ICR",            HOSTADDR(RGF_USER_USER_ICR)},
2473         {"DMA_EP_TX_ICR",       HOSTADDR(RGF_DMA_EP_TX_ICR)},
2474         {"DMA_EP_RX_ICR",       HOSTADDR(RGF_DMA_EP_RX_ICR)},
2475         {"DMA_EP_MISC_ICR",     HOSTADDR(RGF_DMA_EP_MISC_ICR)},
2476 };
2477
2478 static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
2479                                      struct dentry *dbg)
2480 {
2481         int i;
2482
2483         for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
2484                 wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
2485                                            dbg_icr[i].icr_off);
2486 }
2487
2488 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
2489         offsetof(struct wil6210_priv, name), type}
2490
2491 /* fields in struct wil6210_priv */
2492 static const struct dbg_off dbg_wil_off[] = {
2493         WIL_FIELD(status[0],    0644,   doff_ulong),
2494         WIL_FIELD(hw_version,   0444,   doff_x32),
2495         WIL_FIELD(recovery_count, 0444, doff_u32),
2496         WIL_FIELD(discovery_mode, 0644, doff_u8),
2497         WIL_FIELD(chip_revision, 0444,  doff_u8),
2498         WIL_FIELD(abft_len, 0644,               doff_u8),
2499         WIL_FIELD(wakeup_trigger, 0644,         doff_u8),
2500         WIL_FIELD(ring_idle_trsh, 0644, doff_u32),
2501         WIL_FIELD(num_rx_status_rings, 0644,    doff_u8),
2502         WIL_FIELD(rx_status_ring_order, 0644,   doff_u32),
2503         WIL_FIELD(tx_status_ring_order, 0644,   doff_u32),
2504         WIL_FIELD(rx_buff_id_count, 0644,       doff_u32),
2505         WIL_FIELD(amsdu_en, 0644,       doff_u8),
2506         {},
2507 };
2508
2509 static const struct dbg_off dbg_wil_regs[] = {
2510         {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
2511                 doff_io32},
2512         {"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
2513         {},
2514 };
2515
2516 /* static parameters */
2517 static const struct dbg_off dbg_statics[] = {
2518         {"desc_index",  0644, (ulong)&dbg_txdesc_index, doff_u32},
2519         {"ring_index",  0644, (ulong)&dbg_ring_index, doff_u32},
2520         {"mem_addr",    0644, (ulong)&mem_addr, doff_u32},
2521         {"led_polarity", 0644, (ulong)&led_polarity, doff_u8},
2522         {"status_index", 0644, (ulong)&dbg_status_msg_index, doff_u32},
2523         {"sring_index", 0644, (ulong)&dbg_sring_index, doff_u32},
2524         {},
2525 };
2526
2527 static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) +
2528                                 ARRAY_SIZE(dbg_wil_regs) - 1 +
2529                                 ARRAY_SIZE(pseudo_isr_off) - 1 +
2530                                 ARRAY_SIZE(lgc_itr_cnt_off) - 1 +
2531                                 ARRAY_SIZE(tx_itr_cnt_off) - 1 +
2532                                 ARRAY_SIZE(rx_itr_cnt_off) - 1;
2533
2534 int wil6210_debugfs_init(struct wil6210_priv *wil)
2535 {
2536         struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
2537                         wil_to_wiphy(wil)->debugfsdir);
2538         if (IS_ERR_OR_NULL(dbg))
2539                 return -ENODEV;
2540
2541         wil->dbg_data.data_arr = kcalloc(dbg_off_count,
2542                                          sizeof(struct wil_debugfs_iomem_data),
2543                                          GFP_KERNEL);
2544         if (!wil->dbg_data.data_arr) {
2545                 debugfs_remove_recursive(dbg);
2546                 wil->debug = NULL;
2547                 return -ENOMEM;
2548         }
2549
2550         wil->dbg_data.iomem_data_count = 0;
2551
2552         wil_pmc_init(wil);
2553
2554         wil6210_debugfs_init_files(wil, dbg);
2555         wil6210_debugfs_init_isr(wil, dbg);
2556         wil6210_debugfs_init_blobs(wil, dbg);
2557         wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
2558         wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
2559                                     dbg_wil_regs);
2560         wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
2561
2562         wil6210_debugfs_create_pseudo_ISR(wil, dbg);
2563
2564         wil6210_debugfs_create_ITR_CNT(wil, dbg);
2565
2566         return 0;
2567 }
2568
2569 void wil6210_debugfs_remove(struct wil6210_priv *wil)
2570 {
2571         int i;
2572
2573         debugfs_remove_recursive(wil->debug);
2574         wil->debug = NULL;
2575
2576         kfree(wil->dbg_data.data_arr);
2577         for (i = 0; i < ARRAY_SIZE(wil->sta); i++)
2578                 kfree(wil->sta[i].tx_latency_bins);
2579
2580         /* free pmc memory without sending command to fw, as it will
2581          * be reset on the way down anyway
2582          */
2583         wil_pmc_free(wil, false);
2584 }