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
);
1015 if (cmdlen
< 0 || *ppos
!= 0)
1018 wmi
= memdup_user(buf
, len
);
1020 return PTR_ERR(wmi
);
1022 cmd
= (cmdlen
> 0) ? &wmi
[1] : NULL
;
1023 cmdid
= le16_to_cpu(wmi
->command_id
);
1025 rc1
= wmi_send(wil
, cmdid
, vif
->mid
, cmd
, cmdlen
);
1028 wil_info(wil
, "0x%04x[%d] -> %d\n", cmdid
, cmdlen
, rc1
);
1033 static const struct file_operations fops_wmi
= {
1034 .write
= wil_write_file_wmi
,
1035 .open
= simple_open
,
1038 static void wil_seq_print_skb(struct seq_file
*s
, struct sk_buff
*skb
)
1041 int len
= skb_headlen(skb
);
1042 void *p
= skb
->data
;
1043 int nr_frags
= skb_shinfo(skb
)->nr_frags
;
1045 seq_printf(s
, " len = %d\n", len
);
1046 wil_seq_hexdump(s
, p
, len
, " : ");
1049 seq_printf(s
, " nr_frags = %d\n", nr_frags
);
1050 for (i
= 0; i
< nr_frags
; i
++) {
1051 const skb_frag_t
*frag
= &skb_shinfo(skb
)->frags
[i
];
1053 len
= skb_frag_size(frag
);
1054 p
= skb_frag_address_safe(frag
);
1055 seq_printf(s
, " [%2d] : len = %d\n", i
, len
);
1056 wil_seq_hexdump(s
, p
, len
, " : ");
1061 /*---------Tx/Rx descriptor------------*/
1062 static int txdesc_show(struct seq_file
*s
, void *data
)
1064 struct wil6210_priv
*wil
= s
->private;
1065 struct wil_ring
*ring
;
1067 int ring_idx
= dbg_ring_index
;
1068 int txdesc_idx
= dbg_txdesc_index
;
1069 volatile struct vring_tx_desc
*d
;
1071 struct sk_buff
*skb
;
1073 if (wil
->use_enhanced_dma_hw
) {
1074 /* RX ring index == 0 */
1075 if (ring_idx
>= WIL6210_MAX_TX_RINGS
) {
1076 seq_printf(s
, "invalid ring index %d\n", ring_idx
);
1079 tx
= ring_idx
> 0; /* desc ring 0 is reserved for RX */
1081 /* RX ring index == WIL6210_MAX_TX_RINGS */
1082 if (ring_idx
> WIL6210_MAX_TX_RINGS
) {
1083 seq_printf(s
, "invalid ring index %d\n", ring_idx
);
1086 tx
= (ring_idx
< WIL6210_MAX_TX_RINGS
);
1089 ring
= tx
? &wil
->ring_tx
[ring_idx
] : &wil
->ring_rx
;
1093 seq_printf(s
, "No Tx[%2d] RING\n", ring_idx
);
1095 seq_puts(s
, "No Rx RING\n");
1099 if (txdesc_idx
>= ring
->size
) {
1101 seq_printf(s
, "[%2d] TxDesc index (%d) >= size (%d)\n",
1102 ring_idx
, txdesc_idx
, ring
->size
);
1104 seq_printf(s
, "RxDesc index (%d) >= size (%d)\n",
1105 txdesc_idx
, ring
->size
);
1109 /* use struct vring_tx_desc for Rx as well,
1110 * only field used, .dma.length, is the same
1112 d
= &ring
->va
[txdesc_idx
].tx
.legacy
;
1113 u
= (volatile u32
*)d
;
1116 if (wil
->use_enhanced_dma_hw
) {
1118 skb
= ring
->ctx
? ring
->ctx
[txdesc_idx
].skb
: NULL
;
1119 } else if (wil
->rx_buff_mgmt
.buff_arr
) {
1120 struct wil_rx_enhanced_desc
*rx_d
=
1121 (struct wil_rx_enhanced_desc
*)
1122 &ring
->va
[txdesc_idx
].rx
.enhanced
;
1123 u16 buff_id
= le16_to_cpu(rx_d
->mac
.buff_id
);
1125 if (!wil_val_in_range(buff_id
, 0,
1126 wil
->rx_buff_mgmt
.size
))
1127 seq_printf(s
, "invalid buff_id %d\n", buff_id
);
1129 skb
= wil
->rx_buff_mgmt
.buff_arr
[buff_id
].skb
;
1132 skb
= ring
->ctx
[txdesc_idx
].skb
;
1135 seq_printf(s
, "Tx[%2d][%3d] = {\n", ring_idx
,
1138 seq_printf(s
, "Rx[%3d] = {\n", txdesc_idx
);
1139 seq_printf(s
, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1140 u
[0], u
[1], u
[2], u
[3]);
1141 seq_printf(s
, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1142 u
[4], u
[5], u
[6], u
[7]);
1143 seq_printf(s
, " SKB = 0x%p\n", skb
);
1147 wil_seq_print_skb(s
, skb
);
1154 DEFINE_SHOW_ATTRIBUTE(txdesc
);
1156 /*---------Tx/Rx status message------------*/
1157 static int status_msg_show(struct seq_file
*s
, void *data
)
1159 struct wil6210_priv
*wil
= s
->private;
1160 int sring_idx
= dbg_sring_index
;
1161 struct wil_status_ring
*sring
;
1163 u32 status_msg_idx
= dbg_status_msg_index
;
1166 if (sring_idx
>= WIL6210_MAX_STATUS_RINGS
) {
1167 seq_printf(s
, "invalid status ring index %d\n", sring_idx
);
1171 sring
= &wil
->srings
[sring_idx
];
1175 seq_printf(s
, "No %cX status ring\n", tx
? 'T' : 'R');
1179 if (status_msg_idx
>= sring
->size
) {
1180 seq_printf(s
, "%cxDesc index (%d) >= size (%d)\n",
1181 tx
? 'T' : 'R', status_msg_idx
, sring
->size
);
1185 u
= sring
->va
+ (sring
->elem_size
* status_msg_idx
);
1187 seq_printf(s
, "%cx[%d][%3d] = {\n",
1188 tx
? 'T' : 'R', sring_idx
, status_msg_idx
);
1190 seq_printf(s
, " 0x%08x 0x%08x 0x%08x 0x%08x\n",
1191 u
[0], u
[1], u
[2], u
[3]);
1192 if (!tx
&& !wil
->use_compressed_rx_status
)
1193 seq_printf(s
, " 0x%08x 0x%08x 0x%08x 0x%08x\n",
1194 u
[4], u
[5], u
[6], u
[7]);
1200 DEFINE_SHOW_ATTRIBUTE(status_msg
);
1202 static int wil_print_rx_buff(struct seq_file
*s
, struct list_head
*lh
)
1204 struct wil_rx_buff
*it
;
1207 list_for_each_entry(it
, lh
, list
) {
1208 if ((i
% 16) == 0 && i
!= 0)
1210 seq_printf(s
, "[%4d] ", it
->id
);
1213 seq_printf(s
, "\nNumber of buffers: %u\n", i
);
1218 static int rx_buff_mgmt_show(struct seq_file
*s
, void *data
)
1220 struct wil6210_priv
*wil
= s
->private;
1221 struct wil_rx_buff_mgmt
*rbm
= &wil
->rx_buff_mgmt
;
1228 seq_printf(s
, " size = %zu\n", rbm
->size
);
1229 seq_printf(s
, " free_list_empty_cnt = %lu\n",
1230 rbm
->free_list_empty_cnt
);
1232 /* Print active list */
1233 seq_puts(s
, " Active list:\n");
1234 num_active
= wil_print_rx_buff(s
, &rbm
->active
);
1235 seq_puts(s
, "\n Free list:\n");
1236 num_free
= wil_print_rx_buff(s
, &rbm
->free
);
1238 seq_printf(s
, " Total number of buffers: %u\n",
1239 num_active
+ num_free
);
1243 DEFINE_SHOW_ATTRIBUTE(rx_buff_mgmt
);
1245 /*---------beamforming------------*/
1246 static char *wil_bfstatus_str(u32 status
)
1260 static bool is_all_zeros(void * const x_
, size_t sz
)
1262 /* if reply is all-0, ignore this CID */
1266 for (n
= 0; n
< sz
/ sizeof(*x
); n
++)
1273 static int bf_show(struct seq_file
*s
, void *data
)
1277 struct wil6210_priv
*wil
= s
->private;
1278 struct wil6210_vif
*vif
= ndev_to_vif(wil
->main_ndev
);
1279 struct wmi_notify_req_cmd cmd
= {
1283 struct wmi_cmd_hdr wmi
;
1284 struct wmi_notify_req_done_event evt
;
1287 memset(&reply
, 0, sizeof(reply
));
1289 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1294 rc
= wmi_call(wil
, WMI_NOTIFY_REQ_CMDID
, vif
->mid
,
1296 WMI_NOTIFY_REQ_DONE_EVENTID
, &reply
,
1297 sizeof(reply
), WIL_WMI_CALL_GENERAL_TO_MS
);
1298 /* if reply is all-0, ignore this CID */
1299 if (rc
|| is_all_zeros(&reply
.evt
, sizeof(reply
.evt
)))
1302 status
= le32_to_cpu(reply
.evt
.status
);
1303 bf_mcs
= le16_to_cpu(reply
.evt
.bf_mcs
);
1304 seq_printf(s
, "CID %d {\n"
1305 " TSF = 0x%016llx\n"
1306 " TxMCS = %s TxTpt = %4d\n"
1309 " Status = 0x%08x %s\n"
1310 " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
1311 " Goodput(rx:tx) %4d:%4d\n"
1314 le64_to_cpu(reply
.evt
.tsf
),
1315 WIL_EXTENDED_MCS_CHECK(bf_mcs
),
1316 le32_to_cpu(reply
.evt
.tx_tpt
),
1319 status
, wil_bfstatus_str(status
),
1320 le16_to_cpu(reply
.evt
.my_rx_sector
),
1321 le16_to_cpu(reply
.evt
.my_tx_sector
),
1322 le16_to_cpu(reply
.evt
.other_rx_sector
),
1323 le16_to_cpu(reply
.evt
.other_tx_sector
),
1324 le32_to_cpu(reply
.evt
.rx_goodput
),
1325 le32_to_cpu(reply
.evt
.tx_goodput
));
1329 DEFINE_SHOW_ATTRIBUTE(bf
);
1331 /*---------temp------------*/
1332 static void print_temp(struct seq_file
*s
, const char *prefix
, s32 t
)
1336 case WMI_INVALID_TEMPERATURE
:
1337 seq_printf(s
, "%s N/A\n", prefix
);
1340 seq_printf(s
, "%s %s%d.%03d\n", prefix
, (t
< 0 ? "-" : ""),
1341 abs(t
/ 1000), abs(t
% 1000));
1346 static int temp_show(struct seq_file
*s
, void *data
)
1348 struct wil6210_priv
*wil
= s
->private;
1351 if (test_bit(WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF
,
1352 wil
->fw_capabilities
)) {
1353 struct wmi_temp_sense_all_done_event sense_all_evt
;
1356 "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is supported");
1357 rc
= wmi_get_all_temperatures(wil
, &sense_all_evt
);
1359 seq_puts(s
, "Failed\n");
1362 print_temp(s
, "T_mac =",
1363 le32_to_cpu(sense_all_evt
.baseband_t1000
));
1364 seq_printf(s
, "Connected RFs [0x%08x]\n",
1365 sense_all_evt
.rf_bitmap
);
1366 for (i
= 0; i
< WMI_MAX_XIF_PORTS_NUM
; i
++) {
1367 seq_printf(s
, "RF[%d] = ", i
);
1369 le32_to_cpu(sense_all_evt
.rf_t1000
[i
]));
1375 "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is not supported");
1376 rc
= wmi_get_temperature(wil
, &t_m
, &t_r
);
1378 seq_puts(s
, "Failed\n");
1381 print_temp(s
, "T_mac =", t_m
);
1382 print_temp(s
, "T_radio =", t_r
);
1386 DEFINE_SHOW_ATTRIBUTE(temp
);
1388 /*---------link------------*/
1389 static int link_show(struct seq_file
*s
, void *data
)
1391 struct wil6210_priv
*wil
= s
->private;
1392 struct station_info
*sinfo
;
1395 sinfo
= kzalloc(sizeof(*sinfo
), GFP_KERNEL
);
1399 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1400 struct wil_sta_info
*p
= &wil
->sta
[i
];
1401 char *status
= "unknown";
1402 struct wil6210_vif
*vif
;
1405 switch (p
->status
) {
1406 case wil_sta_unused
:
1409 case wil_sta_conn_pending
:
1410 status
= "pending ";
1412 case wil_sta_connected
:
1413 status
= "connected";
1416 mid
= (p
->status
!= wil_sta_unused
) ? p
->mid
: U8_MAX
;
1417 seq_printf(s
, "[%d][MID %d] %pM %s\n",
1418 i
, mid
, p
->addr
, status
);
1420 if (p
->status
!= wil_sta_connected
)
1423 vif
= (mid
< GET_MAX_VIFS(wil
)) ? wil
->vifs
[mid
] : NULL
;
1425 rc
= wil_cid_fill_sinfo(vif
, i
, sinfo
);
1429 seq_printf(s
, " Tx_mcs = %s\n",
1430 WIL_EXTENDED_MCS_CHECK(sinfo
->txrate
.mcs
));
1431 seq_printf(s
, " Rx_mcs = %s\n",
1432 WIL_EXTENDED_MCS_CHECK(sinfo
->rxrate
.mcs
));
1433 seq_printf(s
, " SQ = %d\n", sinfo
->signal
);
1435 seq_puts(s
, " INVALID MID\n");
1443 DEFINE_SHOW_ATTRIBUTE(link
);
1445 /*---------info------------*/
1446 static int info_show(struct seq_file
*s
, void *data
)
1448 struct wil6210_priv
*wil
= s
->private;
1449 struct net_device
*ndev
= wil
->main_ndev
;
1450 int is_ac
= power_supply_is_system_supplied();
1451 int rx
= atomic_xchg(&wil
->isr_count_rx
, 0);
1452 int tx
= atomic_xchg(&wil
->isr_count_tx
, 0);
1453 static ulong rxf_old
, txf_old
;
1454 ulong rxf
= ndev
->stats
.rx_packets
;
1455 ulong txf
= ndev
->stats
.tx_packets
;
1458 /* >0 : AC; 0 : battery; <0 : error */
1459 seq_printf(s
, "AC powered : %d\n", is_ac
);
1460 seq_printf(s
, "Rx irqs:packets : %8d : %8ld\n", rx
, rxf
- rxf_old
);
1461 seq_printf(s
, "Tx irqs:packets : %8d : %8ld\n", tx
, txf
- txf_old
);
1465 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1466 " " __stringify(x) : ""
1468 for (i
= 0; i
< ndev
->num_tx_queues
; i
++) {
1469 struct netdev_queue
*txq
= netdev_get_tx_queue(ndev
, i
);
1470 unsigned long state
= txq
->state
;
1472 seq_printf(s
, "Tx queue[%i] state : 0x%lx%s%s%s\n", i
, state
,
1473 CHECK_QSTATE(DRV_XOFF
),
1474 CHECK_QSTATE(STACK_XOFF
),
1475 CHECK_QSTATE(FROZEN
)
1481 DEFINE_SHOW_ATTRIBUTE(info
);
1483 /*---------recovery------------*/
1484 /* mode = [manual|auto]
1485 * state = [idle|pending|running]
1487 static ssize_t
wil_read_file_recovery(struct file
*file
, char __user
*user_buf
,
1488 size_t count
, loff_t
*ppos
)
1490 struct wil6210_priv
*wil
= file
->private_data
;
1493 static const char * const sstate
[] = {"idle", "pending", "running"};
1495 n
= snprintf(buf
, sizeof(buf
), "mode = %s\nstate = %s\n",
1496 no_fw_recovery
? "manual" : "auto",
1497 sstate
[wil
->recovery_state
]);
1499 n
= min_t(int, n
, sizeof(buf
));
1501 return simple_read_from_buffer(user_buf
, count
, ppos
,
1505 static ssize_t
wil_write_file_recovery(struct file
*file
,
1506 const char __user
*buf_
,
1507 size_t count
, loff_t
*ppos
)
1509 struct wil6210_priv
*wil
= file
->private_data
;
1510 static const char run_command
[] = "run";
1511 char buf
[sizeof(run_command
) + 1]; /* to detect "runx" */
1514 if (wil
->recovery_state
!= fw_recovery_pending
) {
1515 wil_err(wil
, "No recovery pending\n");
1520 wil_err(wil
, "Offset [%d]\n", (int)*ppos
);
1524 if (count
> sizeof(buf
)) {
1525 wil_err(wil
, "Input too long, len = %d\n", (int)count
);
1529 rc
= simple_write_to_buffer(buf
, sizeof(buf
) - 1, ppos
, buf_
, count
);
1534 if (0 == strcmp(buf
, run_command
))
1535 wil_set_recovery_state(wil
, fw_recovery_running
);
1537 wil_err(wil
, "Bad recovery command \"%s\"\n", buf
);
1542 static const struct file_operations fops_recovery
= {
1543 .read
= wil_read_file_recovery
,
1544 .write
= wil_write_file_recovery
,
1545 .open
= simple_open
,
1548 /*---------Station matrix------------*/
1549 static void wil_print_rxtid(struct seq_file
*s
, struct wil_tid_ampdu_rx
*r
)
1552 u16 index
= ((r
->head_seq_num
- r
->ssn
) & 0xfff) % r
->buf_size
;
1553 unsigned long long drop_dup
= r
->drop_dup
, drop_old
= r
->drop_old
;
1554 unsigned long long drop_dup_mcast
= r
->drop_dup_mcast
;
1556 seq_printf(s
, "([%2d]) 0x%03x [", r
->buf_size
, r
->head_seq_num
);
1557 for (i
= 0; i
< r
->buf_size
; i
++) {
1559 seq_printf(s
, "%c", r
->reorder_buf
[i
] ? 'O' : '|');
1561 seq_printf(s
, "%c", r
->reorder_buf
[i
] ? '*' : '_');
1564 "] total %llu drop %llu (dup %llu + old %llu + dup mcast %llu) last 0x%03x\n",
1565 r
->total
, drop_dup
+ drop_old
+ drop_dup_mcast
, drop_dup
,
1566 drop_old
, drop_dup_mcast
, r
->ssn_last_drop
);
1569 static void wil_print_rxtid_crypto(struct seq_file
*s
, int tid
,
1570 struct wil_tid_crypto_rx
*c
)
1574 for (i
= 0; i
< 4; i
++) {
1575 struct wil_tid_crypto_rx_single
*cc
= &c
->key_id
[i
];
1583 if (tid
< WIL_STA_TID_NUM
)
1584 seq_printf(s
, " [%2d] PN", tid
);
1586 seq_puts(s
, " [GR] PN");
1588 for (i
= 0; i
< 4; i
++) {
1589 struct wil_tid_crypto_rx_single
*cc
= &c
->key_id
[i
];
1591 seq_printf(s
, " [%i%s]%6phN", i
, cc
->key_set
? "+" : "-",
1597 static int sta_show(struct seq_file
*s
, void *data
)
1598 __acquires(&p
->tid_rx_lock
) __releases(&p
->tid_rx_lock
)
1600 struct wil6210_priv
*wil
= s
->private;
1603 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1604 struct wil_sta_info
*p
= &wil
->sta
[i
];
1605 char *status
= "unknown";
1608 bool sta_connected
= false;
1610 switch (p
->status
) {
1611 case wil_sta_unused
:
1614 case wil_sta_conn_pending
:
1615 status
= "pending ";
1617 case wil_sta_connected
:
1618 status
= "connected";
1622 mid
= (p
->status
!= wil_sta_unused
) ? p
->mid
: U8_MAX
;
1623 if (mid
< GET_MAX_VIFS(wil
)) {
1624 struct wil6210_vif
*vif
= wil
->vifs
[mid
];
1626 if (vif
->wdev
.iftype
== NL80211_IFTYPE_STATION
&&
1627 p
->status
== wil_sta_connected
)
1628 sta_connected
= true;
1630 /* print roam counter only for connected stations */
1632 seq_printf(s
, "[%d] %pM connected (roam counter %d) MID %d AID %d\n",
1633 i
, p
->addr
, p
->stats
.ft_roams
, mid
, aid
);
1635 seq_printf(s
, "[%d] %pM %s MID %d AID %d\n", i
,
1636 p
->addr
, status
, mid
, aid
);
1638 if (p
->status
== wil_sta_connected
) {
1639 spin_lock_bh(&p
->tid_rx_lock
);
1640 for (tid
= 0; tid
< WIL_STA_TID_NUM
; tid
++) {
1641 struct wil_tid_ampdu_rx
*r
= p
->tid_rx
[tid
];
1642 struct wil_tid_crypto_rx
*c
=
1643 &p
->tid_crypto_rx
[tid
];
1646 seq_printf(s
, " [%2d] ", tid
);
1647 wil_print_rxtid(s
, r
);
1650 wil_print_rxtid_crypto(s
, tid
, c
);
1652 wil_print_rxtid_crypto(s
, WIL_STA_TID_NUM
,
1653 &p
->group_crypto_rx
);
1654 spin_unlock_bh(&p
->tid_rx_lock
);
1656 "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n",
1657 p
->stats
.rx_non_data_frame
,
1658 p
->stats
.rx_short_frame
,
1659 p
->stats
.rx_large_frame
,
1660 p
->stats
.rx_replay
);
1662 "mic error %lu, key error %lu, amsdu error %lu, csum error %lu\n",
1663 p
->stats
.rx_mic_error
,
1664 p
->stats
.rx_key_error
,
1665 p
->stats
.rx_amsdu_error
,
1666 p
->stats
.rx_csum_err
);
1668 seq_puts(s
, "Rx/MCS:");
1669 for (mcs
= 0; mcs
< ARRAY_SIZE(p
->stats
.rx_per_mcs
);
1671 seq_printf(s
, " %lld",
1672 p
->stats
.rx_per_mcs
[mcs
]);
1679 DEFINE_SHOW_ATTRIBUTE(sta
);
1681 static int mids_show(struct seq_file
*s
, void *data
)
1683 struct wil6210_priv
*wil
= s
->private;
1684 struct wil6210_vif
*vif
;
1685 struct net_device
*ndev
;
1688 mutex_lock(&wil
->vif_mutex
);
1689 for (i
= 0; i
< GET_MAX_VIFS(wil
); i
++) {
1693 ndev
= vif_to_ndev(vif
);
1694 seq_printf(s
, "[%d] %pM %s\n", i
, ndev
->dev_addr
,
1697 seq_printf(s
, "[%d] unused\n", i
);
1700 mutex_unlock(&wil
->vif_mutex
);
1704 DEFINE_SHOW_ATTRIBUTE(mids
);
1706 static int wil_tx_latency_debugfs_show(struct seq_file
*s
, void *data
)
1707 __acquires(&p
->tid_rx_lock
) __releases(&p
->tid_rx_lock
)
1709 struct wil6210_priv
*wil
= s
->private;
1712 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1713 struct wil_sta_info
*p
= &wil
->sta
[i
];
1714 char *status
= "unknown";
1718 if (!p
->tx_latency_bins
)
1721 switch (p
->status
) {
1722 case wil_sta_unused
:
1725 case wil_sta_conn_pending
:
1726 status
= "pending ";
1728 case wil_sta_connected
:
1729 status
= "connected";
1733 mid
= (p
->status
!= wil_sta_unused
) ? p
->mid
: U8_MAX
;
1734 seq_printf(s
, "[%d] %pM %s MID %d AID %d\n", i
, p
->addr
, status
,
1737 if (p
->status
== wil_sta_connected
) {
1738 u64 num_packets
= 0;
1739 u64 tx_latency_avg
= p
->stats
.tx_latency_total_us
;
1741 seq_puts(s
, "Tx/Latency bin:");
1742 for (bin
= 0; bin
< WIL_NUM_LATENCY_BINS
; bin
++) {
1743 seq_printf(s
, " %lld",
1744 p
->tx_latency_bins
[bin
]);
1745 num_packets
+= p
->tx_latency_bins
[bin
];
1750 do_div(tx_latency_avg
, num_packets
);
1751 seq_printf(s
, "Tx/Latency min/avg/max (us): %d/%lld/%d",
1752 p
->stats
.tx_latency_min_us
,
1754 p
->stats
.tx_latency_max_us
);
1763 static int wil_tx_latency_seq_open(struct inode
*inode
, struct file
*file
)
1765 return single_open(file
, wil_tx_latency_debugfs_show
,
1769 static ssize_t
wil_tx_latency_write(struct file
*file
, const char __user
*buf
,
1770 size_t len
, loff_t
*ppos
)
1772 struct seq_file
*s
= file
->private_data
;
1773 struct wil6210_priv
*wil
= s
->private;
1777 rc
= kstrtoint_from_user(buf
, len
, 0, &val
);
1779 wil_err(wil
, "Invalid argument\n");
1783 /* default resolution */
1785 if (val
&& (val
< 50 || val
> 1000)) {
1786 wil_err(wil
, "Invalid resolution %d\n", val
);
1791 if (wil
->tx_latency
== enable
)
1794 wil_info(wil
, "%s TX latency measurements (resolution %dusec)\n",
1795 enable
? "Enabling" : "Disabling", val
);
1798 size_t sz
= sizeof(u64
) * WIL_NUM_LATENCY_BINS
;
1800 wil
->tx_latency_res
= val
;
1801 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1802 struct wil_sta_info
*sta
= &wil
->sta
[i
];
1804 kfree(sta
->tx_latency_bins
);
1805 sta
->tx_latency_bins
= kzalloc(sz
, GFP_KERNEL
);
1806 if (!sta
->tx_latency_bins
)
1808 sta
->stats
.tx_latency_min_us
= U32_MAX
;
1809 sta
->stats
.tx_latency_max_us
= 0;
1810 sta
->stats
.tx_latency_total_us
= 0;
1813 wil
->tx_latency
= enable
;
1818 static const struct file_operations fops_tx_latency
= {
1819 .open
= wil_tx_latency_seq_open
,
1820 .release
= single_release
,
1822 .write
= wil_tx_latency_write
,
1823 .llseek
= seq_lseek
,
1826 static void wil_link_stats_print_basic(struct wil6210_vif
*vif
,
1828 struct wmi_link_stats_basic
*basic
)
1832 if (basic
->per_average
!= 0xff)
1833 snprintf(per
, sizeof(per
), "%d%%", basic
->per_average
);
1835 seq_printf(s
, "CID %d {\n"
1836 "\tTxMCS %s TxTpt %d\n"
1837 "\tGoodput(rx:tx) %d:%d\n"
1838 "\tRxBcastFrames %d\n"
1839 "\tRSSI %d SQI %d SNR %d PER %s\n"
1840 "\tRx RFC %d Ant num %d\n"
1841 "\tSectors(rx:tx) my %d:%d peer %d:%d\n"
1844 WIL_EXTENDED_MCS_CHECK(basic
->bf_mcs
),
1845 le32_to_cpu(basic
->tx_tpt
),
1846 le32_to_cpu(basic
->rx_goodput
),
1847 le32_to_cpu(basic
->tx_goodput
),
1848 le32_to_cpu(basic
->rx_bcast_frames
),
1849 basic
->rssi
, basic
->sqi
, basic
->snr
, per
,
1850 basic
->selected_rfc
, basic
->rx_effective_ant_num
,
1851 basic
->my_rx_sector
, basic
->my_tx_sector
,
1852 basic
->other_rx_sector
, basic
->other_tx_sector
);
1855 static void wil_link_stats_print_global(struct wil6210_priv
*wil
,
1857 struct wmi_link_stats_global
*global
)
1859 seq_printf(s
, "Frames(rx:tx) %d:%d\n"
1860 "BA Frames(rx:tx) %d:%d\n"
1862 "Rx Errors (MIC:CRC) %d:%d\n"
1863 "Tx Errors (no ack) %d\n",
1864 le32_to_cpu(global
->rx_frames
),
1865 le32_to_cpu(global
->tx_frames
),
1866 le32_to_cpu(global
->rx_ba_frames
),
1867 le32_to_cpu(global
->tx_ba_frames
),
1868 le32_to_cpu(global
->tx_beacons
),
1869 le32_to_cpu(global
->rx_mic_errors
),
1870 le32_to_cpu(global
->rx_crc_errors
),
1871 le32_to_cpu(global
->tx_fail_no_ack
));
1874 static void wil_link_stats_debugfs_show_vif(struct wil6210_vif
*vif
,
1877 struct wil6210_priv
*wil
= vif_to_wil(vif
);
1878 struct wmi_link_stats_basic
*stats
;
1881 if (!vif
->fw_stats_ready
) {
1882 seq_puts(s
, "no statistics\n");
1886 seq_printf(s
, "TSF %lld\n", vif
->fw_stats_tsf
);
1887 for (i
= 0; i
< wil
->max_assoc_sta
; i
++) {
1888 if (wil
->sta
[i
].status
== wil_sta_unused
)
1890 if (wil
->sta
[i
].mid
!= vif
->mid
)
1893 stats
= &wil
->sta
[i
].fw_stats_basic
;
1894 wil_link_stats_print_basic(vif
, s
, stats
);
1898 static int wil_link_stats_debugfs_show(struct seq_file
*s
, void *data
)
1900 struct wil6210_priv
*wil
= s
->private;
1901 struct wil6210_vif
*vif
;
1904 rc
= mutex_lock_interruptible(&wil
->vif_mutex
);
1908 /* iterate over all MIDs and show per-cid statistics. Then show the
1911 for (i
= 0; i
< GET_MAX_VIFS(wil
); i
++) {
1914 seq_printf(s
, "MID %d ", i
);
1916 seq_puts(s
, "unused\n");
1920 wil_link_stats_debugfs_show_vif(vif
, s
);
1923 mutex_unlock(&wil
->vif_mutex
);
1928 static int wil_link_stats_seq_open(struct inode
*inode
, struct file
*file
)
1930 return single_open(file
, wil_link_stats_debugfs_show
, inode
->i_private
);
1933 static ssize_t
wil_link_stats_write(struct file
*file
, const char __user
*buf
,
1934 size_t len
, loff_t
*ppos
)
1936 struct seq_file
*s
= file
->private_data
;
1937 struct wil6210_priv
*wil
= s
->private;
1938 int cid
, interval
, rc
, i
;
1939 struct wil6210_vif
*vif
;
1940 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
1945 rc
= simple_write_to_buffer(kbuf
, len
, ppos
, buf
, len
);
1948 return rc
>= 0 ? -EIO
: rc
;
1952 /* specify cid (use -1 for all cids) and snapshot interval in ms */
1953 rc
= sscanf(kbuf
, "%d %d", &cid
, &interval
);
1957 if (rc
< 2 || interval
< 0)
1960 wil_info(wil
, "request link statistics, cid %d interval %d\n",
1963 rc
= mutex_lock_interruptible(&wil
->vif_mutex
);
1967 for (i
= 0; i
< GET_MAX_VIFS(wil
); i
++) {
1972 rc
= wmi_link_stats_cfg(vif
, WMI_LINK_STATS_TYPE_BASIC
,
1973 (cid
== -1 ? 0xff : cid
), interval
);
1975 wil_err(wil
, "link statistics failed for mid %d\n", i
);
1977 mutex_unlock(&wil
->vif_mutex
);
1982 static const struct file_operations fops_link_stats
= {
1983 .open
= wil_link_stats_seq_open
,
1984 .release
= single_release
,
1986 .write
= wil_link_stats_write
,
1987 .llseek
= seq_lseek
,
1991 wil_link_stats_global_debugfs_show(struct seq_file
*s
, void *data
)
1993 struct wil6210_priv
*wil
= s
->private;
1995 if (!wil
->fw_stats_global
.ready
)
1998 seq_printf(s
, "TSF %lld\n", wil
->fw_stats_global
.tsf
);
1999 wil_link_stats_print_global(wil
, s
, &wil
->fw_stats_global
.stats
);
2005 wil_link_stats_global_seq_open(struct inode
*inode
, struct file
*file
)
2007 return single_open(file
, wil_link_stats_global_debugfs_show
,
2012 wil_link_stats_global_write(struct file
*file
, const char __user
*buf
,
2013 size_t len
, loff_t
*ppos
)
2015 struct seq_file
*s
= file
->private_data
;
2016 struct wil6210_priv
*wil
= s
->private;
2018 struct wil6210_vif
*vif
= ndev_to_vif(wil
->main_ndev
);
2020 /* specify snapshot interval in ms */
2021 rc
= kstrtoint_from_user(buf
, len
, 0, &interval
);
2022 if (rc
|| interval
< 0) {
2023 wil_err(wil
, "Invalid argument\n");
2027 wil_info(wil
, "request global link stats, interval %d\n", interval
);
2029 rc
= wmi_link_stats_cfg(vif
, WMI_LINK_STATS_TYPE_GLOBAL
, 0, interval
);
2031 wil_err(wil
, "global link stats failed %d\n", rc
);
2033 return rc
? rc
: len
;
2036 static const struct file_operations fops_link_stats_global
= {
2037 .open
= wil_link_stats_global_seq_open
,
2038 .release
= single_release
,
2040 .write
= wil_link_stats_global_write
,
2041 .llseek
= seq_lseek
,
2044 static ssize_t
wil_read_file_led_cfg(struct file
*file
, char __user
*user_buf
,
2045 size_t count
, loff_t
*ppos
)
2050 n
= snprintf(buf
, sizeof(buf
),
2051 "led_id is set to %d, echo 1 to enable, 0 to disable\n",
2054 n
= min_t(int, n
, sizeof(buf
));
2056 return simple_read_from_buffer(user_buf
, count
, ppos
,
2060 static ssize_t
wil_write_file_led_cfg(struct file
*file
,
2061 const char __user
*buf_
,
2062 size_t count
, loff_t
*ppos
)
2064 struct wil6210_priv
*wil
= file
->private_data
;
2068 rc
= kstrtoint_from_user(buf_
, count
, 0, &val
);
2070 wil_err(wil
, "Invalid argument\n");
2074 wil_info(wil
, "%s led %d\n", val
? "Enabling" : "Disabling", led_id
);
2075 rc
= wmi_led_cfg(wil
, val
);
2077 wil_info(wil
, "%s led %d failed\n",
2078 val
? "Enabling" : "Disabling", led_id
);
2085 static const struct file_operations fops_led_cfg
= {
2086 .read
= wil_read_file_led_cfg
,
2087 .write
= wil_write_file_led_cfg
,
2088 .open
= simple_open
,
2091 /* led_blink_time, write:
2092 * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
2094 static ssize_t
wil_write_led_blink_time(struct file
*file
,
2095 const char __user
*buf
,
2096 size_t len
, loff_t
*ppos
)
2099 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
2104 rc
= simple_write_to_buffer(kbuf
, len
, ppos
, buf
, len
);
2107 return rc
>= 0 ? -EIO
: rc
;
2111 rc
= sscanf(kbuf
, "%d %d %d %d %d %d",
2112 &led_blink_time
[WIL_LED_TIME_SLOW
].on_ms
,
2113 &led_blink_time
[WIL_LED_TIME_SLOW
].off_ms
,
2114 &led_blink_time
[WIL_LED_TIME_MED
].on_ms
,
2115 &led_blink_time
[WIL_LED_TIME_MED
].off_ms
,
2116 &led_blink_time
[WIL_LED_TIME_FAST
].on_ms
,
2117 &led_blink_time
[WIL_LED_TIME_FAST
].off_ms
);
2128 static ssize_t
wil_read_led_blink_time(struct file
*file
, char __user
*user_buf
,
2129 size_t count
, loff_t
*ppos
)
2131 static char text
[400];
2133 snprintf(text
, sizeof(text
),
2134 "To set led blink on/off time variables write:\n"
2135 "<blink_on_slow> <blink_off_slow> <blink_on_med> "
2136 "<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
2137 "The current values are:\n"
2138 "%d %d %d %d %d %d\n",
2139 led_blink_time
[WIL_LED_TIME_SLOW
].on_ms
,
2140 led_blink_time
[WIL_LED_TIME_SLOW
].off_ms
,
2141 led_blink_time
[WIL_LED_TIME_MED
].on_ms
,
2142 led_blink_time
[WIL_LED_TIME_MED
].off_ms
,
2143 led_blink_time
[WIL_LED_TIME_FAST
].on_ms
,
2144 led_blink_time
[WIL_LED_TIME_FAST
].off_ms
);
2146 return simple_read_from_buffer(user_buf
, count
, ppos
, text
,
2150 static const struct file_operations fops_led_blink_time
= {
2151 .read
= wil_read_led_blink_time
,
2152 .write
= wil_write_led_blink_time
,
2153 .open
= simple_open
,
2156 /*---------FW capabilities------------*/
2157 static int fw_capabilities_show(struct seq_file
*s
, void *data
)
2159 struct wil6210_priv
*wil
= s
->private;
2161 seq_printf(s
, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX
,
2162 wil
->fw_capabilities
);
2166 DEFINE_SHOW_ATTRIBUTE(fw_capabilities
);
2168 /*---------FW version------------*/
2169 static int fw_version_show(struct seq_file
*s
, void *data
)
2171 struct wil6210_priv
*wil
= s
->private;
2173 if (wil
->fw_version
[0])
2174 seq_printf(s
, "%s\n", wil
->fw_version
);
2176 seq_puts(s
, "N/A\n");
2180 DEFINE_SHOW_ATTRIBUTE(fw_version
);
2182 /*---------suspend_stats---------*/
2183 static ssize_t
wil_write_suspend_stats(struct file
*file
,
2184 const char __user
*buf
,
2185 size_t len
, loff_t
*ppos
)
2187 struct wil6210_priv
*wil
= file
->private_data
;
2189 memset(&wil
->suspend_stats
, 0, sizeof(wil
->suspend_stats
));
2194 static ssize_t
wil_read_suspend_stats(struct file
*file
,
2195 char __user
*user_buf
,
2196 size_t count
, loff_t
*ppos
)
2198 struct wil6210_priv
*wil
= file
->private_data
;
2200 int n
, ret
, text_size
= 500;
2202 text
= kmalloc(text_size
, GFP_KERNEL
);
2206 n
= snprintf(text
, text_size
,
2207 "Radio on suspend statistics:\n"
2208 "successful suspends:%ld failed suspends:%ld\n"
2209 "successful resumes:%ld failed resumes:%ld\n"
2210 "rejected by device:%ld\n"
2211 "Radio off suspend statistics:\n"
2212 "successful suspends:%ld failed suspends:%ld\n"
2213 "successful resumes:%ld failed resumes:%ld\n"
2214 "General statistics:\n"
2215 "rejected by host:%ld\n",
2216 wil
->suspend_stats
.r_on
.successful_suspends
,
2217 wil
->suspend_stats
.r_on
.failed_suspends
,
2218 wil
->suspend_stats
.r_on
.successful_resumes
,
2219 wil
->suspend_stats
.r_on
.failed_resumes
,
2220 wil
->suspend_stats
.rejected_by_device
,
2221 wil
->suspend_stats
.r_off
.successful_suspends
,
2222 wil
->suspend_stats
.r_off
.failed_suspends
,
2223 wil
->suspend_stats
.r_off
.successful_resumes
,
2224 wil
->suspend_stats
.r_off
.failed_resumes
,
2225 wil
->suspend_stats
.rejected_by_host
);
2227 n
= min_t(int, n
, text_size
);
2229 ret
= simple_read_from_buffer(user_buf
, count
, ppos
, text
, n
);
2236 static const struct file_operations fops_suspend_stats
= {
2237 .read
= wil_read_suspend_stats
,
2238 .write
= wil_write_suspend_stats
,
2239 .open
= simple_open
,
2242 /*---------compressed_rx_status---------*/
2243 static ssize_t
wil_compressed_rx_status_write(struct file
*file
,
2244 const char __user
*buf
,
2245 size_t len
, loff_t
*ppos
)
2247 struct seq_file
*s
= file
->private_data
;
2248 struct wil6210_priv
*wil
= s
->private;
2249 int compressed_rx_status
;
2252 rc
= kstrtoint_from_user(buf
, len
, 0, &compressed_rx_status
);
2254 wil_err(wil
, "Invalid argument\n");
2258 if (wil_has_active_ifaces(wil
, true, false)) {
2259 wil_err(wil
, "cannot change edma config after iface is up\n");
2263 wil_info(wil
, "%sable compressed_rx_status\n",
2264 compressed_rx_status
? "En" : "Dis");
2266 wil
->use_compressed_rx_status
= compressed_rx_status
;
2272 wil_compressed_rx_status_show(struct seq_file
*s
, void *data
)
2274 struct wil6210_priv
*wil
= s
->private;
2276 seq_printf(s
, "%d\n", wil
->use_compressed_rx_status
);
2282 wil_compressed_rx_status_seq_open(struct inode
*inode
, struct file
*file
)
2284 return single_open(file
, wil_compressed_rx_status_show
,
2288 static const struct file_operations fops_compressed_rx_status
= {
2289 .open
= wil_compressed_rx_status_seq_open
,
2290 .release
= single_release
,
2292 .write
= wil_compressed_rx_status_write
,
2293 .llseek
= seq_lseek
,
2296 /*----------------*/
2297 static void wil6210_debugfs_init_blobs(struct wil6210_priv
*wil
,
2303 for (i
= 0; i
< ARRAY_SIZE(fw_mapping
); i
++) {
2304 struct wil_blob_wrapper
*wil_blob
= &wil
->blobs
[i
];
2305 struct debugfs_blob_wrapper
*blob
= &wil_blob
->blob
;
2306 const struct fw_map
*map
= &fw_mapping
[i
];
2311 wil_blob
->wil
= wil
;
2312 blob
->data
= (void * __force
)wil
->csr
+ HOSTADDR(map
->host
);
2313 blob
->size
= map
->to
- map
->from
;
2314 snprintf(name
, sizeof(name
), "blob_%s", map
->name
);
2315 wil_debugfs_create_ioblob(name
, 0444, dbg
, wil_blob
);
2320 static const struct {
2323 const struct file_operations
*fops
;
2325 {"mbox", 0444, &mbox_fops
},
2326 {"rings", 0444, &ring_fops
},
2327 {"stations", 0444, &sta_fops
},
2328 {"mids", 0444, &mids_fops
},
2329 {"desc", 0444, &txdesc_fops
},
2330 {"bf", 0444, &bf_fops
},
2331 {"mem_val", 0644, &memread_fops
},
2332 {"rxon", 0244, &fops_rxon
},
2333 {"tx_mgmt", 0244, &fops_txmgmt
},
2334 {"wmi_send", 0244, &fops_wmi
},
2335 {"back", 0644, &fops_back
},
2336 {"pmccfg", 0644, &fops_pmccfg
},
2337 {"pmcdata", 0444, &fops_pmcdata
},
2338 {"pmcring", 0444, &fops_pmcring
},
2339 {"temp", 0444, &temp_fops
},
2340 {"link", 0444, &link_fops
},
2341 {"info", 0444, &info_fops
},
2342 {"recovery", 0644, &fops_recovery
},
2343 {"led_cfg", 0644, &fops_led_cfg
},
2344 {"led_blink_time", 0644, &fops_led_blink_time
},
2345 {"fw_capabilities", 0444, &fw_capabilities_fops
},
2346 {"fw_version", 0444, &fw_version_fops
},
2347 {"suspend_stats", 0644, &fops_suspend_stats
},
2348 {"compressed_rx_status", 0644, &fops_compressed_rx_status
},
2349 {"srings", 0444, &srings_fops
},
2350 {"status_msg", 0444, &status_msg_fops
},
2351 {"rx_buff_mgmt", 0444, &rx_buff_mgmt_fops
},
2352 {"tx_latency", 0644, &fops_tx_latency
},
2353 {"link_stats", 0644, &fops_link_stats
},
2354 {"link_stats_global", 0644, &fops_link_stats_global
},
2355 {"rbufcap", 0244, &fops_rbufcap
},
2358 static void wil6210_debugfs_init_files(struct wil6210_priv
*wil
,
2363 for (i
= 0; i
< ARRAY_SIZE(dbg_files
); i
++)
2364 debugfs_create_file(dbg_files
[i
].name
, dbg_files
[i
].mode
, dbg
,
2365 wil
, dbg_files
[i
].fops
);
2368 /* interrupt control blocks */
2369 static const struct {
2373 {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR
)},
2374 {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR
)},
2375 {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR
)},
2376 {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR
)},
2379 static void wil6210_debugfs_init_isr(struct wil6210_priv
*wil
,
2384 for (i
= 0; i
< ARRAY_SIZE(dbg_icr
); i
++)
2385 wil6210_debugfs_create_ISR(wil
, dbg_icr
[i
].name
, dbg
,
2386 dbg_icr
[i
].icr_off
);
2389 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
2390 offsetof(struct wil6210_priv, name), type}
2392 /* fields in struct wil6210_priv */
2393 static const struct dbg_off dbg_wil_off
[] = {
2394 WIL_FIELD(status
[0], 0644, doff_ulong
),
2395 WIL_FIELD(hw_version
, 0444, doff_x32
),
2396 WIL_FIELD(recovery_count
, 0444, doff_u32
),
2397 WIL_FIELD(discovery_mode
, 0644, doff_u8
),
2398 WIL_FIELD(chip_revision
, 0444, doff_u8
),
2399 WIL_FIELD(abft_len
, 0644, doff_u8
),
2400 WIL_FIELD(wakeup_trigger
, 0644, doff_u8
),
2401 WIL_FIELD(ring_idle_trsh
, 0644, doff_u32
),
2402 WIL_FIELD(num_rx_status_rings
, 0644, doff_u8
),
2403 WIL_FIELD(rx_status_ring_order
, 0644, doff_u32
),
2404 WIL_FIELD(tx_status_ring_order
, 0644, doff_u32
),
2405 WIL_FIELD(rx_buff_id_count
, 0644, doff_u32
),
2406 WIL_FIELD(amsdu_en
, 0644, doff_u8
),
2410 static const struct dbg_off dbg_wil_regs
[] = {
2411 {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0
),
2413 {"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1
), doff_io32
},
2414 {"RGF_USER_USAGE_2", 0444, HOSTADDR(RGF_USER_USAGE_2
), doff_io32
},
2418 /* static parameters */
2419 static const struct dbg_off dbg_statics
[] = {
2420 {"desc_index", 0644, (ulong
)&dbg_txdesc_index
, doff_u32
},
2421 {"ring_index", 0644, (ulong
)&dbg_ring_index
, doff_u32
},
2422 {"mem_addr", 0644, (ulong
)&mem_addr
, doff_u32
},
2423 {"led_polarity", 0644, (ulong
)&led_polarity
, doff_u8
},
2424 {"status_index", 0644, (ulong
)&dbg_status_msg_index
, doff_u32
},
2425 {"sring_index", 0644, (ulong
)&dbg_sring_index
, doff_u32
},
2426 {"drop_if_ring_full", 0644, (ulong
)&drop_if_ring_full
, doff_u8
},
2430 static const int dbg_off_count
= 4 * (ARRAY_SIZE(isr_off
) - 1) +
2431 ARRAY_SIZE(dbg_wil_regs
) - 1 +
2432 ARRAY_SIZE(pseudo_isr_off
) - 1 +
2433 ARRAY_SIZE(lgc_itr_cnt_off
) - 1 +
2434 ARRAY_SIZE(tx_itr_cnt_off
) - 1 +
2435 ARRAY_SIZE(rx_itr_cnt_off
) - 1;
2437 int wil6210_debugfs_init(struct wil6210_priv
*wil
)
2439 struct dentry
*dbg
= wil
->debug
= debugfs_create_dir(WIL_NAME
,
2440 wil_to_wiphy(wil
)->debugfsdir
);
2441 if (IS_ERR_OR_NULL(dbg
))
2444 wil
->dbg_data
.data_arr
= kcalloc(dbg_off_count
,
2445 sizeof(struct wil_debugfs_iomem_data
),
2447 if (!wil
->dbg_data
.data_arr
) {
2448 debugfs_remove_recursive(dbg
);
2453 wil
->dbg_data
.iomem_data_count
= 0;
2457 wil6210_debugfs_init_files(wil
, dbg
);
2458 wil6210_debugfs_init_isr(wil
, dbg
);
2459 wil6210_debugfs_init_blobs(wil
, dbg
);
2460 wil6210_debugfs_init_offset(wil
, dbg
, wil
, dbg_wil_off
);
2461 wil6210_debugfs_init_offset(wil
, dbg
, (void * __force
)wil
->csr
,
2463 wil6210_debugfs_init_offset(wil
, dbg
, NULL
, dbg_statics
);
2465 wil6210_debugfs_create_pseudo_ISR(wil
, dbg
);
2467 wil6210_debugfs_create_ITR_CNT(wil
, dbg
);
2472 void wil6210_debugfs_remove(struct wil6210_priv
*wil
)
2476 debugfs_remove_recursive(wil
->debug
);
2479 kfree(wil
->dbg_data
.data_arr
);
2480 for (i
= 0; i
< wil
->max_assoc_sta
; i
++)
2481 kfree(wil
->sta
[i
].tx_latency_bins
);
2483 /* free pmc memory without sending command to fw, as it will
2484 * be reset on the way down anyway
2486 wil_pmc_free(wil
, false);