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