2 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/module.h>
18 #include <linux/debugfs.h>
19 #include <linux/seq_file.h>
20 #include <linux/pci.h>
21 #include <linux/rtnetlink.h>
22 #include <linux/power_supply.h>
28 /* Nasty hack. Better have per device instances */
30 static u32 dbg_txdesc_index
;
31 static u32 dbg_vring_index
; /* 24+ for Rx, 0..23 for Tx */
46 enum dbg_off_type type
;
49 static void wil_print_vring(struct seq_file
*s
, struct wil6210_priv
*wil
,
50 const char *name
, struct vring
*vring
,
53 void __iomem
*x
= wmi_addr(wil
, vring
->hwtail
);
56 seq_printf(s
, "VRING %s = {\n", name
);
57 seq_printf(s
, " pa = %pad\n", &vring
->pa
);
58 seq_printf(s
, " va = 0x%p\n", vring
->va
);
59 seq_printf(s
, " size = %d\n", vring
->size
);
60 seq_printf(s
, " swtail = %d\n", vring
->swtail
);
61 seq_printf(s
, " swhead = %d\n", vring
->swhead
);
62 seq_printf(s
, " hwtail = [0x%08x] -> ", vring
->hwtail
);
65 seq_printf(s
, "0x%08x = %d\n", v
, v
);
70 if (vring
->va
&& (vring
->size
<= (1 << WIL_RING_SIZE_ORDER_MAX
))) {
73 for (i
= 0; i
< vring
->size
; i
++) {
74 volatile struct vring_tx_desc
*d
= &vring
->va
[i
].tx
;
76 if ((i
% 128) == 0 && (i
!= 0))
78 seq_printf(s
, "%c", (d
->dma
.status
& BIT(0)) ?
79 _s
: (vring
->ctx
[i
].skb
? _h
: 'h'));
86 static int wil_vring_debugfs_show(struct seq_file
*s
, void *data
)
89 struct wil6210_priv
*wil
= s
->private;
91 wil_print_vring(s
, wil
, "rx", &wil
->vring_rx
, 'S', '_');
93 for (i
= 0; i
< ARRAY_SIZE(wil
->vring_tx
); i
++) {
94 struct vring
*vring
= &wil
->vring_tx
[i
];
95 struct vring_tx_data
*txdata
= &wil
->vring_tx_data
[i
];
98 int cid
= wil
->vring2cid_tid
[i
][0];
99 int tid
= wil
->vring2cid_tid
[i
][1];
100 u32 swhead
= vring
->swhead
;
101 u32 swtail
= vring
->swtail
;
102 int used
= (vring
->size
+ swhead
- swtail
)
104 int avail
= vring
->size
- used
- 1;
107 /* performance monitoring */
108 cycles_t now
= get_cycles();
109 uint64_t idle
= txdata
->idle
* 100;
110 uint64_t total
= now
- txdata
->begin
;
114 snprintf(sidle
, sizeof(sidle
), "%3d%%",
117 snprintf(sidle
, sizeof(sidle
), "N/A");
122 snprintf(name
, sizeof(name
), "tx_%2d", i
);
124 if (cid
< WIL6210_MAX_CID
)
126 "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
127 wil
->sta
[cid
].addr
, cid
, tid
,
128 txdata
->dot1x_open
? "+" : "-",
131 txdata
->agg_amsdu
? "+" : "-",
135 "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
136 txdata
->dot1x_open
? "+" : "-",
139 wil_print_vring(s
, wil
, name
, vring
, '_', 'H');
146 static int wil_vring_seq_open(struct inode
*inode
, struct file
*file
)
148 return single_open(file
, wil_vring_debugfs_show
, inode
->i_private
);
151 static const struct file_operations fops_vring
= {
152 .open
= wil_vring_seq_open
,
153 .release
= single_release
,
158 static void wil_seq_hexdump(struct seq_file
*s
, void *p
, int len
,
161 seq_hex_dump(s
, prefix
, DUMP_PREFIX_NONE
, 16, 1, p
, len
, false);
164 static void wil_print_ring(struct seq_file
*s
, const char *prefix
,
167 struct wil6210_priv
*wil
= s
->private;
168 struct wil6210_mbox_ring r
;
174 wil_memcpy_fromio_32(&r
, off
, sizeof(r
));
175 wil_mbox_ring_le2cpus(&r
);
177 * we just read memory block from NIC. This memory may be
178 * garbage. Check validity before using it.
180 rsize
= r
.size
/ sizeof(struct wil6210_mbox_ring_desc
);
182 seq_printf(s
, "ring %s = {\n", prefix
);
183 seq_printf(s
, " base = 0x%08x\n", r
.base
);
184 seq_printf(s
, " size = 0x%04x bytes -> %d entries\n", r
.size
, rsize
);
185 seq_printf(s
, " tail = 0x%08x\n", r
.tail
);
186 seq_printf(s
, " head = 0x%08x\n", r
.head
);
187 seq_printf(s
, " entry size = %d\n", r
.entry_size
);
189 if (r
.size
% sizeof(struct wil6210_mbox_ring_desc
)) {
190 seq_printf(s
, " ??? size is not multiple of %zd, garbage?\n",
191 sizeof(struct wil6210_mbox_ring_desc
));
195 if (!wmi_addr(wil
, r
.base
) ||
196 !wmi_addr(wil
, r
.tail
) ||
197 !wmi_addr(wil
, r
.head
)) {
198 seq_puts(s
, " ??? pointers are garbage?\n");
202 for (i
= 0; i
< rsize
; i
++) {
203 struct wil6210_mbox_ring_desc d
;
204 struct wil6210_mbox_hdr hdr
;
205 size_t delta
= i
* sizeof(d
);
206 void __iomem
*x
= wil
->csr
+ HOSTADDR(r
.base
) + delta
;
208 wil_memcpy_fromio_32(&d
, x
, sizeof(d
));
210 seq_printf(s
, " [%2x] %s %s%s 0x%08x", i
,
212 (r
.tail
- r
.base
== delta
) ? "t" : " ",
213 (r
.head
- r
.base
== delta
) ? "h" : " ",
214 le32_to_cpu(d
.addr
));
215 if (0 == wmi_read_hdr(wil
, d
.addr
, &hdr
)) {
216 u16 len
= le16_to_cpu(hdr
.len
);
218 seq_printf(s
, " -> %04x %04x %04x %02x\n",
219 le16_to_cpu(hdr
.seq
), len
,
220 le16_to_cpu(hdr
.type
), hdr
.flags
);
221 if (len
<= MAX_MBOXITEM_SIZE
) {
222 unsigned char databuf
[MAX_MBOXITEM_SIZE
];
223 void __iomem
*src
= wmi_buffer(wil
, d
.addr
) +
224 sizeof(struct wil6210_mbox_hdr
);
226 * No need to check @src for validity -
227 * we already validated @d.addr while
230 wil_memcpy_fromio_32(databuf
, src
, len
);
231 wil_seq_hexdump(s
, databuf
, len
, " : ");
239 wil_halp_unvote(wil
);
242 static int wil_mbox_debugfs_show(struct seq_file
*s
, void *data
)
244 struct wil6210_priv
*wil
= s
->private;
247 ret
= wil_pm_runtime_get(wil
);
251 wil_print_ring(s
, "tx", wil
->csr
+ HOST_MBOX
+
252 offsetof(struct wil6210_mbox_ctl
, tx
));
253 wil_print_ring(s
, "rx", wil
->csr
+ HOST_MBOX
+
254 offsetof(struct wil6210_mbox_ctl
, rx
));
256 wil_pm_runtime_put(wil
);
261 static int wil_mbox_seq_open(struct inode
*inode
, struct file
*file
)
263 return single_open(file
, wil_mbox_debugfs_show
, inode
->i_private
);
266 static const struct file_operations fops_mbox
= {
267 .open
= wil_mbox_seq_open
,
268 .release
= single_release
,
273 static int wil_debugfs_iomem_x32_set(void *data
, u64 val
)
275 struct wil_debugfs_iomem_data
*d
= (struct
276 wil_debugfs_iomem_data
*)data
;
277 struct wil6210_priv
*wil
= d
->wil
;
280 ret
= wil_pm_runtime_get(wil
);
284 writel(val
, (void __iomem
*)d
->offset
);
285 wmb(); /* make sure write propagated to HW */
287 wil_pm_runtime_put(wil
);
292 static int wil_debugfs_iomem_x32_get(void *data
, u64
*val
)
294 struct wil_debugfs_iomem_data
*d
= (struct
295 wil_debugfs_iomem_data
*)data
;
296 struct wil6210_priv
*wil
= d
->wil
;
299 ret
= wil_pm_runtime_get(wil
);
303 *val
= readl((void __iomem
*)d
->offset
);
305 wil_pm_runtime_put(wil
);
310 DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32
, wil_debugfs_iomem_x32_get
,
311 wil_debugfs_iomem_x32_set
, "0x%08llx\n");
313 static struct dentry
*wil_debugfs_create_iomem_x32(const char *name
,
315 struct dentry
*parent
,
317 struct wil6210_priv
*wil
)
320 struct wil_debugfs_iomem_data
*data
= &wil
->dbg_data
.data_arr
[
321 wil
->dbg_data
.iomem_data_count
];
324 data
->offset
= value
;
326 file
= debugfs_create_file(name
, mode
, parent
, data
, &fops_iomem_x32
);
327 if (!IS_ERR_OR_NULL(file
))
328 wil
->dbg_data
.iomem_data_count
++;
333 static int wil_debugfs_ulong_set(void *data
, u64 val
)
335 *(ulong
*)data
= val
;
339 static int wil_debugfs_ulong_get(void *data
, u64
*val
)
341 *val
= *(ulong
*)data
;
345 DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong
, wil_debugfs_ulong_get
,
346 wil_debugfs_ulong_set
, "0x%llx\n");
348 static struct dentry
*wil_debugfs_create_ulong(const char *name
, umode_t mode
,
349 struct dentry
*parent
,
352 return debugfs_create_file(name
, mode
, parent
, value
, &wil_fops_ulong
);
356 * wil6210_debugfs_init_offset - create set of debugfs files
357 * @wil - driver's context, used for printing
358 * @dbg - directory on the debugfs, where files will be created
359 * @base - base address used in address calculation
360 * @tbl - table with file descriptions. Should be terminated with empty element.
362 * Creates files accordingly to the @tbl.
364 static void wil6210_debugfs_init_offset(struct wil6210_priv
*wil
,
365 struct dentry
*dbg
, void *base
,
366 const struct dbg_off
* const tbl
)
370 for (i
= 0; tbl
[i
].name
; i
++) {
373 switch (tbl
[i
].type
) {
375 f
= debugfs_create_u32(tbl
[i
].name
, tbl
[i
].mode
, dbg
,
379 f
= debugfs_create_x32(tbl
[i
].name
, tbl
[i
].mode
, dbg
,
383 f
= wil_debugfs_create_ulong(tbl
[i
].name
, tbl
[i
].mode
,
384 dbg
, base
+ tbl
[i
].off
);
387 f
= wil_debugfs_create_iomem_x32(tbl
[i
].name
,
393 f
= debugfs_create_u8(tbl
[i
].name
, tbl
[i
].mode
, dbg
,
397 f
= ERR_PTR(-EINVAL
);
399 if (IS_ERR_OR_NULL(f
))
400 wil_err(wil
, "Create file \"%s\": err %ld\n",
401 tbl
[i
].name
, PTR_ERR(f
));
405 static const struct dbg_off isr_off
[] = {
406 {"ICC", 0644, offsetof(struct RGF_ICR
, ICC
), doff_io32
},
407 {"ICR", 0644, offsetof(struct RGF_ICR
, ICR
), doff_io32
},
408 {"ICM", 0644, offsetof(struct RGF_ICR
, ICM
), doff_io32
},
409 {"ICS", 0244, offsetof(struct RGF_ICR
, ICS
), doff_io32
},
410 {"IMV", 0644, offsetof(struct RGF_ICR
, IMV
), doff_io32
},
411 {"IMS", 0244, offsetof(struct RGF_ICR
, IMS
), doff_io32
},
412 {"IMC", 0244, offsetof(struct RGF_ICR
, IMC
), doff_io32
},
416 static int wil6210_debugfs_create_ISR(struct wil6210_priv
*wil
,
418 struct dentry
*parent
, u32 off
)
420 struct dentry
*d
= debugfs_create_dir(name
, parent
);
422 if (IS_ERR_OR_NULL(d
))
425 wil6210_debugfs_init_offset(wil
, d
, (void * __force
)wil
->csr
+ off
,
431 static const struct dbg_off pseudo_isr_off
[] = {
432 {"CAUSE", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE
), doff_io32
},
433 {"MASK_SW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW
), doff_io32
},
434 {"MASK_FW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW
), doff_io32
},
438 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv
*wil
,
439 struct dentry
*parent
)
441 struct dentry
*d
= debugfs_create_dir("PSEUDO_ISR", parent
);
443 if (IS_ERR_OR_NULL(d
))
446 wil6210_debugfs_init_offset(wil
, d
, (void * __force
)wil
->csr
,
452 static const struct dbg_off lgc_itr_cnt_off
[] = {
453 {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_CNT_TRSH
), doff_io32
},
454 {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_CNT_DATA
), doff_io32
},
455 {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_CNT_CRL
), doff_io32
},
459 static const struct dbg_off tx_itr_cnt_off
[] = {
460 {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH
),
462 {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA
),
464 {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL
),
466 {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH
),
468 {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA
),
470 {"IDL_CTL", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL
),
475 static const struct dbg_off rx_itr_cnt_off
[] = {
476 {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH
),
478 {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA
),
480 {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL
),
482 {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH
),
484 {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA
),
486 {"IDL_CTL", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL
),
491 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv
*wil
,
492 struct dentry
*parent
)
494 struct dentry
*d
, *dtx
, *drx
;
496 d
= debugfs_create_dir("ITR_CNT", parent
);
497 if (IS_ERR_OR_NULL(d
))
500 dtx
= debugfs_create_dir("TX", d
);
501 drx
= debugfs_create_dir("RX", d
);
502 if (IS_ERR_OR_NULL(dtx
) || IS_ERR_OR_NULL(drx
))
505 wil6210_debugfs_init_offset(wil
, d
, (void * __force
)wil
->csr
,
508 wil6210_debugfs_init_offset(wil
, dtx
, (void * __force
)wil
->csr
,
511 wil6210_debugfs_init_offset(wil
, drx
, (void * __force
)wil
->csr
,
516 static int wil_memread_debugfs_show(struct seq_file
*s
, void *data
)
518 struct wil6210_priv
*wil
= s
->private;
522 ret
= wil_pm_runtime_get(wil
);
526 a
= wmi_buffer(wil
, cpu_to_le32(mem_addr
));
529 seq_printf(s
, "[0x%08x] = 0x%08x\n", mem_addr
, readl(a
));
531 seq_printf(s
, "[0x%08x] = INVALID\n", mem_addr
);
533 wil_pm_runtime_put(wil
);
538 static int wil_memread_seq_open(struct inode
*inode
, struct file
*file
)
540 return single_open(file
, wil_memread_debugfs_show
, inode
->i_private
);
543 static const struct file_operations fops_memread
= {
544 .open
= wil_memread_seq_open
,
545 .release
= single_release
,
550 static ssize_t
wil_read_file_ioblob(struct file
*file
, char __user
*user_buf
,
551 size_t count
, loff_t
*ppos
)
553 enum { max_count
= 4096 };
554 struct wil_blob_wrapper
*wil_blob
= file
->private_data
;
555 struct wil6210_priv
*wil
= wil_blob
->wil
;
557 size_t available
= wil_blob
->blob
.size
;
562 if (test_bit(wil_status_suspending
, wil_blob
->wil
->status
) ||
563 test_bit(wil_status_suspended
, wil_blob
->wil
->status
))
569 if (pos
>= available
|| !count
)
572 if (count
> available
- pos
)
573 count
= available
- pos
;
574 if (count
> max_count
)
577 buf
= kmalloc(count
, GFP_KERNEL
);
581 rc
= wil_pm_runtime_get(wil
);
587 wil_memcpy_fromio_32(buf
, (const void __iomem
*)
588 wil_blob
->blob
.data
+ pos
, count
);
590 ret
= copy_to_user(user_buf
, buf
, count
);
592 wil_pm_runtime_put(wil
);
604 static const struct file_operations fops_ioblob
= {
605 .read
= wil_read_file_ioblob
,
607 .llseek
= default_llseek
,
611 struct dentry
*wil_debugfs_create_ioblob(const char *name
,
613 struct dentry
*parent
,
614 struct wil_blob_wrapper
*wil_blob
)
616 return debugfs_create_file(name
, mode
, parent
, wil_blob
, &fops_ioblob
);
620 static ssize_t
wil_write_file_reset(struct file
*file
, const char __user
*buf
,
621 size_t len
, loff_t
*ppos
)
623 struct wil6210_priv
*wil
= file
->private_data
;
624 struct net_device
*ndev
= wil_to_ndev(wil
);
628 * this code does NOT sync device state with the rest of system
629 * use with care, debug only!!!
633 ndev
->flags
&= ~IFF_UP
;
635 wil_reset(wil
, true);
640 static const struct file_operations fops_reset
= {
641 .write
= wil_write_file_reset
,
645 /*---write channel 1..4 to rxon for it, 0 to rxoff---*/
646 static ssize_t
wil_write_file_rxon(struct file
*file
, const char __user
*buf
,
647 size_t len
, loff_t
*ppos
)
649 struct wil6210_priv
*wil
= file
->private_data
;
654 char *kbuf
= memdup_user_nul(buf
, len
);
657 return PTR_ERR(kbuf
);
658 rc
= kstrtol(kbuf
, 0, &channel
);
663 if ((channel
< 0) || (channel
> 4)) {
664 wil_err(wil
, "Invalid channel %ld\n", channel
);
670 rc
= wmi_set_channel(wil
, (int)channel
);
675 rc
= wmi_rxon(wil
, on
);
682 static const struct file_operations fops_rxon
= {
683 .write
= wil_write_file_rxon
,
687 /* block ack control, write:
688 * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
689 * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
690 * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
692 static ssize_t
wil_write_back(struct file
*file
, const char __user
*buf
,
693 size_t len
, loff_t
*ppos
)
695 struct wil6210_priv
*wil
= file
->private_data
;
697 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
704 rc
= simple_write_to_buffer(kbuf
, len
, ppos
, buf
, len
);
707 return rc
>= 0 ? -EIO
: rc
;
711 rc
= sscanf(kbuf
, "%8s %d %d %d", cmd
, &p1
, &p2
, &p3
);
719 if (0 == strcmp(cmd
, "add")) {
721 wil_err(wil
, "BACK: add require at least 2 params\n");
726 wmi_addba(wil
, p1
, p2
, p3
);
727 } else if (0 == strcmp(cmd
, "del_tx")) {
729 p2
= WLAN_REASON_QSTA_LEAVE_QBSS
;
730 wmi_delba_tx(wil
, p1
, p2
);
731 } else if (0 == strcmp(cmd
, "del_rx")) {
734 "BACK: del_rx require at least 2 params\n");
738 p3
= WLAN_REASON_QSTA_LEAVE_QBSS
;
739 wmi_delba_rx(wil
, mk_cidxtid(p1
, p2
), p3
);
741 wil_err(wil
, "BACK: Unrecognized command \"%s\"\n", cmd
);
748 static ssize_t
wil_read_back(struct file
*file
, char __user
*user_buf
,
749 size_t count
, loff_t
*ppos
)
751 static const char text
[] = "block ack control, write:\n"
752 " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
753 "If missing, <timeout> defaults to 0\n"
754 " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
755 " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
756 "If missing, <reason> set to \"STA_LEAVING\" (36)\n";
758 return simple_read_from_buffer(user_buf
, count
, ppos
, text
,
762 static const struct file_operations fops_back
= {
763 .read
= wil_read_back
,
764 .write
= wil_write_back
,
768 /* pmc control, write:
769 * - "alloc <num descriptors> <descriptor_size>" to allocate PMC
770 * - "free" to release memory allocated for PMC
772 static ssize_t
wil_write_pmccfg(struct file
*file
, const char __user
*buf
,
773 size_t len
, loff_t
*ppos
)
775 struct wil6210_priv
*wil
= file
->private_data
;
777 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
779 int num_descs
, desc_size
;
784 rc
= simple_write_to_buffer(kbuf
, len
, ppos
, buf
, len
);
787 return rc
>= 0 ? -EIO
: rc
;
791 rc
= sscanf(kbuf
, "%8s %d %d", cmd
, &num_descs
, &desc_size
);
798 wil_err(wil
, "pmccfg: no params given\n");
802 if (0 == strcmp(cmd
, "alloc")) {
804 wil_err(wil
, "pmccfg: alloc requires 2 params\n");
807 wil_pmc_alloc(wil
, num_descs
, desc_size
);
808 } else if (0 == strcmp(cmd
, "free")) {
810 wil_err(wil
, "pmccfg: free does not have any params\n");
813 wil_pmc_free(wil
, true);
815 wil_err(wil
, "pmccfg: Unrecognized command \"%s\"\n", cmd
);
822 static ssize_t
wil_read_pmccfg(struct file
*file
, char __user
*user_buf
,
823 size_t count
, loff_t
*ppos
)
825 struct wil6210_priv
*wil
= file
->private_data
;
827 char help
[] = "pmc control, write:\n"
828 " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
829 " - \"free\" to free memory allocated for pmc\n";
831 sprintf(text
, "Last command status: %d\n\n%s",
832 wil_pmc_last_cmd_status(wil
),
835 return simple_read_from_buffer(user_buf
, count
, ppos
, text
,
839 static const struct file_operations fops_pmccfg
= {
840 .read
= wil_read_pmccfg
,
841 .write
= wil_write_pmccfg
,
845 static const struct file_operations fops_pmcdata
= {
847 .read
= wil_pmc_read
,
848 .llseek
= wil_pmc_llseek
,
852 /* Write mgmt frame to this file to send it */
853 static ssize_t
wil_write_file_txmgmt(struct file
*file
, const char __user
*buf
,
854 size_t len
, loff_t
*ppos
)
856 struct wil6210_priv
*wil
= file
->private_data
;
857 struct wiphy
*wiphy
= wil_to_wiphy(wil
);
858 struct wireless_dev
*wdev
= wil_to_wdev(wil
);
859 struct cfg80211_mgmt_tx_params params
;
866 frame
= memdup_user(buf
, len
);
868 return PTR_ERR(frame
);
873 rc
= wil_cfg80211_mgmt_tx(wiphy
, wdev
, ¶ms
, NULL
);
876 wil_info(wil
, "-> %d\n", rc
);
881 static const struct file_operations fops_txmgmt
= {
882 .write
= wil_write_file_txmgmt
,
886 /* Write WMI command (w/o mbox header) to this file to send it
887 * WMI starts from wil6210_mbox_hdr_wmi header
889 static ssize_t
wil_write_file_wmi(struct file
*file
, const char __user
*buf
,
890 size_t len
, loff_t
*ppos
)
892 struct wil6210_priv
*wil
= file
->private_data
;
893 struct wmi_cmd_hdr
*wmi
;
895 int cmdlen
= len
- sizeof(struct wmi_cmd_hdr
);
902 wmi
= kmalloc(len
, GFP_KERNEL
);
906 rc
= simple_write_to_buffer(wmi
, len
, ppos
, buf
, len
);
912 cmd
= (cmdlen
> 0) ? &wmi
[1] : NULL
;
913 cmdid
= le16_to_cpu(wmi
->command_id
);
915 rc1
= wmi_send(wil
, cmdid
, cmd
, cmdlen
);
918 wil_info(wil
, "0x%04x[%d] -> %d\n", cmdid
, cmdlen
, rc1
);
923 static const struct file_operations fops_wmi
= {
924 .write
= wil_write_file_wmi
,
928 static void wil_seq_print_skb(struct seq_file
*s
, struct sk_buff
*skb
)
931 int len
= skb_headlen(skb
);
933 int nr_frags
= skb_shinfo(skb
)->nr_frags
;
935 seq_printf(s
, " len = %d\n", len
);
936 wil_seq_hexdump(s
, p
, len
, " : ");
939 seq_printf(s
, " nr_frags = %d\n", nr_frags
);
940 for (i
= 0; i
< nr_frags
; i
++) {
941 const struct skb_frag_struct
*frag
=
942 &skb_shinfo(skb
)->frags
[i
];
944 len
= skb_frag_size(frag
);
945 p
= skb_frag_address_safe(frag
);
946 seq_printf(s
, " [%2d] : len = %d\n", i
, len
);
947 wil_seq_hexdump(s
, p
, len
, " : ");
952 /*---------Tx/Rx descriptor------------*/
953 static int wil_txdesc_debugfs_show(struct seq_file
*s
, void *data
)
955 struct wil6210_priv
*wil
= s
->private;
957 bool tx
= (dbg_vring_index
< WIL6210_MAX_TX_RINGS
);
959 vring
= tx
? &wil
->vring_tx
[dbg_vring_index
] : &wil
->vring_rx
;
963 seq_printf(s
, "No Tx[%2d] VRING\n", dbg_vring_index
);
965 seq_puts(s
, "No Rx VRING\n");
969 if (dbg_txdesc_index
< vring
->size
) {
970 /* use struct vring_tx_desc for Rx as well,
971 * only field used, .dma.length, is the same
973 volatile struct vring_tx_desc
*d
=
974 &vring
->va
[dbg_txdesc_index
].tx
;
975 volatile u32
*u
= (volatile u32
*)d
;
976 struct sk_buff
*skb
= vring
->ctx
[dbg_txdesc_index
].skb
;
979 seq_printf(s
, "Tx[%2d][%3d] = {\n", dbg_vring_index
,
982 seq_printf(s
, "Rx[%3d] = {\n", dbg_txdesc_index
);
983 seq_printf(s
, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
984 u
[0], u
[1], u
[2], u
[3]);
985 seq_printf(s
, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
986 u
[4], u
[5], u
[6], u
[7]);
987 seq_printf(s
, " SKB = 0x%p\n", skb
);
991 wil_seq_print_skb(s
, skb
);
997 seq_printf(s
, "[%2d] TxDesc index (%d) >= size (%d)\n",
998 dbg_vring_index
, dbg_txdesc_index
,
1001 seq_printf(s
, "RxDesc index (%d) >= size (%d)\n",
1002 dbg_txdesc_index
, vring
->size
);
1008 static int wil_txdesc_seq_open(struct inode
*inode
, struct file
*file
)
1010 return single_open(file
, wil_txdesc_debugfs_show
, inode
->i_private
);
1013 static const struct file_operations fops_txdesc
= {
1014 .open
= wil_txdesc_seq_open
,
1015 .release
= single_release
,
1017 .llseek
= seq_lseek
,
1020 /*---------beamforming------------*/
1021 static char *wil_bfstatus_str(u32 status
)
1035 static bool is_all_zeros(void * const x_
, size_t sz
)
1037 /* if reply is all-0, ignore this CID */
1041 for (n
= 0; n
< sz
/ sizeof(*x
); n
++)
1048 static int wil_bf_debugfs_show(struct seq_file
*s
, void *data
)
1052 struct wil6210_priv
*wil
= s
->private;
1053 struct wmi_notify_req_cmd cmd
= {
1057 struct wmi_cmd_hdr wmi
;
1058 struct wmi_notify_req_done_event evt
;
1061 for (i
= 0; i
< ARRAY_SIZE(wil
->sta
); i
++) {
1065 rc
= wmi_call(wil
, WMI_NOTIFY_REQ_CMDID
, &cmd
, sizeof(cmd
),
1066 WMI_NOTIFY_REQ_DONE_EVENTID
, &reply
,
1068 /* if reply is all-0, ignore this CID */
1069 if (rc
|| is_all_zeros(&reply
.evt
, sizeof(reply
.evt
)))
1072 status
= le32_to_cpu(reply
.evt
.status
);
1073 seq_printf(s
, "CID %d {\n"
1074 " TSF = 0x%016llx\n"
1075 " TxMCS = %2d TxTpt = %4d\n"
1078 " Status = 0x%08x %s\n"
1079 " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
1080 " Goodput(rx:tx) %4d:%4d\n"
1083 le64_to_cpu(reply
.evt
.tsf
),
1084 le16_to_cpu(reply
.evt
.bf_mcs
),
1085 le32_to_cpu(reply
.evt
.tx_tpt
),
1088 status
, wil_bfstatus_str(status
),
1089 le16_to_cpu(reply
.evt
.my_rx_sector
),
1090 le16_to_cpu(reply
.evt
.my_tx_sector
),
1091 le16_to_cpu(reply
.evt
.other_rx_sector
),
1092 le16_to_cpu(reply
.evt
.other_tx_sector
),
1093 le32_to_cpu(reply
.evt
.rx_goodput
),
1094 le32_to_cpu(reply
.evt
.tx_goodput
));
1099 static int wil_bf_seq_open(struct inode
*inode
, struct file
*file
)
1101 return single_open(file
, wil_bf_debugfs_show
, inode
->i_private
);
1104 static const struct file_operations fops_bf
= {
1105 .open
= wil_bf_seq_open
,
1106 .release
= single_release
,
1108 .llseek
= seq_lseek
,
1111 /*---------temp------------*/
1112 static void print_temp(struct seq_file
*s
, const char *prefix
, u32 t
)
1117 seq_printf(s
, "%s N/A\n", prefix
);
1120 seq_printf(s
, "%s %d.%03d\n", prefix
, t
/ 1000, t
% 1000);
1125 static int wil_temp_debugfs_show(struct seq_file
*s
, void *data
)
1127 struct wil6210_priv
*wil
= s
->private;
1129 int rc
= wmi_get_temperature(wil
, &t_m
, &t_r
);
1132 seq_puts(s
, "Failed\n");
1136 print_temp(s
, "T_mac =", t_m
);
1137 print_temp(s
, "T_radio =", t_r
);
1142 static int wil_temp_seq_open(struct inode
*inode
, struct file
*file
)
1144 return single_open(file
, wil_temp_debugfs_show
, inode
->i_private
);
1147 static const struct file_operations fops_temp
= {
1148 .open
= wil_temp_seq_open
,
1149 .release
= single_release
,
1151 .llseek
= seq_lseek
,
1154 /*---------freq------------*/
1155 static int wil_freq_debugfs_show(struct seq_file
*s
, void *data
)
1157 struct wil6210_priv
*wil
= s
->private;
1158 struct wireless_dev
*wdev
= wil_to_wdev(wil
);
1159 u16 freq
= wdev
->chandef
.chan
? wdev
->chandef
.chan
->center_freq
: 0;
1161 seq_printf(s
, "Freq = %d\n", freq
);
1166 static int wil_freq_seq_open(struct inode
*inode
, struct file
*file
)
1168 return single_open(file
, wil_freq_debugfs_show
, inode
->i_private
);
1171 static const struct file_operations fops_freq
= {
1172 .open
= wil_freq_seq_open
,
1173 .release
= single_release
,
1175 .llseek
= seq_lseek
,
1178 /*---------link------------*/
1179 static int wil_link_debugfs_show(struct seq_file
*s
, void *data
)
1181 struct wil6210_priv
*wil
= s
->private;
1182 struct station_info sinfo
;
1185 for (i
= 0; i
< ARRAY_SIZE(wil
->sta
); i
++) {
1186 struct wil_sta_info
*p
= &wil
->sta
[i
];
1187 char *status
= "unknown";
1189 switch (p
->status
) {
1190 case wil_sta_unused
:
1193 case wil_sta_conn_pending
:
1194 status
= "pending ";
1196 case wil_sta_connected
:
1197 status
= "connected";
1200 seq_printf(s
, "[%d] %pM %s\n", i
, p
->addr
, status
);
1202 if (p
->status
== wil_sta_connected
) {
1203 rc
= wil_cid_fill_sinfo(wil
, i
, &sinfo
);
1207 seq_printf(s
, " Tx_mcs = %d\n", sinfo
.txrate
.mcs
);
1208 seq_printf(s
, " Rx_mcs = %d\n", sinfo
.rxrate
.mcs
);
1209 seq_printf(s
, " SQ = %d\n", sinfo
.signal
);
1216 static int wil_link_seq_open(struct inode
*inode
, struct file
*file
)
1218 return single_open(file
, wil_link_debugfs_show
, inode
->i_private
);
1221 static const struct file_operations fops_link
= {
1222 .open
= wil_link_seq_open
,
1223 .release
= single_release
,
1225 .llseek
= seq_lseek
,
1228 /*---------info------------*/
1229 static int wil_info_debugfs_show(struct seq_file
*s
, void *data
)
1231 struct wil6210_priv
*wil
= s
->private;
1232 struct net_device
*ndev
= wil_to_ndev(wil
);
1233 int is_ac
= power_supply_is_system_supplied();
1234 int rx
= atomic_xchg(&wil
->isr_count_rx
, 0);
1235 int tx
= atomic_xchg(&wil
->isr_count_tx
, 0);
1236 static ulong rxf_old
, txf_old
;
1237 ulong rxf
= ndev
->stats
.rx_packets
;
1238 ulong txf
= ndev
->stats
.tx_packets
;
1241 /* >0 : AC; 0 : battery; <0 : error */
1242 seq_printf(s
, "AC powered : %d\n", is_ac
);
1243 seq_printf(s
, "Rx irqs:packets : %8d : %8ld\n", rx
, rxf
- rxf_old
);
1244 seq_printf(s
, "Tx irqs:packets : %8d : %8ld\n", tx
, txf
- txf_old
);
1248 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1249 " " __stringify(x) : ""
1251 for (i
= 0; i
< ndev
->num_tx_queues
; i
++) {
1252 struct netdev_queue
*txq
= netdev_get_tx_queue(ndev
, i
);
1253 unsigned long state
= txq
->state
;
1255 seq_printf(s
, "Tx queue[%i] state : 0x%lx%s%s%s\n", i
, state
,
1256 CHECK_QSTATE(DRV_XOFF
),
1257 CHECK_QSTATE(STACK_XOFF
),
1258 CHECK_QSTATE(FROZEN
)
1265 static int wil_info_seq_open(struct inode
*inode
, struct file
*file
)
1267 return single_open(file
, wil_info_debugfs_show
, inode
->i_private
);
1270 static const struct file_operations fops_info
= {
1271 .open
= wil_info_seq_open
,
1272 .release
= single_release
,
1274 .llseek
= seq_lseek
,
1277 /*---------recovery------------*/
1278 /* mode = [manual|auto]
1279 * state = [idle|pending|running]
1281 static ssize_t
wil_read_file_recovery(struct file
*file
, char __user
*user_buf
,
1282 size_t count
, loff_t
*ppos
)
1284 struct wil6210_priv
*wil
= file
->private_data
;
1287 static const char * const sstate
[] = {"idle", "pending", "running"};
1289 n
= snprintf(buf
, sizeof(buf
), "mode = %s\nstate = %s\n",
1290 no_fw_recovery
? "manual" : "auto",
1291 sstate
[wil
->recovery_state
]);
1293 n
= min_t(int, n
, sizeof(buf
));
1295 return simple_read_from_buffer(user_buf
, count
, ppos
,
1299 static ssize_t
wil_write_file_recovery(struct file
*file
,
1300 const char __user
*buf_
,
1301 size_t count
, loff_t
*ppos
)
1303 struct wil6210_priv
*wil
= file
->private_data
;
1304 static const char run_command
[] = "run";
1305 char buf
[sizeof(run_command
) + 1]; /* to detect "runx" */
1308 if (wil
->recovery_state
!= fw_recovery_pending
) {
1309 wil_err(wil
, "No recovery pending\n");
1314 wil_err(wil
, "Offset [%d]\n", (int)*ppos
);
1318 if (count
> sizeof(buf
)) {
1319 wil_err(wil
, "Input too long, len = %d\n", (int)count
);
1323 rc
= simple_write_to_buffer(buf
, sizeof(buf
) - 1, ppos
, buf_
, count
);
1328 if (0 == strcmp(buf
, run_command
))
1329 wil_set_recovery_state(wil
, fw_recovery_running
);
1331 wil_err(wil
, "Bad recovery command \"%s\"\n", buf
);
1336 static const struct file_operations fops_recovery
= {
1337 .read
= wil_read_file_recovery
,
1338 .write
= wil_write_file_recovery
,
1339 .open
= simple_open
,
1342 /*---------Station matrix------------*/
1343 static void wil_print_rxtid(struct seq_file
*s
, struct wil_tid_ampdu_rx
*r
)
1346 u16 index
= ((r
->head_seq_num
- r
->ssn
) & 0xfff) % r
->buf_size
;
1347 unsigned long long drop_dup
= r
->drop_dup
, drop_old
= r
->drop_old
;
1349 seq_printf(s
, "([%2d] %3d TU) 0x%03x [", r
->buf_size
, r
->timeout
,
1351 for (i
= 0; i
< r
->buf_size
; i
++) {
1353 seq_printf(s
, "%c", r
->reorder_buf
[i
] ? 'O' : '|');
1355 seq_printf(s
, "%c", r
->reorder_buf
[i
] ? '*' : '_');
1358 "] total %llu drop %llu (dup %llu + old %llu) last 0x%03x\n",
1359 r
->total
, drop_dup
+ drop_old
, drop_dup
, drop_old
,
1363 static void wil_print_rxtid_crypto(struct seq_file
*s
, int tid
,
1364 struct wil_tid_crypto_rx
*c
)
1368 for (i
= 0; i
< 4; i
++) {
1369 struct wil_tid_crypto_rx_single
*cc
= &c
->key_id
[i
];
1377 if (tid
< WIL_STA_TID_NUM
)
1378 seq_printf(s
, " [%2d] PN", tid
);
1380 seq_puts(s
, " [GR] PN");
1382 for (i
= 0; i
< 4; i
++) {
1383 struct wil_tid_crypto_rx_single
*cc
= &c
->key_id
[i
];
1385 seq_printf(s
, " [%i%s]%6phN", i
, cc
->key_set
? "+" : "-",
1391 static int wil_sta_debugfs_show(struct seq_file
*s
, void *data
)
1392 __acquires(&p
->tid_rx_lock
) __releases(&p
->tid_rx_lock
)
1394 struct wil6210_priv
*wil
= s
->private;
1397 for (i
= 0; i
< ARRAY_SIZE(wil
->sta
); i
++) {
1398 struct wil_sta_info
*p
= &wil
->sta
[i
];
1399 char *status
= "unknown";
1402 switch (p
->status
) {
1403 case wil_sta_unused
:
1406 case wil_sta_conn_pending
:
1407 status
= "pending ";
1409 case wil_sta_connected
:
1410 status
= "connected";
1414 seq_printf(s
, "[%d] %pM %s AID %d\n", i
, p
->addr
, status
, aid
);
1416 if (p
->status
== wil_sta_connected
) {
1417 spin_lock_bh(&p
->tid_rx_lock
);
1418 for (tid
= 0; tid
< WIL_STA_TID_NUM
; tid
++) {
1419 struct wil_tid_ampdu_rx
*r
= p
->tid_rx
[tid
];
1420 struct wil_tid_crypto_rx
*c
=
1421 &p
->tid_crypto_rx
[tid
];
1424 seq_printf(s
, " [%2d] ", tid
);
1425 wil_print_rxtid(s
, r
);
1428 wil_print_rxtid_crypto(s
, tid
, c
);
1430 wil_print_rxtid_crypto(s
, WIL_STA_TID_NUM
,
1431 &p
->group_crypto_rx
);
1432 spin_unlock_bh(&p
->tid_rx_lock
);
1434 "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n",
1435 p
->stats
.rx_non_data_frame
,
1436 p
->stats
.rx_short_frame
,
1437 p
->stats
.rx_large_frame
,
1438 p
->stats
.rx_replay
);
1440 seq_puts(s
, "Rx/MCS:");
1441 for (mcs
= 0; mcs
< ARRAY_SIZE(p
->stats
.rx_per_mcs
);
1443 seq_printf(s
, " %lld",
1444 p
->stats
.rx_per_mcs
[mcs
]);
1452 static int wil_sta_seq_open(struct inode
*inode
, struct file
*file
)
1454 return single_open(file
, wil_sta_debugfs_show
, inode
->i_private
);
1457 static const struct file_operations fops_sta
= {
1458 .open
= wil_sta_seq_open
,
1459 .release
= single_release
,
1461 .llseek
= seq_lseek
,
1464 static ssize_t
wil_read_file_led_cfg(struct file
*file
, char __user
*user_buf
,
1465 size_t count
, loff_t
*ppos
)
1470 n
= snprintf(buf
, sizeof(buf
),
1471 "led_id is set to %d, echo 1 to enable, 0 to disable\n",
1474 n
= min_t(int, n
, sizeof(buf
));
1476 return simple_read_from_buffer(user_buf
, count
, ppos
,
1480 static ssize_t
wil_write_file_led_cfg(struct file
*file
,
1481 const char __user
*buf_
,
1482 size_t count
, loff_t
*ppos
)
1484 struct wil6210_priv
*wil
= file
->private_data
;
1488 rc
= kstrtoint_from_user(buf_
, count
, 0, &val
);
1490 wil_err(wil
, "Invalid argument\n");
1494 wil_info(wil
, "%s led %d\n", val
? "Enabling" : "Disabling", led_id
);
1495 rc
= wmi_led_cfg(wil
, val
);
1497 wil_info(wil
, "%s led %d failed\n",
1498 val
? "Enabling" : "Disabling", led_id
);
1505 static const struct file_operations fops_led_cfg
= {
1506 .read
= wil_read_file_led_cfg
,
1507 .write
= wil_write_file_led_cfg
,
1508 .open
= simple_open
,
1511 /* led_blink_time, write:
1512 * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
1514 static ssize_t
wil_write_led_blink_time(struct file
*file
,
1515 const char __user
*buf
,
1516 size_t len
, loff_t
*ppos
)
1519 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
1524 rc
= simple_write_to_buffer(kbuf
, len
, ppos
, buf
, len
);
1527 return rc
>= 0 ? -EIO
: rc
;
1531 rc
= sscanf(kbuf
, "%d %d %d %d %d %d",
1532 &led_blink_time
[WIL_LED_TIME_SLOW
].on_ms
,
1533 &led_blink_time
[WIL_LED_TIME_SLOW
].off_ms
,
1534 &led_blink_time
[WIL_LED_TIME_MED
].on_ms
,
1535 &led_blink_time
[WIL_LED_TIME_MED
].off_ms
,
1536 &led_blink_time
[WIL_LED_TIME_FAST
].on_ms
,
1537 &led_blink_time
[WIL_LED_TIME_FAST
].off_ms
);
1548 static ssize_t
wil_read_led_blink_time(struct file
*file
, char __user
*user_buf
,
1549 size_t count
, loff_t
*ppos
)
1551 static char text
[400];
1553 snprintf(text
, sizeof(text
),
1554 "To set led blink on/off time variables write:\n"
1555 "<blink_on_slow> <blink_off_slow> <blink_on_med> "
1556 "<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
1557 "The current values are:\n"
1558 "%d %d %d %d %d %d\n",
1559 led_blink_time
[WIL_LED_TIME_SLOW
].on_ms
,
1560 led_blink_time
[WIL_LED_TIME_SLOW
].off_ms
,
1561 led_blink_time
[WIL_LED_TIME_MED
].on_ms
,
1562 led_blink_time
[WIL_LED_TIME_MED
].off_ms
,
1563 led_blink_time
[WIL_LED_TIME_FAST
].on_ms
,
1564 led_blink_time
[WIL_LED_TIME_FAST
].off_ms
);
1566 return simple_read_from_buffer(user_buf
, count
, ppos
, text
,
1570 static const struct file_operations fops_led_blink_time
= {
1571 .read
= wil_read_led_blink_time
,
1572 .write
= wil_write_led_blink_time
,
1573 .open
= simple_open
,
1576 /*---------FW capabilities------------*/
1577 static int wil_fw_capabilities_debugfs_show(struct seq_file
*s
, void *data
)
1579 struct wil6210_priv
*wil
= s
->private;
1581 seq_printf(s
, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX
,
1582 wil
->fw_capabilities
);
1587 static int wil_fw_capabilities_seq_open(struct inode
*inode
, struct file
*file
)
1589 return single_open(file
, wil_fw_capabilities_debugfs_show
,
1593 static const struct file_operations fops_fw_capabilities
= {
1594 .open
= wil_fw_capabilities_seq_open
,
1595 .release
= single_release
,
1597 .llseek
= seq_lseek
,
1600 /*---------FW version------------*/
1601 static int wil_fw_version_debugfs_show(struct seq_file
*s
, void *data
)
1603 struct wil6210_priv
*wil
= s
->private;
1605 if (wil
->fw_version
[0])
1606 seq_printf(s
, "%s\n", wil
->fw_version
);
1608 seq_puts(s
, "N/A\n");
1613 static int wil_fw_version_seq_open(struct inode
*inode
, struct file
*file
)
1615 return single_open(file
, wil_fw_version_debugfs_show
,
1619 static const struct file_operations fops_fw_version
= {
1620 .open
= wil_fw_version_seq_open
,
1621 .release
= single_release
,
1623 .llseek
= seq_lseek
,
1626 /*---------suspend_stats---------*/
1627 static ssize_t
wil_write_suspend_stats(struct file
*file
,
1628 const char __user
*buf
,
1629 size_t len
, loff_t
*ppos
)
1631 struct wil6210_priv
*wil
= file
->private_data
;
1633 memset(&wil
->suspend_stats
, 0, sizeof(wil
->suspend_stats
));
1638 static ssize_t
wil_read_suspend_stats(struct file
*file
,
1639 char __user
*user_buf
,
1640 size_t count
, loff_t
*ppos
)
1642 struct wil6210_priv
*wil
= file
->private_data
;
1644 int n
, ret
, text_size
= 500;
1646 text
= kmalloc(text_size
, GFP_KERNEL
);
1650 n
= snprintf(text
, text_size
,
1651 "Radio on suspend statistics:\n"
1652 "successful suspends:%ld failed suspends:%ld\n"
1653 "successful resumes:%ld failed resumes:%ld\n"
1654 "rejected by device:%ld\n"
1655 "Radio off suspend statistics:\n"
1656 "successful suspends:%ld failed suspends:%ld\n"
1657 "successful resumes:%ld failed resumes:%ld\n"
1658 "General statistics:\n"
1659 "rejected by host:%ld\n",
1660 wil
->suspend_stats
.r_on
.successful_suspends
,
1661 wil
->suspend_stats
.r_on
.failed_suspends
,
1662 wil
->suspend_stats
.r_on
.successful_resumes
,
1663 wil
->suspend_stats
.r_on
.failed_resumes
,
1664 wil
->suspend_stats
.rejected_by_device
,
1665 wil
->suspend_stats
.r_off
.successful_suspends
,
1666 wil
->suspend_stats
.r_off
.failed_suspends
,
1667 wil
->suspend_stats
.r_off
.successful_resumes
,
1668 wil
->suspend_stats
.r_off
.failed_resumes
,
1669 wil
->suspend_stats
.rejected_by_host
);
1671 n
= min_t(int, n
, text_size
);
1673 ret
= simple_read_from_buffer(user_buf
, count
, ppos
, text
, n
);
1680 static const struct file_operations fops_suspend_stats
= {
1681 .read
= wil_read_suspend_stats
,
1682 .write
= wil_write_suspend_stats
,
1683 .open
= simple_open
,
1686 /*----------------*/
1687 static void wil6210_debugfs_init_blobs(struct wil6210_priv
*wil
,
1693 for (i
= 0; i
< ARRAY_SIZE(fw_mapping
); i
++) {
1694 struct wil_blob_wrapper
*wil_blob
= &wil
->blobs
[i
];
1695 struct debugfs_blob_wrapper
*blob
= &wil_blob
->blob
;
1696 const struct fw_map
*map
= &fw_mapping
[i
];
1701 wil_blob
->wil
= wil
;
1702 blob
->data
= (void * __force
)wil
->csr
+ HOSTADDR(map
->host
);
1703 blob
->size
= map
->to
- map
->from
;
1704 snprintf(name
, sizeof(name
), "blob_%s", map
->name
);
1705 wil_debugfs_create_ioblob(name
, 0444, dbg
, wil_blob
);
1710 static const struct {
1713 const struct file_operations
*fops
;
1715 {"mbox", 0444, &fops_mbox
},
1716 {"vrings", 0444, &fops_vring
},
1717 {"stations", 0444, &fops_sta
},
1718 {"desc", 0444, &fops_txdesc
},
1719 {"bf", 0444, &fops_bf
},
1720 {"mem_val", 0644, &fops_memread
},
1721 {"reset", 0244, &fops_reset
},
1722 {"rxon", 0244, &fops_rxon
},
1723 {"tx_mgmt", 0244, &fops_txmgmt
},
1724 {"wmi_send", 0244, &fops_wmi
},
1725 {"back", 0644, &fops_back
},
1726 {"pmccfg", 0644, &fops_pmccfg
},
1727 {"pmcdata", 0444, &fops_pmcdata
},
1728 {"temp", 0444, &fops_temp
},
1729 {"freq", 0444, &fops_freq
},
1730 {"link", 0444, &fops_link
},
1731 {"info", 0444, &fops_info
},
1732 {"recovery", 0644, &fops_recovery
},
1733 {"led_cfg", 0644, &fops_led_cfg
},
1734 {"led_blink_time", 0644, &fops_led_blink_time
},
1735 {"fw_capabilities", 0444, &fops_fw_capabilities
},
1736 {"fw_version", 0444, &fops_fw_version
},
1737 {"suspend_stats", 0644, &fops_suspend_stats
},
1740 static void wil6210_debugfs_init_files(struct wil6210_priv
*wil
,
1745 for (i
= 0; i
< ARRAY_SIZE(dbg_files
); i
++)
1746 debugfs_create_file(dbg_files
[i
].name
, dbg_files
[i
].mode
, dbg
,
1747 wil
, dbg_files
[i
].fops
);
1750 /* interrupt control blocks */
1751 static const struct {
1755 {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR
)},
1756 {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR
)},
1757 {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR
)},
1758 {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR
)},
1761 static void wil6210_debugfs_init_isr(struct wil6210_priv
*wil
,
1766 for (i
= 0; i
< ARRAY_SIZE(dbg_icr
); i
++)
1767 wil6210_debugfs_create_ISR(wil
, dbg_icr
[i
].name
, dbg
,
1768 dbg_icr
[i
].icr_off
);
1771 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
1772 offsetof(struct wil6210_priv, name), type}
1774 /* fields in struct wil6210_priv */
1775 static const struct dbg_off dbg_wil_off
[] = {
1776 WIL_FIELD(privacy
, 0444, doff_u32
),
1777 WIL_FIELD(status
[0], 0644, doff_ulong
),
1778 WIL_FIELD(hw_version
, 0444, doff_x32
),
1779 WIL_FIELD(recovery_count
, 0444, doff_u32
),
1780 WIL_FIELD(ap_isolate
, 0444, doff_u32
),
1781 WIL_FIELD(discovery_mode
, 0644, doff_u8
),
1782 WIL_FIELD(chip_revision
, 0444, doff_u8
),
1783 WIL_FIELD(abft_len
, 0644, doff_u8
),
1784 WIL_FIELD(wakeup_trigger
, 0644, doff_u8
),
1785 WIL_FIELD(vring_idle_trsh
, 0644, doff_u32
),
1789 static const struct dbg_off dbg_wil_regs
[] = {
1790 {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0
),
1792 {"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1
), doff_io32
},
1796 /* static parameters */
1797 static const struct dbg_off dbg_statics
[] = {
1798 {"desc_index", 0644, (ulong
)&dbg_txdesc_index
, doff_u32
},
1799 {"vring_index", 0644, (ulong
)&dbg_vring_index
, doff_u32
},
1800 {"mem_addr", 0644, (ulong
)&mem_addr
, doff_u32
},
1801 {"led_polarity", 0644, (ulong
)&led_polarity
, doff_u8
},
1805 static const int dbg_off_count
= 4 * (ARRAY_SIZE(isr_off
) - 1) +
1806 ARRAY_SIZE(dbg_wil_regs
) - 1 +
1807 ARRAY_SIZE(pseudo_isr_off
) - 1 +
1808 ARRAY_SIZE(lgc_itr_cnt_off
) - 1 +
1809 ARRAY_SIZE(tx_itr_cnt_off
) - 1 +
1810 ARRAY_SIZE(rx_itr_cnt_off
) - 1;
1812 int wil6210_debugfs_init(struct wil6210_priv
*wil
)
1814 struct dentry
*dbg
= wil
->debug
= debugfs_create_dir(WIL_NAME
,
1815 wil_to_wiphy(wil
)->debugfsdir
);
1816 if (IS_ERR_OR_NULL(dbg
))
1819 wil
->dbg_data
.data_arr
= kcalloc(dbg_off_count
,
1820 sizeof(struct wil_debugfs_iomem_data
),
1822 if (!wil
->dbg_data
.data_arr
) {
1823 debugfs_remove_recursive(dbg
);
1828 wil
->dbg_data
.iomem_data_count
= 0;
1832 wil6210_debugfs_init_files(wil
, dbg
);
1833 wil6210_debugfs_init_isr(wil
, dbg
);
1834 wil6210_debugfs_init_blobs(wil
, dbg
);
1835 wil6210_debugfs_init_offset(wil
, dbg
, wil
, dbg_wil_off
);
1836 wil6210_debugfs_init_offset(wil
, dbg
, (void * __force
)wil
->csr
,
1838 wil6210_debugfs_init_offset(wil
, dbg
, NULL
, dbg_statics
);
1840 wil6210_debugfs_create_pseudo_ISR(wil
, dbg
);
1842 wil6210_debugfs_create_ITR_CNT(wil
, dbg
);
1847 void wil6210_debugfs_remove(struct wil6210_priv
*wil
)
1849 debugfs_remove_recursive(wil
->debug
);
1852 kfree(wil
->dbg_data
.data_arr
);
1854 /* free pmc memory without sending command to fw, as it will
1855 * be reset on the way down anyway
1857 wil_pmc_free(wil
, false);