1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
7 #include <linux/module.h>
8 #include <linux/debugfs.h>
9 #include <linux/seq_file.h>
10 #include <linux/pci.h>
11 #include <linux/rtnetlink.h>
12 #include <linux/power_supply.h>
18 /* Nasty hack. Better have per device instances */
20 static u32 dbg_txdesc_index
;
21 static u32 dbg_ring_index
; /* 24+ for Rx, 0..23 for Tx */
22 static u32 dbg_status_msg_index
;
23 /* 0..wil->num_rx_status_rings-1 for Rx, wil->tx_sring_idx for Tx */
24 static u32 dbg_sring_index
;
39 enum dbg_off_type type
;
42 static void wil_print_desc_edma(struct seq_file
*s
, struct wil6210_priv
*wil
,
43 struct wil_ring
*ring
,
44 char _s
, char _h
, int idx
)
50 struct wil_rx_enhanced_desc
*rx_d
=
51 (struct wil_rx_enhanced_desc
*)
52 &ring
->va
[idx
].rx
.enhanced
;
53 u16 buff_id
= le16_to_cpu(rx_d
->mac
.buff_id
);
55 if (wil
->rx_buff_mgmt
.buff_arr
&&
56 wil_val_in_range(buff_id
, 0, wil
->rx_buff_mgmt
.size
))
57 has_skb
= wil
->rx_buff_mgmt
.buff_arr
[buff_id
].skb
;
58 seq_printf(s
, "%c", (has_skb
) ? _h
: _s
);
60 struct wil_tx_enhanced_desc
*d
=
61 (struct wil_tx_enhanced_desc
*)
62 &ring
->va
[idx
].tx
.enhanced
;
64 num_of_descs
= (u8
)d
->mac
.d
[2];
65 has_skb
= ring
->ctx
&& ring
->ctx
[idx
].skb
;
66 if (num_of_descs
>= 1)
67 seq_printf(s
, "%c", has_skb
? _h
: _s
);
69 /* num_of_descs == 0, it's a frag in a list of descs */
70 seq_printf(s
, "%c", has_skb
? 'h' : _s
);
74 static void wil_print_ring(struct seq_file
*s
, struct wil6210_priv
*wil
,
75 const char *name
, struct wil_ring
*ring
,
81 seq_printf(s
, "RING %s = {\n", name
);
82 seq_printf(s
, " pa = %pad\n", &ring
->pa
);
83 seq_printf(s
, " va = 0x%p\n", ring
->va
);
84 seq_printf(s
, " size = %d\n", ring
->size
);
85 if (wil
->use_enhanced_dma_hw
&& ring
->is_rx
)
86 seq_printf(s
, " swtail = %u\n", *ring
->edma_rx_swtail
.va
);
88 seq_printf(s
, " swtail = %d\n", ring
->swtail
);
89 seq_printf(s
, " swhead = %d\n", ring
->swhead
);
90 if (wil
->use_enhanced_dma_hw
) {
91 int ring_id
= ring
->is_rx
?
92 WIL_RX_DESC_RING_ID
: ring
- wil
->ring_tx
;
93 /* SUBQ_CONS is a table of 32 entries, one for each Q pair.
94 * lower 16bits are for even ring_id and upper 16bits are for
97 x
= wmi_addr(wil
, RGF_DMA_SCM_SUBQ_CONS
+ 4 * (ring_id
/ 2));
100 v
= (ring_id
% 2 ? (v
>> 16) : (v
& 0xffff));
101 seq_printf(s
, " hwhead = %u\n", v
);
103 seq_printf(s
, " hwtail = [0x%08x] -> ", ring
->hwtail
);
104 x
= wmi_addr(wil
, ring
->hwtail
);
107 seq_printf(s
, "0x%08x = %d\n", v
, v
);
109 seq_puts(s
, "???\n");
112 if (ring
->va
&& (ring
->size
<= (1 << WIL_RING_SIZE_ORDER_MAX
))) {
115 for (i
= 0; i
< ring
->size
; i
++) {
116 if ((i
% 128) == 0 && i
!= 0)
118 if (wil
->use_enhanced_dma_hw
) {
119 wil_print_desc_edma(s
, wil
, ring
, _s
, _h
, i
);
121 volatile struct vring_tx_desc
*d
=
122 &ring
->va
[i
].tx
.legacy
;
123 seq_printf(s
, "%c", (d
->dma
.status
& BIT(0)) ?
124 _s
: (ring
->ctx
[i
].skb
? _h
: 'h'));
132 static int ring_show(struct seq_file
*s
, void *data
)
135 struct wil6210_priv
*wil
= s
->private;
137 wil_print_ring(s
, wil
, "rx", &wil
->ring_rx
, 'S', '_');
139 for (i
= 0; i
< ARRAY_SIZE(wil
->ring_tx
); i
++) {
140 struct wil_ring
*ring
= &wil
->ring_tx
[i
];
141 struct wil_ring_tx_data
*txdata
= &wil
->ring_tx_data
[i
];
144 int cid
= wil
->ring2cid_tid
[i
][0];
145 int tid
= wil
->ring2cid_tid
[i
][1];
146 u32 swhead
= ring
->swhead
;
147 u32 swtail
= ring
->swtail
;
148 int used
= (ring
->size
+ swhead
- swtail
)
150 int avail
= ring
->size
- used
- 1;
153 /* performance monitoring */
154 cycles_t now
= get_cycles();
155 uint64_t idle
= txdata
->idle
* 100;
156 uint64_t total
= now
- txdata
->begin
;
160 snprintf(sidle
, sizeof(sidle
), "%3d%%",
163 snprintf(sidle
, sizeof(sidle
), "N/A");
168 snprintf(name
, sizeof(name
), "tx_%2d", i
);
170 if (cid
< wil
->max_assoc_sta
)
172 "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
173 wil
->sta
[cid
].addr
, cid
, tid
,
174 txdata
->dot1x_open
? "+" : "-",
177 txdata
->agg_amsdu
? "+" : "-",
181 "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
182 txdata
->dot1x_open
? "+" : "-",
185 wil_print_ring(s
, wil
, name
, ring
, '_', 'H');
191 DEFINE_SHOW_ATTRIBUTE(ring
);
193 static void wil_print_sring(struct seq_file
*s
, struct wil6210_priv
*wil
,
194 struct wil_status_ring
*sring
)
197 int sring_idx
= sring
- wil
->srings
;
200 seq_printf(s
, "Status Ring %s [ %d ] = {\n",
201 sring
->is_rx
? "RX" : "TX", sring_idx
);
202 seq_printf(s
, " pa = %pad\n", &sring
->pa
);
203 seq_printf(s
, " va = 0x%pK\n", sring
->va
);
204 seq_printf(s
, " size = %d\n", sring
->size
);
205 seq_printf(s
, " elem_size = %zu\n", sring
->elem_size
);
206 seq_printf(s
, " swhead = %d\n", sring
->swhead
);
207 if (wil
->use_enhanced_dma_hw
) {
208 /* COMPQ_PROD is a table of 32 entries, one for each Q pair.
209 * lower 16bits are for even ring_id and upper 16bits are for
212 x
= wmi_addr(wil
, RGF_DMA_SCM_COMPQ_PROD
+ 4 * (sring_idx
/ 2));
213 v
= readl_relaxed(x
);
215 v
= (sring_idx
% 2 ? (v
>> 16) : (v
& 0xffff));
216 seq_printf(s
, " hwhead = %u\n", v
);
218 seq_printf(s
, " hwtail = [0x%08x] -> ", sring
->hwtail
);
219 x
= wmi_addr(wil
, sring
->hwtail
);
221 v
= readl_relaxed(x
);
222 seq_printf(s
, "0x%08x = %d\n", v
, v
);
224 seq_puts(s
, "???\n");
226 seq_printf(s
, " desc_rdy_pol = %d\n", sring
->desc_rdy_pol
);
227 seq_printf(s
, " invalid_buff_id_cnt = %d\n",
228 sring
->invalid_buff_id_cnt
);
230 if (sring
->va
&& (sring
->size
<= (1 << WIL_RING_SIZE_ORDER_MAX
))) {
233 for (i
= 0; i
< sring
->size
; i
++) {
235 (u32
*)(sring
->va
+ (sring
->elem_size
* i
));
237 if ((i
% 128) == 0 && i
!= 0)
239 if (i
== sring
->swhead
)
240 seq_printf(s
, "%c", (*sdword_0
& BIT(31)) ?
243 seq_printf(s
, "%c", (*sdword_0
& BIT(31)) ?
251 static int srings_show(struct seq_file
*s
, void *data
)
253 struct wil6210_priv
*wil
= s
->private;
256 for (i
= 0; i
< WIL6210_MAX_STATUS_RINGS
; i
++)
257 if (wil
->srings
[i
].va
)
258 wil_print_sring(s
, wil
, &wil
->srings
[i
]);
262 DEFINE_SHOW_ATTRIBUTE(srings
);
264 static void wil_seq_hexdump(struct seq_file
*s
, void *p
, int len
,
267 seq_hex_dump(s
, prefix
, DUMP_PREFIX_NONE
, 16, 1, p
, len
, false);
270 static void wil_print_mbox_ring(struct seq_file
*s
, const char *prefix
,
273 struct wil6210_priv
*wil
= s
->private;
274 struct wil6210_mbox_ring r
;
280 if (wil_mem_access_lock(wil
)) {
281 wil_halp_unvote(wil
);
285 wil_memcpy_fromio_32(&r
, off
, sizeof(r
));
286 wil_mbox_ring_le2cpus(&r
);
288 * we just read memory block from NIC. This memory may be
289 * garbage. Check validity before using it.
291 rsize
= r
.size
/ sizeof(struct wil6210_mbox_ring_desc
);
293 seq_printf(s
, "ring %s = {\n", prefix
);
294 seq_printf(s
, " base = 0x%08x\n", r
.base
);
295 seq_printf(s
, " size = 0x%04x bytes -> %d entries\n", r
.size
, rsize
);
296 seq_printf(s
, " tail = 0x%08x\n", r
.tail
);
297 seq_printf(s
, " head = 0x%08x\n", r
.head
);
298 seq_printf(s
, " entry size = %d\n", r
.entry_size
);
300 if (r
.size
% sizeof(struct wil6210_mbox_ring_desc
)) {
301 seq_printf(s
, " ??? size is not multiple of %zd, garbage?\n",
302 sizeof(struct wil6210_mbox_ring_desc
));
306 if (!wmi_addr(wil
, r
.base
) ||
307 !wmi_addr(wil
, r
.tail
) ||
308 !wmi_addr(wil
, r
.head
)) {
309 seq_puts(s
, " ??? pointers are garbage?\n");
313 for (i
= 0; i
< rsize
; i
++) {
314 struct wil6210_mbox_ring_desc d
;
315 struct wil6210_mbox_hdr hdr
;
316 size_t delta
= i
* sizeof(d
);
317 void __iomem
*x
= wil
->csr
+ HOSTADDR(r
.base
) + delta
;
319 wil_memcpy_fromio_32(&d
, x
, sizeof(d
));
321 seq_printf(s
, " [%2x] %s %s%s 0x%08x", i
,
323 (r
.tail
- r
.base
== delta
) ? "t" : " ",
324 (r
.head
- r
.base
== delta
) ? "h" : " ",
325 le32_to_cpu(d
.addr
));
326 if (0 == wmi_read_hdr(wil
, d
.addr
, &hdr
)) {
327 u16 len
= le16_to_cpu(hdr
.len
);
329 seq_printf(s
, " -> %04x %04x %04x %02x\n",
330 le16_to_cpu(hdr
.seq
), len
,
331 le16_to_cpu(hdr
.type
), hdr
.flags
);
332 if (len
<= MAX_MBOXITEM_SIZE
) {
333 unsigned char databuf
[MAX_MBOXITEM_SIZE
];
334 void __iomem
*src
= wmi_buffer(wil
, d
.addr
) +
335 sizeof(struct wil6210_mbox_hdr
);
337 * No need to check @src for validity -
338 * we already validated @d.addr while
341 wil_memcpy_fromio_32(databuf
, src
, len
);
342 wil_seq_hexdump(s
, databuf
, len
, " : ");
350 wil_mem_access_unlock(wil
);
351 wil_halp_unvote(wil
);
354 static int mbox_show(struct seq_file
*s
, void *data
)
356 struct wil6210_priv
*wil
= s
->private;
359 ret
= wil_pm_runtime_get(wil
);
363 wil_print_mbox_ring(s
, "tx", wil
->csr
+ HOST_MBOX
+
364 offsetof(struct wil6210_mbox_ctl
, tx
));
365 wil_print_mbox_ring(s
, "rx", wil
->csr
+ HOST_MBOX
+
366 offsetof(struct wil6210_mbox_ctl
, rx
));
368 wil_pm_runtime_put(wil
);
372 DEFINE_SHOW_ATTRIBUTE(mbox
);
374 static int wil_debugfs_iomem_x32_set(void *data
, u64 val
)
376 struct wil_debugfs_iomem_data
*d
= (struct
377 wil_debugfs_iomem_data
*)data
;
378 struct wil6210_priv
*wil
= d
->wil
;
381 ret
= wil_pm_runtime_get(wil
);
385 writel_relaxed(val
, (void __iomem
*)d
->offset
);
387 wmb(); /* make sure write propagated to HW */
389 wil_pm_runtime_put(wil
);
394 static int wil_debugfs_iomem_x32_get(void *data
, u64
*val
)
396 struct wil_debugfs_iomem_data
*d
= (struct
397 wil_debugfs_iomem_data
*)data
;
398 struct wil6210_priv
*wil
= d
->wil
;
401 ret
= wil_pm_runtime_get(wil
);
405 *val
= readl((void __iomem
*)d
->offset
);
407 wil_pm_runtime_put(wil
);
412 DEFINE_DEBUGFS_ATTRIBUTE(fops_iomem_x32
, wil_debugfs_iomem_x32_get
,
413 wil_debugfs_iomem_x32_set
, "0x%08llx\n");
415 static void wil_debugfs_create_iomem_x32(const char *name
, umode_t mode
,
416 struct dentry
*parent
, void *value
,
417 struct wil6210_priv
*wil
)
419 struct wil_debugfs_iomem_data
*data
= &wil
->dbg_data
.data_arr
[
420 wil
->dbg_data
.iomem_data_count
];
423 data
->offset
= value
;
425 debugfs_create_file_unsafe(name
, mode
, parent
, data
, &fops_iomem_x32
);
426 wil
->dbg_data
.iomem_data_count
++;
429 static int wil_debugfs_ulong_set(void *data
, u64 val
)
431 *(ulong
*)data
= val
;
435 static int wil_debugfs_ulong_get(void *data
, u64
*val
)
437 *val
= *(ulong
*)data
;
441 DEFINE_DEBUGFS_ATTRIBUTE(wil_fops_ulong
, wil_debugfs_ulong_get
,
442 wil_debugfs_ulong_set
, "0x%llx\n");
445 * wil6210_debugfs_init_offset - create set of debugfs files
446 * @wil - driver's context, used for printing
447 * @dbg - directory on the debugfs, where files will be created
448 * @base - base address used in address calculation
449 * @tbl - table with file descriptions. Should be terminated with empty element.
451 * Creates files accordingly to the @tbl.
453 static void wil6210_debugfs_init_offset(struct wil6210_priv
*wil
,
454 struct dentry
*dbg
, void *base
,
455 const struct dbg_off
* const tbl
)
459 for (i
= 0; tbl
[i
].name
; i
++) {
460 switch (tbl
[i
].type
) {
462 debugfs_create_u32(tbl
[i
].name
, tbl
[i
].mode
, dbg
,
466 debugfs_create_x32(tbl
[i
].name
, tbl
[i
].mode
, dbg
,
470 debugfs_create_file_unsafe(tbl
[i
].name
, tbl
[i
].mode
,
471 dbg
, base
+ tbl
[i
].off
,
475 wil_debugfs_create_iomem_x32(tbl
[i
].name
, tbl
[i
].mode
,
476 dbg
, base
+ tbl
[i
].off
,
480 debugfs_create_u8(tbl
[i
].name
, tbl
[i
].mode
, dbg
,
487 static const struct dbg_off isr_off
[] = {
488 {"ICC", 0644, offsetof(struct RGF_ICR
, ICC
), doff_io32
},
489 {"ICR", 0644, offsetof(struct RGF_ICR
, ICR
), doff_io32
},
490 {"ICM", 0644, offsetof(struct RGF_ICR
, ICM
), doff_io32
},
491 {"ICS", 0244, offsetof(struct RGF_ICR
, ICS
), doff_io32
},
492 {"IMV", 0644, offsetof(struct RGF_ICR
, IMV
), doff_io32
},
493 {"IMS", 0244, offsetof(struct RGF_ICR
, IMS
), doff_io32
},
494 {"IMC", 0244, offsetof(struct RGF_ICR
, IMC
), doff_io32
},
498 static void wil6210_debugfs_create_ISR(struct wil6210_priv
*wil
,
499 const char *name
, struct dentry
*parent
,
502 struct dentry
*d
= debugfs_create_dir(name
, parent
);
504 wil6210_debugfs_init_offset(wil
, d
, (void * __force
)wil
->csr
+ off
,
508 static const struct dbg_off pseudo_isr_off
[] = {
509 {"CAUSE", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE
), doff_io32
},
510 {"MASK_SW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW
), doff_io32
},
511 {"MASK_FW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW
), doff_io32
},
515 static void wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv
*wil
,
516 struct dentry
*parent
)
518 struct dentry
*d
= debugfs_create_dir("PSEUDO_ISR", parent
);
520 wil6210_debugfs_init_offset(wil
, d
, (void * __force
)wil
->csr
,
524 static const struct dbg_off lgc_itr_cnt_off
[] = {
525 {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_CNT_TRSH
), doff_io32
},
526 {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_CNT_DATA
), doff_io32
},
527 {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_CNT_CRL
), doff_io32
},
531 static const struct dbg_off tx_itr_cnt_off
[] = {
532 {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH
),
534 {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA
),
536 {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL
),
538 {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH
),
540 {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA
),
542 {"IDL_CTL", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL
),
547 static const struct dbg_off rx_itr_cnt_off
[] = {
548 {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH
),
550 {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA
),
552 {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL
),
554 {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH
),
556 {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA
),
558 {"IDL_CTL", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL
),
563 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv
*wil
,
564 struct dentry
*parent
)
566 struct dentry
*d
, *dtx
, *drx
;
568 d
= debugfs_create_dir("ITR_CNT", parent
);
570 dtx
= debugfs_create_dir("TX", d
);
571 drx
= debugfs_create_dir("RX", d
);
573 wil6210_debugfs_init_offset(wil
, d
, (void * __force
)wil
->csr
,
576 wil6210_debugfs_init_offset(wil
, dtx
, (void * __force
)wil
->csr
,
579 wil6210_debugfs_init_offset(wil
, drx
, (void * __force
)wil
->csr
,
584 static int memread_show(struct seq_file
*s
, void *data
)
586 struct wil6210_priv
*wil
= s
->private;
590 ret
= wil_pm_runtime_get(wil
);
594 ret
= wil_mem_access_lock(wil
);
596 wil_pm_runtime_put(wil
);
600 a
= wmi_buffer(wil
, cpu_to_le32(mem_addr
));
603 seq_printf(s
, "[0x%08x] = 0x%08x\n", mem_addr
, readl(a
));
605 seq_printf(s
, "[0x%08x] = INVALID\n", mem_addr
);
607 wil_mem_access_unlock(wil
);
608 wil_pm_runtime_put(wil
);
612 DEFINE_SHOW_ATTRIBUTE(memread
);
614 static ssize_t
wil_read_file_ioblob(struct file
*file
, char __user
*user_buf
,
615 size_t count
, loff_t
*ppos
)
617 enum { max_count
= 4096 };
618 struct wil_blob_wrapper
*wil_blob
= file
->private_data
;
619 struct wil6210_priv
*wil
= wil_blob
->wil
;
620 loff_t aligned_pos
, pos
= *ppos
;
621 size_t available
= wil_blob
->blob
.size
;
623 size_t unaligned_bytes
, aligned_count
, ret
;
629 if (pos
>= available
|| !count
)
632 if (count
> available
- pos
)
633 count
= available
- pos
;
634 if (count
> max_count
)
637 /* set pos to 4 bytes aligned */
638 unaligned_bytes
= pos
% 4;
639 aligned_pos
= pos
- unaligned_bytes
;
640 aligned_count
= count
+ unaligned_bytes
;
642 buf
= kmalloc(aligned_count
, GFP_KERNEL
);
646 rc
= wil_pm_runtime_get(wil
);
652 rc
= wil_mem_access_lock(wil
);
655 wil_pm_runtime_put(wil
);
659 wil_memcpy_fromio_32(buf
, (const void __iomem
*)
660 wil_blob
->blob
.data
+ aligned_pos
, aligned_count
);
662 ret
= copy_to_user(user_buf
, buf
+ unaligned_bytes
, count
);
664 wil_mem_access_unlock(wil
);
665 wil_pm_runtime_put(wil
);
677 static const struct file_operations fops_ioblob
= {
678 .read
= wil_read_file_ioblob
,
680 .llseek
= default_llseek
,
684 struct dentry
*wil_debugfs_create_ioblob(const char *name
,
686 struct dentry
*parent
,
687 struct wil_blob_wrapper
*wil_blob
)
689 return debugfs_create_file(name
, mode
, parent
, wil_blob
, &fops_ioblob
);
692 /*---write channel 1..4 to rxon for it, 0 to rxoff---*/
693 static ssize_t
wil_write_file_rxon(struct file
*file
, const char __user
*buf
,
694 size_t len
, loff_t
*ppos
)
696 struct wil6210_priv
*wil
= file
->private_data
;
701 char *kbuf
= memdup_user_nul(buf
, len
);
704 return PTR_ERR(kbuf
);
705 rc
= kstrtol(kbuf
, 0, &channel
);
710 if ((channel
< 0) || (channel
> 4)) {
711 wil_err(wil
, "Invalid channel %ld\n", channel
);
717 rc
= wmi_set_channel(wil
, (int)channel
);
722 rc
= wmi_rxon(wil
, on
);
729 static const struct file_operations fops_rxon
= {
730 .write
= wil_write_file_rxon
,
734 static ssize_t
wil_write_file_rbufcap(struct file
*file
,
735 const char __user
*buf
,
736 size_t count
, loff_t
*ppos
)
738 struct wil6210_priv
*wil
= file
->private_data
;
742 rc
= kstrtoint_from_user(buf
, count
, 0, &val
);
744 wil_err(wil
, "Invalid argument\n");
747 /* input value: negative to disable, 0 to use system default,
748 * 1..ring size to set descriptor threshold
750 wil_info(wil
, "%s RBUFCAP, descriptors threshold - %d\n",
751 val
< 0 ? "Disabling" : "Enabling", val
);
753 if (!wil
->ring_rx
.va
|| val
> wil
->ring_rx
.size
) {
754 wil_err(wil
, "Invalid descriptors threshold, %d\n", val
);
758 rc
= wmi_rbufcap_cfg(wil
, val
< 0 ? 0 : 1, val
< 0 ? 0 : val
);
760 wil_err(wil
, "RBUFCAP config failed: %d\n", rc
);
767 static const struct file_operations fops_rbufcap
= {
768 .write
= wil_write_file_rbufcap
,
772 /* block ack control, write:
773 * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
774 * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
775 * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
777 static ssize_t
wil_write_back(struct file
*file
, const char __user
*buf
,
778 size_t len
, loff_t
*ppos
)
780 struct wil6210_priv
*wil
= file
->private_data
;
782 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
789 rc
= simple_write_to_buffer(kbuf
, len
, ppos
, buf
, len
);
792 return rc
>= 0 ? -EIO
: rc
;
796 rc
= sscanf(kbuf
, "%8s %d %d %d", cmd
, &p1
, &p2
, &p3
);
804 if ((strcmp(cmd
, "add") == 0) ||
805 (strcmp(cmd
, "del_tx") == 0)) {
806 struct wil_ring_tx_data
*txdata
;
808 if (p1
< 0 || p1
>= WIL6210_MAX_TX_RINGS
) {
809 wil_err(wil
, "BACK: invalid ring id %d\n", p1
);
812 txdata
= &wil
->ring_tx_data
[p1
];
813 if (strcmp(cmd
, "add") == 0) {
815 wil_err(wil
, "BACK: add require at least 2 params\n");
820 wmi_addba(wil
, txdata
->mid
, p1
, p2
, p3
);
823 p2
= WLAN_REASON_QSTA_LEAVE_QBSS
;
824 wmi_delba_tx(wil
, txdata
->mid
, p1
, p2
);
826 } else if (strcmp(cmd
, "del_rx") == 0) {
827 struct wil_sta_info
*sta
;
831 "BACK: del_rx require at least 2 params\n");
834 if (p1
< 0 || p1
>= wil
->max_assoc_sta
) {
835 wil_err(wil
, "BACK: invalid CID %d\n", p1
);
839 p3
= WLAN_REASON_QSTA_LEAVE_QBSS
;
841 wmi_delba_rx(wil
, sta
->mid
, p1
, p2
, p3
);
843 wil_err(wil
, "BACK: Unrecognized command \"%s\"\n", cmd
);
850 static ssize_t
wil_read_back(struct file
*file
, char __user
*user_buf
,
851 size_t count
, loff_t
*ppos
)
853 static const char text
[] = "block ack control, write:\n"
854 " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
855 "If missing, <timeout> defaults to 0\n"
856 " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
857 " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
858 "If missing, <reason> set to \"STA_LEAVING\" (36)\n";
860 return simple_read_from_buffer(user_buf
, count
, ppos
, text
,
864 static const struct file_operations fops_back
= {
865 .read
= wil_read_back
,
866 .write
= wil_write_back
,
870 /* pmc control, write:
871 * - "alloc <num descriptors> <descriptor_size>" to allocate PMC
872 * - "free" to release memory allocated for PMC
874 static ssize_t
wil_write_pmccfg(struct file
*file
, const char __user
*buf
,
875 size_t len
, loff_t
*ppos
)
877 struct wil6210_priv
*wil
= file
->private_data
;
879 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
881 int num_descs
, desc_size
;
886 rc
= simple_write_to_buffer(kbuf
, len
, ppos
, buf
, len
);
889 return rc
>= 0 ? -EIO
: rc
;
893 rc
= sscanf(kbuf
, "%8s %d %d", cmd
, &num_descs
, &desc_size
);
900 wil_err(wil
, "pmccfg: no params given\n");
904 if (0 == strcmp(cmd
, "alloc")) {
906 wil_err(wil
, "pmccfg: alloc requires 2 params\n");
909 wil_pmc_alloc(wil
, num_descs
, desc_size
);
910 } else if (0 == strcmp(cmd
, "free")) {
912 wil_err(wil
, "pmccfg: free does not have any params\n");
915 wil_pmc_free(wil
, true);
917 wil_err(wil
, "pmccfg: Unrecognized command \"%s\"\n", cmd
);
924 static ssize_t
wil_read_pmccfg(struct file
*file
, char __user
*user_buf
,
925 size_t count
, loff_t
*ppos
)
927 struct wil6210_priv
*wil
= file
->private_data
;
929 char help
[] = "pmc control, write:\n"
930 " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
931 " - \"free\" to free memory allocated for pmc\n";
933 snprintf(text
, sizeof(text
), "Last command status: %d\n\n%s",
934 wil_pmc_last_cmd_status(wil
), help
);
936 return simple_read_from_buffer(user_buf
, count
, ppos
, text
,
940 static const struct file_operations fops_pmccfg
= {
941 .read
= wil_read_pmccfg
,
942 .write
= wil_write_pmccfg
,
946 static const struct file_operations fops_pmcdata
= {
948 .read
= wil_pmc_read
,
949 .llseek
= wil_pmc_llseek
,
952 static int wil_pmcring_seq_open(struct inode
*inode
, struct file
*file
)
954 return single_open(file
, wil_pmcring_read
, inode
->i_private
);
957 static const struct file_operations fops_pmcring
= {
958 .open
= wil_pmcring_seq_open
,
959 .release
= single_release
,
965 /* Write mgmt frame to this file to send it */
966 static ssize_t
wil_write_file_txmgmt(struct file
*file
, const char __user
*buf
,
967 size_t len
, loff_t
*ppos
)
969 struct wil6210_priv
*wil
= file
->private_data
;
970 struct wiphy
*wiphy
= wil_to_wiphy(wil
);
971 struct wireless_dev
*wdev
= wil
->main_ndev
->ieee80211_ptr
;
972 struct cfg80211_mgmt_tx_params params
;
976 memset(¶ms
, 0, sizeof(params
));
981 frame
= memdup_user(buf
, len
);
983 return PTR_ERR(frame
);
988 rc
= wil_cfg80211_mgmt_tx(wiphy
, wdev
, ¶ms
, NULL
);
991 wil_info(wil
, "-> %d\n", rc
);
996 static const struct file_operations fops_txmgmt
= {
997 .write
= wil_write_file_txmgmt
,
1001 /* Write WMI command (w/o mbox header) to this file to send it
1002 * WMI starts from wil6210_mbox_hdr_wmi header
1004 static ssize_t
wil_write_file_wmi(struct file
*file
, const char __user
*buf
,
1005 size_t len
, loff_t
*ppos
)
1007 struct wil6210_priv
*wil
= file
->private_data
;
1008 struct wil6210_vif
*vif
= ndev_to_vif(wil
->main_ndev
);
1009 struct wmi_cmd_hdr
*wmi
;
1011 int cmdlen
= len
- sizeof(struct wmi_cmd_hdr
);
1018 wmi
= kmalloc(len
, GFP_KERNEL
);
1022 rc
= simple_write_to_buffer(wmi
, len
, ppos
, buf
, len
);
1028 cmd
= (cmdlen
> 0) ? &wmi
[1] : NULL
;
1029 cmdid
= le16_to_cpu(wmi
->command_id
);
1031 rc1
= wmi_send(wil
, cmdid
, vif
->mid
, cmd
, cmdlen
);
1034 wil_info(wil
, "0x%04x[%d] -> %d\n", cmdid
, cmdlen
, rc1
);
1039 static const struct file_operations fops_wmi
= {
1040 .write
= wil_write_file_wmi
,
1041 .open
= simple_open
,
1044 static void wil_seq_print_skb(struct seq_file
*s
, struct sk_buff
*skb
)
1047 int len
= skb_headlen(skb
);
1048 void *p
= skb
->data
;
1049 int nr_frags
= skb_shinfo(skb
)->nr_frags
;
1051 seq_printf(s
, " len = %d\n", len
);
1052 wil_seq_hexdump(s
, p
, len
, " : ");
1055 seq_printf(s
, " nr_frags = %d\n", nr_frags
);
1056 for (i
= 0; i
< nr_frags
; i
++) {
1057 const skb_frag_t
*frag
= &skb_shinfo(skb
)->frags
[i
];
1059 len
= skb_frag_size(frag
);
1060 p
= skb_frag_address_safe(frag
);
1061 seq_printf(s
, " [%2d] : len = %d\n", i
, len
);
1062 wil_seq_hexdump(s
, p
, len
, " : ");
1067 /*---------Tx/Rx descriptor------------*/
1068 static int txdesc_show(struct seq_file
*s
, void *data
)
1070 struct wil6210_priv
*wil
= s
->private;
1071 struct wil_ring
*ring
;
1073 int ring_idx
= dbg_ring_index
;
1074 int txdesc_idx
= dbg_txdesc_index
;
1075 volatile struct vring_tx_desc
*d
;
1077 struct sk_buff
*skb
;
1079 if (wil
->use_enhanced_dma_hw
) {
1080 /* RX ring index == 0 */
1081 if (ring_idx
>= WIL6210_MAX_TX_RINGS
) {
1082 seq_printf(s
, "invalid ring index %d\n", ring_idx
);
1085 tx
= ring_idx
> 0; /* desc ring 0 is reserved for RX */
1087 /* RX ring index == WIL6210_MAX_TX_RINGS */
1088 if (ring_idx
> WIL6210_MAX_TX_RINGS
) {
1089 seq_printf(s
, "invalid ring index %d\n", ring_idx
);
1092 tx
= (ring_idx
< WIL6210_MAX_TX_RINGS
);
1095 ring
= tx
? &wil
->ring_tx
[ring_idx
] : &wil
->ring_rx
;
1099 seq_printf(s
, "No Tx[%2d] RING\n", ring_idx
);
1101 seq_puts(s
, "No Rx RING\n");
1105 if (txdesc_idx
>= ring
->size
) {
1107 seq_printf(s
, "[%2d] TxDesc index (%d) >= size (%d)\n",
1108 ring_idx
, txdesc_idx
, ring
->size
);
1110 seq_printf(s
, "RxDesc index (%d) >= size (%d)\n",
1111 txdesc_idx
, ring
->size
);
1115 /* use struct vring_tx_desc for Rx as well,
1116 * only field used, .dma.length, is the same
1118 d
= &ring
->va
[txdesc_idx
].tx
.legacy
;
1119 u
= (volatile u32
*)d
;
1122 if (wil
->use_enhanced_dma_hw
) {
1124 skb
= ring
->ctx
? ring
->ctx
[txdesc_idx
].skb
: NULL
;
1125 } else if (wil
->rx_buff_mgmt
.buff_arr
) {
1126 struct wil_rx_enhanced_desc
*rx_d
=
1127 (struct wil_rx_enhanced_desc
*)
1128 &ring
->va
[txdesc_idx
].rx
.enhanced
;
1129 u16 buff_id
= le16_to_cpu(rx_d
->mac
.buff_id
);
1131 if (!wil_val_in_range(buff_id
, 0,
1132 wil
->rx_buff_mgmt
.size
))
1133 seq_printf(s
, "invalid buff_id %d\n", buff_id
);
1135 skb
= wil
->rx_buff_mgmt
.buff_arr
[buff_id
].skb
;
1138 skb
= ring
->ctx
[txdesc_idx
].skb
;
1141 seq_printf(s
, "Tx[%2d][%3d] = {\n", ring_idx
,
1144 seq_printf(s
, "Rx[%3d] = {\n", txdesc_idx
);
1145 seq_printf(s
, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1146 u
[0], u
[1], u
[2], u
[3]);
1147 seq_printf(s
, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1148 u
[4], u
[5], u
[6], u
[7]);
1149 seq_printf(s
, " SKB = 0x%p\n", skb
);
1153 wil_seq_print_skb(s
, skb
);
1160 DEFINE_SHOW_ATTRIBUTE(txdesc
);
1162 /*---------Tx/Rx status message------------*/
1163 static int status_msg_show(struct seq_file
*s
, void *data
)
1165 struct wil6210_priv
*wil
= s
->private;
1166 int sring_idx
= dbg_sring_index
;
1167 struct wil_status_ring
*sring
;
1169 u32 status_msg_idx
= dbg_status_msg_index
;
1172 if (sring_idx
>= WIL6210_MAX_STATUS_RINGS
) {
1173 seq_printf(s
, "invalid status ring index %d\n", sring_idx
);
1177 sring
= &wil
->srings
[sring_idx
];
1181 seq_printf(s
, "No %cX status ring\n", tx
? 'T' : 'R');
1185 if (status_msg_idx
>= sring
->size
) {
1186 seq_printf(s
, "%cxDesc index (%d) >= size (%d)\n",
1187 tx
? 'T' : 'R', status_msg_idx
, sring
->size
);
1191 u
= sring
->va
+ (sring
->elem_size
* status_msg_idx
);
1193 seq_printf(s
, "%cx[%d][%3d] = {\n",
1194 tx
? 'T' : 'R', sring_idx
, status_msg_idx
);
1196 seq_printf(s
, " 0x%08x 0x%08x 0x%08x 0x%08x\n",
1197 u
[0], u
[1], u
[2], u
[3]);
1198 if (!tx
&& !wil
->use_compressed_rx_status
)
1199 seq_printf(s
, " 0x%08x 0x%08x 0x%08x 0x%08x\n",
1200 u
[4], u
[5], u
[6], u
[7]);
1206 DEFINE_SHOW_ATTRIBUTE(status_msg
);
1208 static int wil_print_rx_buff(struct seq_file
*s
, struct list_head
*lh
)
1210 struct wil_rx_buff
*it
;
1213 list_for_each_entry(it
, lh
, list
) {
1214 if ((i
% 16) == 0 && i
!= 0)
1216 seq_printf(s
, "[%4d] ", it
->id
);
1219 seq_printf(s
, "\nNumber of buffers: %u\n", i
);
1224 static int rx_buff_mgmt_show(struct seq_file
*s
, void *data
)
1226 struct wil6210_priv
*wil
= s
->private;
1227 struct wil_rx_buff_mgmt
*rbm
= &wil
->rx_buff_mgmt
;
1234 seq_printf(s
, " size = %zu\n", rbm
->size
);
1235 seq_printf(s
, " free_list_empty_cnt = %lu\n",
1236 rbm
->free_list_empty_cnt
);
1238 /* Print active list */
1239 seq_puts(s
, " Active list:\n");
1240 num_active
= wil_print_rx_buff(s
, &rbm
->active
);
1241 seq_puts(s
, "\n Free list:\n");
1242 num_free
= wil_print_rx_buff(s
, &rbm
->free
);
1244 seq_printf(s
, " Total number of buffers: %u\n",
1245 num_active
+ num_free
);
1249 DEFINE_SHOW_ATTRIBUTE(rx_buff_mgmt
);
1251 /*---------beamforming------------*/
1252 static char *wil_bfstatus_str(u32 status
)
1266 static bool is_all_zeros(void * const x_
, size_t sz
)
1268 /* if reply is all-0, ignore this CID */
1272 for (n
= 0; n
< sz
/ sizeof(*x
); n
++)
1279 static int bf_show(struct seq_file
*s
, void *data
)
1283 struct wil6210_priv
*wil
= s
->private;
1284 struct wil6210_vif
*vif
= ndev_to_vif(wil
->main_ndev
);
1285 struct wmi_notify_req_cmd cmd
= {
1289 struct wmi_cmd_hdr wmi
;
1290 struct wmi_notify_req_done_event evt
;
1293 memset(&reply
, 0, sizeof(reply
));
1295 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1299 rc
= wmi_call(wil
, WMI_NOTIFY_REQ_CMDID
, vif
->mid
,
1301 WMI_NOTIFY_REQ_DONE_EVENTID
, &reply
,
1302 sizeof(reply
), WIL_WMI_CALL_GENERAL_TO_MS
);
1303 /* if reply is all-0, ignore this CID */
1304 if (rc
|| is_all_zeros(&reply
.evt
, sizeof(reply
.evt
)))
1307 status
= le32_to_cpu(reply
.evt
.status
);
1308 seq_printf(s
, "CID %d {\n"
1309 " TSF = 0x%016llx\n"
1310 " TxMCS = %2d TxTpt = %4d\n"
1313 " Status = 0x%08x %s\n"
1314 " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
1315 " Goodput(rx:tx) %4d:%4d\n"
1318 le64_to_cpu(reply
.evt
.tsf
),
1319 le16_to_cpu(reply
.evt
.bf_mcs
),
1320 le32_to_cpu(reply
.evt
.tx_tpt
),
1323 status
, wil_bfstatus_str(status
),
1324 le16_to_cpu(reply
.evt
.my_rx_sector
),
1325 le16_to_cpu(reply
.evt
.my_tx_sector
),
1326 le16_to_cpu(reply
.evt
.other_rx_sector
),
1327 le16_to_cpu(reply
.evt
.other_tx_sector
),
1328 le32_to_cpu(reply
.evt
.rx_goodput
),
1329 le32_to_cpu(reply
.evt
.tx_goodput
));
1333 DEFINE_SHOW_ATTRIBUTE(bf
);
1335 /*---------temp------------*/
1336 static void print_temp(struct seq_file
*s
, const char *prefix
, s32 t
)
1340 case WMI_INVALID_TEMPERATURE
:
1341 seq_printf(s
, "%s N/A\n", prefix
);
1344 seq_printf(s
, "%s %s%d.%03d\n", prefix
, (t
< 0 ? "-" : ""),
1345 abs(t
/ 1000), abs(t
% 1000));
1350 static int temp_show(struct seq_file
*s
, void *data
)
1352 struct wil6210_priv
*wil
= s
->private;
1355 if (test_bit(WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF
,
1356 wil
->fw_capabilities
)) {
1357 struct wmi_temp_sense_all_done_event sense_all_evt
;
1360 "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is supported");
1361 rc
= wmi_get_all_temperatures(wil
, &sense_all_evt
);
1363 seq_puts(s
, "Failed\n");
1366 print_temp(s
, "T_mac =",
1367 le32_to_cpu(sense_all_evt
.baseband_t1000
));
1368 seq_printf(s
, "Connected RFs [0x%08x]\n",
1369 sense_all_evt
.rf_bitmap
);
1370 for (i
= 0; i
< WMI_MAX_XIF_PORTS_NUM
; i
++) {
1371 seq_printf(s
, "RF[%d] = ", i
);
1373 le32_to_cpu(sense_all_evt
.rf_t1000
[i
]));
1379 "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is not supported");
1380 rc
= wmi_get_temperature(wil
, &t_m
, &t_r
);
1382 seq_puts(s
, "Failed\n");
1385 print_temp(s
, "T_mac =", t_m
);
1386 print_temp(s
, "T_radio =", t_r
);
1390 DEFINE_SHOW_ATTRIBUTE(temp
);
1392 /*---------freq------------*/
1393 static int freq_show(struct seq_file
*s
, void *data
)
1395 struct wil6210_priv
*wil
= s
->private;
1396 struct wireless_dev
*wdev
= wil
->main_ndev
->ieee80211_ptr
;
1397 u32 freq
= wdev
->chandef
.chan
? wdev
->chandef
.chan
->center_freq
: 0;
1399 seq_printf(s
, "Freq = %d\n", freq
);
1403 DEFINE_SHOW_ATTRIBUTE(freq
);
1405 /*---------link------------*/
1406 static int link_show(struct seq_file
*s
, void *data
)
1408 struct wil6210_priv
*wil
= s
->private;
1409 struct station_info
*sinfo
;
1412 sinfo
= kzalloc(sizeof(*sinfo
), GFP_KERNEL
);
1416 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1417 struct wil_sta_info
*p
= &wil
->sta
[i
];
1418 char *status
= "unknown";
1419 struct wil6210_vif
*vif
;
1422 switch (p
->status
) {
1423 case wil_sta_unused
:
1426 case wil_sta_conn_pending
:
1427 status
= "pending ";
1429 case wil_sta_connected
:
1430 status
= "connected";
1433 mid
= (p
->status
!= wil_sta_unused
) ? p
->mid
: U8_MAX
;
1434 seq_printf(s
, "[%d][MID %d] %pM %s\n",
1435 i
, mid
, p
->addr
, status
);
1437 if (p
->status
!= wil_sta_connected
)
1440 vif
= (mid
< GET_MAX_VIFS(wil
)) ? wil
->vifs
[mid
] : NULL
;
1442 rc
= wil_cid_fill_sinfo(vif
, i
, sinfo
);
1446 seq_printf(s
, " Tx_mcs = %d\n", sinfo
->txrate
.mcs
);
1447 seq_printf(s
, " Rx_mcs = %d\n", sinfo
->rxrate
.mcs
);
1448 seq_printf(s
, " SQ = %d\n", sinfo
->signal
);
1450 seq_puts(s
, " INVALID MID\n");
1458 DEFINE_SHOW_ATTRIBUTE(link
);
1460 /*---------info------------*/
1461 static int info_show(struct seq_file
*s
, void *data
)
1463 struct wil6210_priv
*wil
= s
->private;
1464 struct net_device
*ndev
= wil
->main_ndev
;
1465 int is_ac
= power_supply_is_system_supplied();
1466 int rx
= atomic_xchg(&wil
->isr_count_rx
, 0);
1467 int tx
= atomic_xchg(&wil
->isr_count_tx
, 0);
1468 static ulong rxf_old
, txf_old
;
1469 ulong rxf
= ndev
->stats
.rx_packets
;
1470 ulong txf
= ndev
->stats
.tx_packets
;
1473 /* >0 : AC; 0 : battery; <0 : error */
1474 seq_printf(s
, "AC powered : %d\n", is_ac
);
1475 seq_printf(s
, "Rx irqs:packets : %8d : %8ld\n", rx
, rxf
- rxf_old
);
1476 seq_printf(s
, "Tx irqs:packets : %8d : %8ld\n", tx
, txf
- txf_old
);
1480 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1481 " " __stringify(x) : ""
1483 for (i
= 0; i
< ndev
->num_tx_queues
; i
++) {
1484 struct netdev_queue
*txq
= netdev_get_tx_queue(ndev
, i
);
1485 unsigned long state
= txq
->state
;
1487 seq_printf(s
, "Tx queue[%i] state : 0x%lx%s%s%s\n", i
, state
,
1488 CHECK_QSTATE(DRV_XOFF
),
1489 CHECK_QSTATE(STACK_XOFF
),
1490 CHECK_QSTATE(FROZEN
)
1496 DEFINE_SHOW_ATTRIBUTE(info
);
1498 /*---------recovery------------*/
1499 /* mode = [manual|auto]
1500 * state = [idle|pending|running]
1502 static ssize_t
wil_read_file_recovery(struct file
*file
, char __user
*user_buf
,
1503 size_t count
, loff_t
*ppos
)
1505 struct wil6210_priv
*wil
= file
->private_data
;
1508 static const char * const sstate
[] = {"idle", "pending", "running"};
1510 n
= snprintf(buf
, sizeof(buf
), "mode = %s\nstate = %s\n",
1511 no_fw_recovery
? "manual" : "auto",
1512 sstate
[wil
->recovery_state
]);
1514 n
= min_t(int, n
, sizeof(buf
));
1516 return simple_read_from_buffer(user_buf
, count
, ppos
,
1520 static ssize_t
wil_write_file_recovery(struct file
*file
,
1521 const char __user
*buf_
,
1522 size_t count
, loff_t
*ppos
)
1524 struct wil6210_priv
*wil
= file
->private_data
;
1525 static const char run_command
[] = "run";
1526 char buf
[sizeof(run_command
) + 1]; /* to detect "runx" */
1529 if (wil
->recovery_state
!= fw_recovery_pending
) {
1530 wil_err(wil
, "No recovery pending\n");
1535 wil_err(wil
, "Offset [%d]\n", (int)*ppos
);
1539 if (count
> sizeof(buf
)) {
1540 wil_err(wil
, "Input too long, len = %d\n", (int)count
);
1544 rc
= simple_write_to_buffer(buf
, sizeof(buf
) - 1, ppos
, buf_
, count
);
1549 if (0 == strcmp(buf
, run_command
))
1550 wil_set_recovery_state(wil
, fw_recovery_running
);
1552 wil_err(wil
, "Bad recovery command \"%s\"\n", buf
);
1557 static const struct file_operations fops_recovery
= {
1558 .read
= wil_read_file_recovery
,
1559 .write
= wil_write_file_recovery
,
1560 .open
= simple_open
,
1563 /*---------Station matrix------------*/
1564 static void wil_print_rxtid(struct seq_file
*s
, struct wil_tid_ampdu_rx
*r
)
1567 u16 index
= ((r
->head_seq_num
- r
->ssn
) & 0xfff) % r
->buf_size
;
1568 unsigned long long drop_dup
= r
->drop_dup
, drop_old
= r
->drop_old
;
1569 unsigned long long drop_dup_mcast
= r
->drop_dup_mcast
;
1571 seq_printf(s
, "([%2d]) 0x%03x [", r
->buf_size
, r
->head_seq_num
);
1572 for (i
= 0; i
< r
->buf_size
; i
++) {
1574 seq_printf(s
, "%c", r
->reorder_buf
[i
] ? 'O' : '|');
1576 seq_printf(s
, "%c", r
->reorder_buf
[i
] ? '*' : '_');
1579 "] total %llu drop %llu (dup %llu + old %llu + dup mcast %llu) last 0x%03x\n",
1580 r
->total
, drop_dup
+ drop_old
+ drop_dup_mcast
, drop_dup
,
1581 drop_old
, drop_dup_mcast
, r
->ssn_last_drop
);
1584 static void wil_print_rxtid_crypto(struct seq_file
*s
, int tid
,
1585 struct wil_tid_crypto_rx
*c
)
1589 for (i
= 0; i
< 4; i
++) {
1590 struct wil_tid_crypto_rx_single
*cc
= &c
->key_id
[i
];
1598 if (tid
< WIL_STA_TID_NUM
)
1599 seq_printf(s
, " [%2d] PN", tid
);
1601 seq_puts(s
, " [GR] PN");
1603 for (i
= 0; i
< 4; i
++) {
1604 struct wil_tid_crypto_rx_single
*cc
= &c
->key_id
[i
];
1606 seq_printf(s
, " [%i%s]%6phN", i
, cc
->key_set
? "+" : "-",
1612 static int sta_show(struct seq_file
*s
, void *data
)
1613 __acquires(&p
->tid_rx_lock
) __releases(&p
->tid_rx_lock
)
1615 struct wil6210_priv
*wil
= s
->private;
1618 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1619 struct wil_sta_info
*p
= &wil
->sta
[i
];
1620 char *status
= "unknown";
1623 bool sta_connected
= false;
1625 switch (p
->status
) {
1626 case wil_sta_unused
:
1629 case wil_sta_conn_pending
:
1630 status
= "pending ";
1632 case wil_sta_connected
:
1633 status
= "connected";
1637 mid
= (p
->status
!= wil_sta_unused
) ? p
->mid
: U8_MAX
;
1638 if (mid
< GET_MAX_VIFS(wil
)) {
1639 struct wil6210_vif
*vif
= wil
->vifs
[mid
];
1641 if (vif
->wdev
.iftype
== NL80211_IFTYPE_STATION
&&
1642 p
->status
== wil_sta_connected
)
1643 sta_connected
= true;
1645 /* print roam counter only for connected stations */
1647 seq_printf(s
, "[%d] %pM connected (roam counter %d) MID %d AID %d\n",
1648 i
, p
->addr
, p
->stats
.ft_roams
, mid
, aid
);
1650 seq_printf(s
, "[%d] %pM %s MID %d AID %d\n", i
,
1651 p
->addr
, status
, mid
, aid
);
1653 if (p
->status
== wil_sta_connected
) {
1654 spin_lock_bh(&p
->tid_rx_lock
);
1655 for (tid
= 0; tid
< WIL_STA_TID_NUM
; tid
++) {
1656 struct wil_tid_ampdu_rx
*r
= p
->tid_rx
[tid
];
1657 struct wil_tid_crypto_rx
*c
=
1658 &p
->tid_crypto_rx
[tid
];
1661 seq_printf(s
, " [%2d] ", tid
);
1662 wil_print_rxtid(s
, r
);
1665 wil_print_rxtid_crypto(s
, tid
, c
);
1667 wil_print_rxtid_crypto(s
, WIL_STA_TID_NUM
,
1668 &p
->group_crypto_rx
);
1669 spin_unlock_bh(&p
->tid_rx_lock
);
1671 "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n",
1672 p
->stats
.rx_non_data_frame
,
1673 p
->stats
.rx_short_frame
,
1674 p
->stats
.rx_large_frame
,
1675 p
->stats
.rx_replay
);
1677 "mic error %lu, key error %lu, amsdu error %lu, csum error %lu\n",
1678 p
->stats
.rx_mic_error
,
1679 p
->stats
.rx_key_error
,
1680 p
->stats
.rx_amsdu_error
,
1681 p
->stats
.rx_csum_err
);
1683 seq_puts(s
, "Rx/MCS:");
1684 for (mcs
= 0; mcs
< ARRAY_SIZE(p
->stats
.rx_per_mcs
);
1686 seq_printf(s
, " %lld",
1687 p
->stats
.rx_per_mcs
[mcs
]);
1694 DEFINE_SHOW_ATTRIBUTE(sta
);
1696 static int mids_show(struct seq_file
*s
, void *data
)
1698 struct wil6210_priv
*wil
= s
->private;
1699 struct wil6210_vif
*vif
;
1700 struct net_device
*ndev
;
1703 mutex_lock(&wil
->vif_mutex
);
1704 for (i
= 0; i
< GET_MAX_VIFS(wil
); i
++) {
1708 ndev
= vif_to_ndev(vif
);
1709 seq_printf(s
, "[%d] %pM %s\n", i
, ndev
->dev_addr
,
1712 seq_printf(s
, "[%d] unused\n", i
);
1715 mutex_unlock(&wil
->vif_mutex
);
1719 DEFINE_SHOW_ATTRIBUTE(mids
);
1721 static int wil_tx_latency_debugfs_show(struct seq_file
*s
, void *data
)
1722 __acquires(&p
->tid_rx_lock
) __releases(&p
->tid_rx_lock
)
1724 struct wil6210_priv
*wil
= s
->private;
1727 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1728 struct wil_sta_info
*p
= &wil
->sta
[i
];
1729 char *status
= "unknown";
1733 if (!p
->tx_latency_bins
)
1736 switch (p
->status
) {
1737 case wil_sta_unused
:
1740 case wil_sta_conn_pending
:
1741 status
= "pending ";
1743 case wil_sta_connected
:
1744 status
= "connected";
1748 mid
= (p
->status
!= wil_sta_unused
) ? p
->mid
: U8_MAX
;
1749 seq_printf(s
, "[%d] %pM %s MID %d AID %d\n", i
, p
->addr
, status
,
1752 if (p
->status
== wil_sta_connected
) {
1753 u64 num_packets
= 0;
1754 u64 tx_latency_avg
= p
->stats
.tx_latency_total_us
;
1756 seq_puts(s
, "Tx/Latency bin:");
1757 for (bin
= 0; bin
< WIL_NUM_LATENCY_BINS
; bin
++) {
1758 seq_printf(s
, " %lld",
1759 p
->tx_latency_bins
[bin
]);
1760 num_packets
+= p
->tx_latency_bins
[bin
];
1765 do_div(tx_latency_avg
, num_packets
);
1766 seq_printf(s
, "Tx/Latency min/avg/max (us): %d/%lld/%d",
1767 p
->stats
.tx_latency_min_us
,
1769 p
->stats
.tx_latency_max_us
);
1778 static int wil_tx_latency_seq_open(struct inode
*inode
, struct file
*file
)
1780 return single_open(file
, wil_tx_latency_debugfs_show
,
1784 static ssize_t
wil_tx_latency_write(struct file
*file
, const char __user
*buf
,
1785 size_t len
, loff_t
*ppos
)
1787 struct seq_file
*s
= file
->private_data
;
1788 struct wil6210_priv
*wil
= s
->private;
1792 rc
= kstrtoint_from_user(buf
, len
, 0, &val
);
1794 wil_err(wil
, "Invalid argument\n");
1798 /* default resolution */
1800 if (val
&& (val
< 50 || val
> 1000)) {
1801 wil_err(wil
, "Invalid resolution %d\n", val
);
1806 if (wil
->tx_latency
== enable
)
1809 wil_info(wil
, "%s TX latency measurements (resolution %dusec)\n",
1810 enable
? "Enabling" : "Disabling", val
);
1813 size_t sz
= sizeof(u64
) * WIL_NUM_LATENCY_BINS
;
1815 wil
->tx_latency_res
= val
;
1816 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1817 struct wil_sta_info
*sta
= &wil
->sta
[i
];
1819 kfree(sta
->tx_latency_bins
);
1820 sta
->tx_latency_bins
= kzalloc(sz
, GFP_KERNEL
);
1821 if (!sta
->tx_latency_bins
)
1823 sta
->stats
.tx_latency_min_us
= U32_MAX
;
1824 sta
->stats
.tx_latency_max_us
= 0;
1825 sta
->stats
.tx_latency_total_us
= 0;
1828 wil
->tx_latency
= enable
;
1833 static const struct file_operations fops_tx_latency
= {
1834 .open
= wil_tx_latency_seq_open
,
1835 .release
= single_release
,
1837 .write
= wil_tx_latency_write
,
1838 .llseek
= seq_lseek
,
1841 static void wil_link_stats_print_basic(struct wil6210_vif
*vif
,
1843 struct wmi_link_stats_basic
*basic
)
1847 if (basic
->per_average
!= 0xff)
1848 snprintf(per
, sizeof(per
), "%d%%", basic
->per_average
);
1850 seq_printf(s
, "CID %d {\n"
1851 "\tTxMCS %d TxTpt %d\n"
1852 "\tGoodput(rx:tx) %d:%d\n"
1853 "\tRxBcastFrames %d\n"
1854 "\tRSSI %d SQI %d SNR %d PER %s\n"
1855 "\tRx RFC %d Ant num %d\n"
1856 "\tSectors(rx:tx) my %d:%d peer %d:%d\n"
1859 basic
->bf_mcs
, le32_to_cpu(basic
->tx_tpt
),
1860 le32_to_cpu(basic
->rx_goodput
),
1861 le32_to_cpu(basic
->tx_goodput
),
1862 le32_to_cpu(basic
->rx_bcast_frames
),
1863 basic
->rssi
, basic
->sqi
, basic
->snr
, per
,
1864 basic
->selected_rfc
, basic
->rx_effective_ant_num
,
1865 basic
->my_rx_sector
, basic
->my_tx_sector
,
1866 basic
->other_rx_sector
, basic
->other_tx_sector
);
1869 static void wil_link_stats_print_global(struct wil6210_priv
*wil
,
1871 struct wmi_link_stats_global
*global
)
1873 seq_printf(s
, "Frames(rx:tx) %d:%d\n"
1874 "BA Frames(rx:tx) %d:%d\n"
1876 "Rx Errors (MIC:CRC) %d:%d\n"
1877 "Tx Errors (no ack) %d\n",
1878 le32_to_cpu(global
->rx_frames
),
1879 le32_to_cpu(global
->tx_frames
),
1880 le32_to_cpu(global
->rx_ba_frames
),
1881 le32_to_cpu(global
->tx_ba_frames
),
1882 le32_to_cpu(global
->tx_beacons
),
1883 le32_to_cpu(global
->rx_mic_errors
),
1884 le32_to_cpu(global
->rx_crc_errors
),
1885 le32_to_cpu(global
->tx_fail_no_ack
));
1888 static void wil_link_stats_debugfs_show_vif(struct wil6210_vif
*vif
,
1891 struct wil6210_priv
*wil
= vif_to_wil(vif
);
1892 struct wmi_link_stats_basic
*stats
;
1895 if (!vif
->fw_stats_ready
) {
1896 seq_puts(s
, "no statistics\n");
1900 seq_printf(s
, "TSF %lld\n", vif
->fw_stats_tsf
);
1901 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1902 if (wil
->sta
[i
].status
== wil_sta_unused
)
1904 if (wil
->sta
[i
].mid
!= vif
->mid
)
1907 stats
= &wil
->sta
[i
].fw_stats_basic
;
1908 wil_link_stats_print_basic(vif
, s
, stats
);
1912 static int wil_link_stats_debugfs_show(struct seq_file
*s
, void *data
)
1914 struct wil6210_priv
*wil
= s
->private;
1915 struct wil6210_vif
*vif
;
1918 rc
= mutex_lock_interruptible(&wil
->vif_mutex
);
1922 /* iterate over all MIDs and show per-cid statistics. Then show the
1925 for (i
= 0; i
< GET_MAX_VIFS(wil
); i
++) {
1928 seq_printf(s
, "MID %d ", i
);
1930 seq_puts(s
, "unused\n");
1934 wil_link_stats_debugfs_show_vif(vif
, s
);
1937 mutex_unlock(&wil
->vif_mutex
);
1942 static int wil_link_stats_seq_open(struct inode
*inode
, struct file
*file
)
1944 return single_open(file
, wil_link_stats_debugfs_show
, inode
->i_private
);
1947 static ssize_t
wil_link_stats_write(struct file
*file
, const char __user
*buf
,
1948 size_t len
, loff_t
*ppos
)
1950 struct seq_file
*s
= file
->private_data
;
1951 struct wil6210_priv
*wil
= s
->private;
1952 int cid
, interval
, rc
, i
;
1953 struct wil6210_vif
*vif
;
1954 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
1959 rc
= simple_write_to_buffer(kbuf
, len
, ppos
, buf
, len
);
1962 return rc
>= 0 ? -EIO
: rc
;
1966 /* specify cid (use -1 for all cids) and snapshot interval in ms */
1967 rc
= sscanf(kbuf
, "%d %d", &cid
, &interval
);
1971 if (rc
< 2 || interval
< 0)
1974 wil_info(wil
, "request link statistics, cid %d interval %d\n",
1977 rc
= mutex_lock_interruptible(&wil
->vif_mutex
);
1981 for (i
= 0; i
< GET_MAX_VIFS(wil
); i
++) {
1986 rc
= wmi_link_stats_cfg(vif
, WMI_LINK_STATS_TYPE_BASIC
,
1987 (cid
== -1 ? 0xff : cid
), interval
);
1989 wil_err(wil
, "link statistics failed for mid %d\n", i
);
1991 mutex_unlock(&wil
->vif_mutex
);
1996 static const struct file_operations fops_link_stats
= {
1997 .open
= wil_link_stats_seq_open
,
1998 .release
= single_release
,
2000 .write
= wil_link_stats_write
,
2001 .llseek
= seq_lseek
,
2005 wil_link_stats_global_debugfs_show(struct seq_file
*s
, void *data
)
2007 struct wil6210_priv
*wil
= s
->private;
2009 if (!wil
->fw_stats_global
.ready
)
2012 seq_printf(s
, "TSF %lld\n", wil
->fw_stats_global
.tsf
);
2013 wil_link_stats_print_global(wil
, s
, &wil
->fw_stats_global
.stats
);
2019 wil_link_stats_global_seq_open(struct inode
*inode
, struct file
*file
)
2021 return single_open(file
, wil_link_stats_global_debugfs_show
,
2026 wil_link_stats_global_write(struct file
*file
, const char __user
*buf
,
2027 size_t len
, loff_t
*ppos
)
2029 struct seq_file
*s
= file
->private_data
;
2030 struct wil6210_priv
*wil
= s
->private;
2032 struct wil6210_vif
*vif
= ndev_to_vif(wil
->main_ndev
);
2034 /* specify snapshot interval in ms */
2035 rc
= kstrtoint_from_user(buf
, len
, 0, &interval
);
2036 if (rc
|| interval
< 0) {
2037 wil_err(wil
, "Invalid argument\n");
2041 wil_info(wil
, "request global link stats, interval %d\n", interval
);
2043 rc
= wmi_link_stats_cfg(vif
, WMI_LINK_STATS_TYPE_GLOBAL
, 0, interval
);
2045 wil_err(wil
, "global link stats failed %d\n", rc
);
2047 return rc
? rc
: len
;
2050 static const struct file_operations fops_link_stats_global
= {
2051 .open
= wil_link_stats_global_seq_open
,
2052 .release
= single_release
,
2054 .write
= wil_link_stats_global_write
,
2055 .llseek
= seq_lseek
,
2058 static ssize_t
wil_read_file_led_cfg(struct file
*file
, char __user
*user_buf
,
2059 size_t count
, loff_t
*ppos
)
2064 n
= snprintf(buf
, sizeof(buf
),
2065 "led_id is set to %d, echo 1 to enable, 0 to disable\n",
2068 n
= min_t(int, n
, sizeof(buf
));
2070 return simple_read_from_buffer(user_buf
, count
, ppos
,
2074 static ssize_t
wil_write_file_led_cfg(struct file
*file
,
2075 const char __user
*buf_
,
2076 size_t count
, loff_t
*ppos
)
2078 struct wil6210_priv
*wil
= file
->private_data
;
2082 rc
= kstrtoint_from_user(buf_
, count
, 0, &val
);
2084 wil_err(wil
, "Invalid argument\n");
2088 wil_info(wil
, "%s led %d\n", val
? "Enabling" : "Disabling", led_id
);
2089 rc
= wmi_led_cfg(wil
, val
);
2091 wil_info(wil
, "%s led %d failed\n",
2092 val
? "Enabling" : "Disabling", led_id
);
2099 static const struct file_operations fops_led_cfg
= {
2100 .read
= wil_read_file_led_cfg
,
2101 .write
= wil_write_file_led_cfg
,
2102 .open
= simple_open
,
2105 /* led_blink_time, write:
2106 * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
2108 static ssize_t
wil_write_led_blink_time(struct file
*file
,
2109 const char __user
*buf
,
2110 size_t len
, loff_t
*ppos
)
2113 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
2118 rc
= simple_write_to_buffer(kbuf
, len
, ppos
, buf
, len
);
2121 return rc
>= 0 ? -EIO
: rc
;
2125 rc
= sscanf(kbuf
, "%d %d %d %d %d %d",
2126 &led_blink_time
[WIL_LED_TIME_SLOW
].on_ms
,
2127 &led_blink_time
[WIL_LED_TIME_SLOW
].off_ms
,
2128 &led_blink_time
[WIL_LED_TIME_MED
].on_ms
,
2129 &led_blink_time
[WIL_LED_TIME_MED
].off_ms
,
2130 &led_blink_time
[WIL_LED_TIME_FAST
].on_ms
,
2131 &led_blink_time
[WIL_LED_TIME_FAST
].off_ms
);
2142 static ssize_t
wil_read_led_blink_time(struct file
*file
, char __user
*user_buf
,
2143 size_t count
, loff_t
*ppos
)
2145 static char text
[400];
2147 snprintf(text
, sizeof(text
),
2148 "To set led blink on/off time variables write:\n"
2149 "<blink_on_slow> <blink_off_slow> <blink_on_med> "
2150 "<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
2151 "The current values are:\n"
2152 "%d %d %d %d %d %d\n",
2153 led_blink_time
[WIL_LED_TIME_SLOW
].on_ms
,
2154 led_blink_time
[WIL_LED_TIME_SLOW
].off_ms
,
2155 led_blink_time
[WIL_LED_TIME_MED
].on_ms
,
2156 led_blink_time
[WIL_LED_TIME_MED
].off_ms
,
2157 led_blink_time
[WIL_LED_TIME_FAST
].on_ms
,
2158 led_blink_time
[WIL_LED_TIME_FAST
].off_ms
);
2160 return simple_read_from_buffer(user_buf
, count
, ppos
, text
,
2164 static const struct file_operations fops_led_blink_time
= {
2165 .read
= wil_read_led_blink_time
,
2166 .write
= wil_write_led_blink_time
,
2167 .open
= simple_open
,
2170 /*---------FW capabilities------------*/
2171 static int wil_fw_capabilities_debugfs_show(struct seq_file
*s
, void *data
)
2173 struct wil6210_priv
*wil
= s
->private;
2175 seq_printf(s
, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX
,
2176 wil
->fw_capabilities
);
2181 static int wil_fw_capabilities_seq_open(struct inode
*inode
, struct file
*file
)
2183 return single_open(file
, wil_fw_capabilities_debugfs_show
,
2187 static const struct file_operations fops_fw_capabilities
= {
2188 .open
= wil_fw_capabilities_seq_open
,
2189 .release
= single_release
,
2191 .llseek
= seq_lseek
,
2194 /*---------FW version------------*/
2195 static int wil_fw_version_debugfs_show(struct seq_file
*s
, void *data
)
2197 struct wil6210_priv
*wil
= s
->private;
2199 if (wil
->fw_version
[0])
2200 seq_printf(s
, "%s\n", wil
->fw_version
);
2202 seq_puts(s
, "N/A\n");
2207 static int wil_fw_version_seq_open(struct inode
*inode
, struct file
*file
)
2209 return single_open(file
, wil_fw_version_debugfs_show
,
2213 static const struct file_operations fops_fw_version
= {
2214 .open
= wil_fw_version_seq_open
,
2215 .release
= single_release
,
2217 .llseek
= seq_lseek
,
2220 /*---------suspend_stats---------*/
2221 static ssize_t
wil_write_suspend_stats(struct file
*file
,
2222 const char __user
*buf
,
2223 size_t len
, loff_t
*ppos
)
2225 struct wil6210_priv
*wil
= file
->private_data
;
2227 memset(&wil
->suspend_stats
, 0, sizeof(wil
->suspend_stats
));
2232 static ssize_t
wil_read_suspend_stats(struct file
*file
,
2233 char __user
*user_buf
,
2234 size_t count
, loff_t
*ppos
)
2236 struct wil6210_priv
*wil
= file
->private_data
;
2238 int n
, ret
, text_size
= 500;
2240 text
= kmalloc(text_size
, GFP_KERNEL
);
2244 n
= snprintf(text
, text_size
,
2245 "Radio on suspend statistics:\n"
2246 "successful suspends:%ld failed suspends:%ld\n"
2247 "successful resumes:%ld failed resumes:%ld\n"
2248 "rejected by device:%ld\n"
2249 "Radio off suspend statistics:\n"
2250 "successful suspends:%ld failed suspends:%ld\n"
2251 "successful resumes:%ld failed resumes:%ld\n"
2252 "General statistics:\n"
2253 "rejected by host:%ld\n",
2254 wil
->suspend_stats
.r_on
.successful_suspends
,
2255 wil
->suspend_stats
.r_on
.failed_suspends
,
2256 wil
->suspend_stats
.r_on
.successful_resumes
,
2257 wil
->suspend_stats
.r_on
.failed_resumes
,
2258 wil
->suspend_stats
.rejected_by_device
,
2259 wil
->suspend_stats
.r_off
.successful_suspends
,
2260 wil
->suspend_stats
.r_off
.failed_suspends
,
2261 wil
->suspend_stats
.r_off
.successful_resumes
,
2262 wil
->suspend_stats
.r_off
.failed_resumes
,
2263 wil
->suspend_stats
.rejected_by_host
);
2265 n
= min_t(int, n
, text_size
);
2267 ret
= simple_read_from_buffer(user_buf
, count
, ppos
, text
, n
);
2274 static const struct file_operations fops_suspend_stats
= {
2275 .read
= wil_read_suspend_stats
,
2276 .write
= wil_write_suspend_stats
,
2277 .open
= simple_open
,
2280 /*---------compressed_rx_status---------*/
2281 static ssize_t
wil_compressed_rx_status_write(struct file
*file
,
2282 const char __user
*buf
,
2283 size_t len
, loff_t
*ppos
)
2285 struct seq_file
*s
= file
->private_data
;
2286 struct wil6210_priv
*wil
= s
->private;
2287 int compressed_rx_status
;
2290 rc
= kstrtoint_from_user(buf
, len
, 0, &compressed_rx_status
);
2292 wil_err(wil
, "Invalid argument\n");
2296 if (wil_has_active_ifaces(wil
, true, false)) {
2297 wil_err(wil
, "cannot change edma config after iface is up\n");
2301 wil_info(wil
, "%sable compressed_rx_status\n",
2302 compressed_rx_status
? "En" : "Dis");
2304 wil
->use_compressed_rx_status
= compressed_rx_status
;
2310 wil_compressed_rx_status_show(struct seq_file
*s
, void *data
)
2312 struct wil6210_priv
*wil
= s
->private;
2314 seq_printf(s
, "%d\n", wil
->use_compressed_rx_status
);
2320 wil_compressed_rx_status_seq_open(struct inode
*inode
, struct file
*file
)
2322 return single_open(file
, wil_compressed_rx_status_show
,
2326 static const struct file_operations fops_compressed_rx_status
= {
2327 .open
= wil_compressed_rx_status_seq_open
,
2328 .release
= single_release
,
2330 .write
= wil_compressed_rx_status_write
,
2331 .llseek
= seq_lseek
,
2334 /*----------------*/
2335 static void wil6210_debugfs_init_blobs(struct wil6210_priv
*wil
,
2341 for (i
= 0; i
< ARRAY_SIZE(fw_mapping
); i
++) {
2342 struct wil_blob_wrapper
*wil_blob
= &wil
->blobs
[i
];
2343 struct debugfs_blob_wrapper
*blob
= &wil_blob
->blob
;
2344 const struct fw_map
*map
= &fw_mapping
[i
];
2349 wil_blob
->wil
= wil
;
2350 blob
->data
= (void * __force
)wil
->csr
+ HOSTADDR(map
->host
);
2351 blob
->size
= map
->to
- map
->from
;
2352 snprintf(name
, sizeof(name
), "blob_%s", map
->name
);
2353 wil_debugfs_create_ioblob(name
, 0444, dbg
, wil_blob
);
2358 static const struct {
2361 const struct file_operations
*fops
;
2363 {"mbox", 0444, &mbox_fops
},
2364 {"rings", 0444, &ring_fops
},
2365 {"stations", 0444, &sta_fops
},
2366 {"mids", 0444, &mids_fops
},
2367 {"desc", 0444, &txdesc_fops
},
2368 {"bf", 0444, &bf_fops
},
2369 {"mem_val", 0644, &memread_fops
},
2370 {"rxon", 0244, &fops_rxon
},
2371 {"tx_mgmt", 0244, &fops_txmgmt
},
2372 {"wmi_send", 0244, &fops_wmi
},
2373 {"back", 0644, &fops_back
},
2374 {"pmccfg", 0644, &fops_pmccfg
},
2375 {"pmcdata", 0444, &fops_pmcdata
},
2376 {"pmcring", 0444, &fops_pmcring
},
2377 {"temp", 0444, &temp_fops
},
2378 {"freq", 0444, &freq_fops
},
2379 {"link", 0444, &link_fops
},
2380 {"info", 0444, &info_fops
},
2381 {"recovery", 0644, &fops_recovery
},
2382 {"led_cfg", 0644, &fops_led_cfg
},
2383 {"led_blink_time", 0644, &fops_led_blink_time
},
2384 {"fw_capabilities", 0444, &fops_fw_capabilities
},
2385 {"fw_version", 0444, &fops_fw_version
},
2386 {"suspend_stats", 0644, &fops_suspend_stats
},
2387 {"compressed_rx_status", 0644, &fops_compressed_rx_status
},
2388 {"srings", 0444, &srings_fops
},
2389 {"status_msg", 0444, &status_msg_fops
},
2390 {"rx_buff_mgmt", 0444, &rx_buff_mgmt_fops
},
2391 {"tx_latency", 0644, &fops_tx_latency
},
2392 {"link_stats", 0644, &fops_link_stats
},
2393 {"link_stats_global", 0644, &fops_link_stats_global
},
2394 {"rbufcap", 0244, &fops_rbufcap
},
2397 static void wil6210_debugfs_init_files(struct wil6210_priv
*wil
,
2402 for (i
= 0; i
< ARRAY_SIZE(dbg_files
); i
++)
2403 debugfs_create_file(dbg_files
[i
].name
, dbg_files
[i
].mode
, dbg
,
2404 wil
, dbg_files
[i
].fops
);
2407 /* interrupt control blocks */
2408 static const struct {
2412 {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR
)},
2413 {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR
)},
2414 {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR
)},
2415 {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR
)},
2418 static void wil6210_debugfs_init_isr(struct wil6210_priv
*wil
,
2423 for (i
= 0; i
< ARRAY_SIZE(dbg_icr
); i
++)
2424 wil6210_debugfs_create_ISR(wil
, dbg_icr
[i
].name
, dbg
,
2425 dbg_icr
[i
].icr_off
);
2428 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
2429 offsetof(struct wil6210_priv, name), type}
2431 /* fields in struct wil6210_priv */
2432 static const struct dbg_off dbg_wil_off
[] = {
2433 WIL_FIELD(status
[0], 0644, doff_ulong
),
2434 WIL_FIELD(hw_version
, 0444, doff_x32
),
2435 WIL_FIELD(recovery_count
, 0444, doff_u32
),
2436 WIL_FIELD(discovery_mode
, 0644, doff_u8
),
2437 WIL_FIELD(chip_revision
, 0444, doff_u8
),
2438 WIL_FIELD(abft_len
, 0644, doff_u8
),
2439 WIL_FIELD(wakeup_trigger
, 0644, doff_u8
),
2440 WIL_FIELD(ring_idle_trsh
, 0644, doff_u32
),
2441 WIL_FIELD(num_rx_status_rings
, 0644, doff_u8
),
2442 WIL_FIELD(rx_status_ring_order
, 0644, doff_u32
),
2443 WIL_FIELD(tx_status_ring_order
, 0644, doff_u32
),
2444 WIL_FIELD(rx_buff_id_count
, 0644, doff_u32
),
2445 WIL_FIELD(amsdu_en
, 0644, doff_u8
),
2449 static const struct dbg_off dbg_wil_regs
[] = {
2450 {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0
),
2452 {"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1
), doff_io32
},
2453 {"RGF_USER_USAGE_2", 0444, HOSTADDR(RGF_USER_USAGE_2
), doff_io32
},
2457 /* static parameters */
2458 static const struct dbg_off dbg_statics
[] = {
2459 {"desc_index", 0644, (ulong
)&dbg_txdesc_index
, doff_u32
},
2460 {"ring_index", 0644, (ulong
)&dbg_ring_index
, doff_u32
},
2461 {"mem_addr", 0644, (ulong
)&mem_addr
, doff_u32
},
2462 {"led_polarity", 0644, (ulong
)&led_polarity
, doff_u8
},
2463 {"status_index", 0644, (ulong
)&dbg_status_msg_index
, doff_u32
},
2464 {"sring_index", 0644, (ulong
)&dbg_sring_index
, doff_u32
},
2465 {"drop_if_ring_full", 0644, (ulong
)&drop_if_ring_full
, doff_u8
},
2469 static const int dbg_off_count
= 4 * (ARRAY_SIZE(isr_off
) - 1) +
2470 ARRAY_SIZE(dbg_wil_regs
) - 1 +
2471 ARRAY_SIZE(pseudo_isr_off
) - 1 +
2472 ARRAY_SIZE(lgc_itr_cnt_off
) - 1 +
2473 ARRAY_SIZE(tx_itr_cnt_off
) - 1 +
2474 ARRAY_SIZE(rx_itr_cnt_off
) - 1;
2476 int wil6210_debugfs_init(struct wil6210_priv
*wil
)
2478 struct dentry
*dbg
= wil
->debug
= debugfs_create_dir(WIL_NAME
,
2479 wil_to_wiphy(wil
)->debugfsdir
);
2480 if (IS_ERR_OR_NULL(dbg
))
2483 wil
->dbg_data
.data_arr
= kcalloc(dbg_off_count
,
2484 sizeof(struct wil_debugfs_iomem_data
),
2486 if (!wil
->dbg_data
.data_arr
) {
2487 debugfs_remove_recursive(dbg
);
2492 wil
->dbg_data
.iomem_data_count
= 0;
2496 wil6210_debugfs_init_files(wil
, dbg
);
2497 wil6210_debugfs_init_isr(wil
, dbg
);
2498 wil6210_debugfs_init_blobs(wil
, dbg
);
2499 wil6210_debugfs_init_offset(wil
, dbg
, wil
, dbg_wil_off
);
2500 wil6210_debugfs_init_offset(wil
, dbg
, (void * __force
)wil
->csr
,
2502 wil6210_debugfs_init_offset(wil
, dbg
, NULL
, dbg_statics
);
2504 wil6210_debugfs_create_pseudo_ISR(wil
, dbg
);
2506 wil6210_debugfs_create_ITR_CNT(wil
, dbg
);
2511 void wil6210_debugfs_remove(struct wil6210_priv
*wil
)
2515 debugfs_remove_recursive(wil
->debug
);
2518 kfree(wil
->dbg_data
.data_arr
);
2519 for (i
= 0; i
< wil
->max_assoc_sta
; i
++)
2520 kfree(wil
->sta
[i
].tx_latency_bins
);
2522 /* free pmc memory without sending command to fw, as it will
2523 * be reset on the way down anyway
2525 wil_pmc_free(wil
, false);