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