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