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