2 * Copyright (c) 2012-2014 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 */
45 enum dbg_off_type type
;
48 static void wil_print_vring(struct seq_file
*s
, struct wil6210_priv
*wil
,
49 const char *name
, struct vring
*vring
,
52 void __iomem
*x
= wmi_addr(wil
, vring
->hwtail
);
54 seq_printf(s
, "VRING %s = {\n", name
);
55 seq_printf(s
, " pa = %pad\n", &vring
->pa
);
56 seq_printf(s
, " va = 0x%p\n", vring
->va
);
57 seq_printf(s
, " size = %d\n", vring
->size
);
58 seq_printf(s
, " swtail = %d\n", vring
->swtail
);
59 seq_printf(s
, " swhead = %d\n", vring
->swhead
);
60 seq_printf(s
, " hwtail = [0x%08x] -> ", vring
->hwtail
);
62 seq_printf(s
, "0x%08x\n", ioread32(x
));
64 seq_printf(s
, "???\n");
66 if (vring
->va
&& (vring
->size
< 1025)) {
68 for (i
= 0; i
< vring
->size
; i
++) {
69 volatile struct vring_tx_desc
*d
= &vring
->va
[i
].tx
;
70 if ((i
% 64) == 0 && (i
!= 0))
72 seq_printf(s
, "%c", (d
->dma
.status
& BIT(0)) ?
73 _s
: (vring
->ctx
[i
].skb
? _h
: 'h'));
80 static int wil_vring_debugfs_show(struct seq_file
*s
, void *data
)
83 struct wil6210_priv
*wil
= s
->private;
85 wil_print_vring(s
, wil
, "rx", &wil
->vring_rx
, 'S', '_');
87 for (i
= 0; i
< ARRAY_SIZE(wil
->vring_tx
); i
++) {
88 struct vring
*vring
= &(wil
->vring_tx
[i
]);
89 struct vring_tx_data
*txdata
= &wil
->vring_tx_data
[i
];
92 int cid
= wil
->vring2cid_tid
[i
][0];
93 int tid
= wil
->vring2cid_tid
[i
][1];
94 u32 swhead
= vring
->swhead
;
95 u32 swtail
= vring
->swtail
;
96 int used
= (vring
->size
+ swhead
- swtail
)
98 int avail
= vring
->size
- used
- 1;
100 /* performance monitoring */
101 cycles_t now
= get_cycles();
102 cycles_t idle
= txdata
->idle
* 100;
103 cycles_t total
= now
- txdata
->begin
;
109 snprintf(name
, sizeof(name
), "tx_%2d", i
);
111 seq_printf(s
, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n",
112 wil
->sta
[cid
].addr
, cid
, tid
, used
, avail
,
115 wil_print_vring(s
, wil
, name
, vring
, '_', 'H');
122 static int wil_vring_seq_open(struct inode
*inode
, struct file
*file
)
124 return single_open(file
, wil_vring_debugfs_show
, inode
->i_private
);
127 static const struct file_operations fops_vring
= {
128 .open
= wil_vring_seq_open
,
129 .release
= single_release
,
134 static void wil_print_ring(struct seq_file
*s
, const char *prefix
,
137 struct wil6210_priv
*wil
= s
->private;
138 struct wil6210_mbox_ring r
;
142 wil_memcpy_fromio_32(&r
, off
, sizeof(r
));
143 wil_mbox_ring_le2cpus(&r
);
145 * we just read memory block from NIC. This memory may be
146 * garbage. Check validity before using it.
148 rsize
= r
.size
/ sizeof(struct wil6210_mbox_ring_desc
);
150 seq_printf(s
, "ring %s = {\n", prefix
);
151 seq_printf(s
, " base = 0x%08x\n", r
.base
);
152 seq_printf(s
, " size = 0x%04x bytes -> %d entries\n", r
.size
, rsize
);
153 seq_printf(s
, " tail = 0x%08x\n", r
.tail
);
154 seq_printf(s
, " head = 0x%08x\n", r
.head
);
155 seq_printf(s
, " entry size = %d\n", r
.entry_size
);
157 if (r
.size
% sizeof(struct wil6210_mbox_ring_desc
)) {
158 seq_printf(s
, " ??? size is not multiple of %zd, garbage?\n",
159 sizeof(struct wil6210_mbox_ring_desc
));
163 if (!wmi_addr(wil
, r
.base
) ||
164 !wmi_addr(wil
, r
.tail
) ||
165 !wmi_addr(wil
, r
.head
)) {
166 seq_printf(s
, " ??? pointers are garbage?\n");
170 for (i
= 0; i
< rsize
; i
++) {
171 struct wil6210_mbox_ring_desc d
;
172 struct wil6210_mbox_hdr hdr
;
173 size_t delta
= i
* sizeof(d
);
174 void __iomem
*x
= wil
->csr
+ HOSTADDR(r
.base
) + delta
;
176 wil_memcpy_fromio_32(&d
, x
, sizeof(d
));
178 seq_printf(s
, " [%2x] %s %s%s 0x%08x", i
,
180 (r
.tail
- r
.base
== delta
) ? "t" : " ",
181 (r
.head
- r
.base
== delta
) ? "h" : " ",
182 le32_to_cpu(d
.addr
));
183 if (0 == wmi_read_hdr(wil
, d
.addr
, &hdr
)) {
184 u16 len
= le16_to_cpu(hdr
.len
);
185 seq_printf(s
, " -> %04x %04x %04x %02x\n",
186 le16_to_cpu(hdr
.seq
), len
,
187 le16_to_cpu(hdr
.type
), hdr
.flags
);
188 if (len
<= MAX_MBOXITEM_SIZE
) {
190 char printbuf
[16 * 3 + 2];
191 unsigned char databuf
[MAX_MBOXITEM_SIZE
];
192 void __iomem
*src
= wmi_buffer(wil
, d
.addr
) +
193 sizeof(struct wil6210_mbox_hdr
);
195 * No need to check @src for validity -
196 * we already validated @d.addr while
199 wil_memcpy_fromio_32(databuf
, src
, len
);
201 int l
= min(len
- n
, 16);
202 hex_dump_to_buffer(databuf
+ n
, l
,
206 seq_printf(s
, " : %s\n", printbuf
);
215 seq_printf(s
, "}\n");
218 static int wil_mbox_debugfs_show(struct seq_file
*s
, void *data
)
220 struct wil6210_priv
*wil
= s
->private;
222 wil_print_ring(s
, "tx", wil
->csr
+ HOST_MBOX
+
223 offsetof(struct wil6210_mbox_ctl
, tx
));
224 wil_print_ring(s
, "rx", wil
->csr
+ HOST_MBOX
+
225 offsetof(struct wil6210_mbox_ctl
, rx
));
230 static int wil_mbox_seq_open(struct inode
*inode
, struct file
*file
)
232 return single_open(file
, wil_mbox_debugfs_show
, inode
->i_private
);
235 static const struct file_operations fops_mbox
= {
236 .open
= wil_mbox_seq_open
,
237 .release
= single_release
,
242 static int wil_debugfs_iomem_x32_set(void *data
, u64 val
)
244 iowrite32(val
, (void __iomem
*)data
);
245 wmb(); /* make sure write propagated to HW */
250 static int wil_debugfs_iomem_x32_get(void *data
, u64
*val
)
252 *val
= ioread32((void __iomem
*)data
);
257 DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32
, wil_debugfs_iomem_x32_get
,
258 wil_debugfs_iomem_x32_set
, "0x%08llx\n");
260 static struct dentry
*wil_debugfs_create_iomem_x32(const char *name
,
262 struct dentry
*parent
,
265 return debugfs_create_file(name
, mode
, parent
, value
,
269 static int wil_debugfs_ulong_set(void *data
, u64 val
)
271 *(ulong
*)data
= val
;
274 static int wil_debugfs_ulong_get(void *data
, u64
*val
)
276 *val
= *(ulong
*)data
;
279 DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong
, wil_debugfs_ulong_get
,
280 wil_debugfs_ulong_set
, "%llu\n");
282 static struct dentry
*wil_debugfs_create_ulong(const char *name
, umode_t mode
,
283 struct dentry
*parent
,
286 return debugfs_create_file(name
, mode
, parent
, value
, &wil_fops_ulong
);
290 * wil6210_debugfs_init_offset - create set of debugfs files
291 * @wil - driver's context, used for printing
292 * @dbg - directory on the debugfs, where files will be created
293 * @base - base address used in address calculation
294 * @tbl - table with file descriptions. Should be terminated with empty element.
296 * Creates files accordingly to the @tbl.
298 static void wil6210_debugfs_init_offset(struct wil6210_priv
*wil
,
299 struct dentry
*dbg
, void *base
,
300 const struct dbg_off
* const tbl
)
304 for (i
= 0; tbl
[i
].name
; i
++) {
305 struct dentry
*f
= NULL
;
307 switch (tbl
[i
].type
) {
309 f
= debugfs_create_u32(tbl
[i
].name
, tbl
[i
].mode
, dbg
,
313 f
= debugfs_create_x32(tbl
[i
].name
, tbl
[i
].mode
, dbg
,
317 f
= wil_debugfs_create_ulong(tbl
[i
].name
, tbl
[i
].mode
,
318 dbg
, base
+ tbl
[i
].off
);
321 f
= wil_debugfs_create_iomem_x32(tbl
[i
].name
,
326 if (IS_ERR_OR_NULL(f
))
327 wil_err(wil
, "Create file \"%s\": err %ld\n",
328 tbl
[i
].name
, PTR_ERR(f
));
332 static const struct dbg_off isr_off
[] = {
333 {"ICC", S_IRUGO
| S_IWUSR
, offsetof(struct RGF_ICR
, ICC
), doff_io32
},
334 {"ICR", S_IRUGO
| S_IWUSR
, offsetof(struct RGF_ICR
, ICR
), doff_io32
},
335 {"ICM", S_IRUGO
| S_IWUSR
, offsetof(struct RGF_ICR
, ICM
), doff_io32
},
336 {"ICS", S_IWUSR
, offsetof(struct RGF_ICR
, ICS
), doff_io32
},
337 {"IMV", S_IRUGO
| S_IWUSR
, offsetof(struct RGF_ICR
, IMV
), doff_io32
},
338 {"IMS", S_IWUSR
, offsetof(struct RGF_ICR
, IMS
), doff_io32
},
339 {"IMC", S_IWUSR
, offsetof(struct RGF_ICR
, IMC
), doff_io32
},
342 static int wil6210_debugfs_create_ISR(struct wil6210_priv
*wil
,
344 struct dentry
*parent
, u32 off
)
346 struct dentry
*d
= debugfs_create_dir(name
, parent
);
348 if (IS_ERR_OR_NULL(d
))
351 wil6210_debugfs_init_offset(wil
, d
, (void * __force
)wil
->csr
+ off
,
357 static const struct dbg_off pseudo_isr_off
[] = {
358 {"CAUSE", S_IRUGO
, HOSTADDR(RGF_DMA_PSEUDO_CAUSE
), doff_io32
},
359 {"MASK_SW", S_IRUGO
, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW
), doff_io32
},
360 {"MASK_FW", S_IRUGO
, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW
), doff_io32
},
364 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv
*wil
,
365 struct dentry
*parent
)
367 struct dentry
*d
= debugfs_create_dir("PSEUDO_ISR", parent
);
369 if (IS_ERR_OR_NULL(d
))
372 wil6210_debugfs_init_offset(wil
, d
, (void * __force
)wil
->csr
,
378 static const struct dbg_off itr_cnt_off
[] = {
379 {"TRSH", S_IRUGO
| S_IWUSR
, HOSTADDR(RGF_DMA_ITR_CNT_TRSH
), doff_io32
},
380 {"DATA", S_IRUGO
| S_IWUSR
, HOSTADDR(RGF_DMA_ITR_CNT_DATA
), doff_io32
},
381 {"CTL", S_IRUGO
| S_IWUSR
, HOSTADDR(RGF_DMA_ITR_CNT_CRL
), doff_io32
},
385 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv
*wil
,
386 struct dentry
*parent
)
388 struct dentry
*d
= debugfs_create_dir("ITR_CNT", parent
);
390 if (IS_ERR_OR_NULL(d
))
393 wil6210_debugfs_init_offset(wil
, d
, (void * __force
)wil
->csr
,
399 static int wil_memread_debugfs_show(struct seq_file
*s
, void *data
)
401 struct wil6210_priv
*wil
= s
->private;
402 void __iomem
*a
= wmi_buffer(wil
, cpu_to_le32(mem_addr
));
405 seq_printf(s
, "[0x%08x] = 0x%08x\n", mem_addr
, ioread32(a
));
407 seq_printf(s
, "[0x%08x] = INVALID\n", mem_addr
);
412 static int wil_memread_seq_open(struct inode
*inode
, struct file
*file
)
414 return single_open(file
, wil_memread_debugfs_show
, inode
->i_private
);
417 static const struct file_operations fops_memread
= {
418 .open
= wil_memread_seq_open
,
419 .release
= single_release
,
424 static ssize_t
wil_read_file_ioblob(struct file
*file
, char __user
*user_buf
,
425 size_t count
, loff_t
*ppos
)
427 enum { max_count
= 4096 };
428 struct debugfs_blob_wrapper
*blob
= file
->private_data
;
430 size_t available
= blob
->size
;
437 if (pos
>= available
|| !count
)
440 if (count
> available
- pos
)
441 count
= available
- pos
;
442 if (count
> max_count
)
445 buf
= kmalloc(count
, GFP_KERNEL
);
449 wil_memcpy_fromio_32(buf
, (const volatile void __iomem
*)blob
->data
+
452 ret
= copy_to_user(user_buf
, buf
, count
);
463 static const struct file_operations fops_ioblob
= {
464 .read
= wil_read_file_ioblob
,
466 .llseek
= default_llseek
,
470 struct dentry
*wil_debugfs_create_ioblob(const char *name
,
472 struct dentry
*parent
,
473 struct debugfs_blob_wrapper
*blob
)
475 return debugfs_create_file(name
, mode
, parent
, blob
, &fops_ioblob
);
478 static ssize_t
wil_write_file_reset(struct file
*file
, const char __user
*buf
,
479 size_t len
, loff_t
*ppos
)
481 struct wil6210_priv
*wil
= file
->private_data
;
482 struct net_device
*ndev
= wil_to_ndev(wil
);
486 * this code does NOT sync device state with the rest of system
487 * use with care, debug only!!!
491 ndev
->flags
&= ~IFF_UP
;
498 static const struct file_operations fops_reset
= {
499 .write
= wil_write_file_reset
,
502 /*---write channel 1..4 to rxon for it, 0 to rxoff---*/
503 static ssize_t
wil_write_file_rxon(struct file
*file
, const char __user
*buf
,
504 size_t len
, loff_t
*ppos
)
506 struct wil6210_priv
*wil
= file
->private_data
;
511 char *kbuf
= kmalloc(len
+ 1, GFP_KERNEL
);
514 if (copy_from_user(kbuf
, buf
, len
)) {
520 rc
= kstrtol(kbuf
, 0, &channel
);
525 if ((channel
< 0) || (channel
> 4)) {
526 wil_err(wil
, "Invalid channel %ld\n", channel
);
532 rc
= wmi_set_channel(wil
, (int)channel
);
537 rc
= wmi_rxon(wil
, on
);
544 static const struct file_operations fops_rxon
= {
545 .write
= wil_write_file_rxon
,
549 /* Write mgmt frame to this file to send it */
550 static ssize_t
wil_write_file_txmgmt(struct file
*file
, const char __user
*buf
,
551 size_t len
, loff_t
*ppos
)
553 struct wil6210_priv
*wil
= file
->private_data
;
554 struct wiphy
*wiphy
= wil_to_wiphy(wil
);
555 struct wireless_dev
*wdev
= wil_to_wdev(wil
);
556 struct cfg80211_mgmt_tx_params params
;
559 void *frame
= kmalloc(len
, GFP_KERNEL
);
563 if (copy_from_user(frame
, buf
, len
))
568 params
.chan
= wdev
->preset_chandef
.chan
;
570 rc
= wil_cfg80211_mgmt_tx(wiphy
, wdev
, ¶ms
, NULL
);
573 wil_info(wil
, "%s() -> %d\n", __func__
, rc
);
578 static const struct file_operations fops_txmgmt
= {
579 .write
= wil_write_file_txmgmt
,
583 /* Write WMI command (w/o mbox header) to this file to send it
584 * WMI starts from wil6210_mbox_hdr_wmi header
586 static ssize_t
wil_write_file_wmi(struct file
*file
, const char __user
*buf
,
587 size_t len
, loff_t
*ppos
)
589 struct wil6210_priv
*wil
= file
->private_data
;
590 struct wil6210_mbox_hdr_wmi
*wmi
;
592 int cmdlen
= len
- sizeof(struct wil6210_mbox_hdr_wmi
);
599 wmi
= kmalloc(len
, GFP_KERNEL
);
603 rc
= simple_write_to_buffer(wmi
, len
, ppos
, buf
, len
);
608 cmdid
= le16_to_cpu(wmi
->id
);
610 rc1
= wmi_send(wil
, cmdid
, cmd
, cmdlen
);
613 wil_info(wil
, "%s(0x%04x[%d]) -> %d\n", __func__
, cmdid
, cmdlen
, rc1
);
618 static const struct file_operations fops_wmi
= {
619 .write
= wil_write_file_wmi
,
623 static void wil_seq_hexdump(struct seq_file
*s
, void *p
, int len
,
626 char printbuf
[16 * 3 + 2];
629 int l
= min(len
- i
, 16);
630 hex_dump_to_buffer(p
+ i
, l
, 16, 1, printbuf
,
631 sizeof(printbuf
), false);
632 seq_printf(s
, "%s%s\n", prefix
, printbuf
);
637 static void wil_seq_print_skb(struct seq_file
*s
, struct sk_buff
*skb
)
640 int len
= skb_headlen(skb
);
642 int nr_frags
= skb_shinfo(skb
)->nr_frags
;
644 seq_printf(s
, " len = %d\n", len
);
645 wil_seq_hexdump(s
, p
, len
, " : ");
648 seq_printf(s
, " nr_frags = %d\n", nr_frags
);
649 for (i
= 0; i
< nr_frags
; i
++) {
650 const struct skb_frag_struct
*frag
=
651 &skb_shinfo(skb
)->frags
[i
];
653 len
= skb_frag_size(frag
);
654 p
= skb_frag_address_safe(frag
);
655 seq_printf(s
, " [%2d] : len = %d\n", i
, len
);
656 wil_seq_hexdump(s
, p
, len
, " : ");
661 /*---------Tx/Rx descriptor------------*/
662 static int wil_txdesc_debugfs_show(struct seq_file
*s
, void *data
)
664 struct wil6210_priv
*wil
= s
->private;
666 bool tx
= (dbg_vring_index
< WIL6210_MAX_TX_RINGS
);
668 vring
= &(wil
->vring_tx
[dbg_vring_index
]);
670 vring
= &wil
->vring_rx
;
674 seq_printf(s
, "No Tx[%2d] VRING\n", dbg_vring_index
);
676 seq_puts(s
, "No Rx VRING\n");
680 if (dbg_txdesc_index
< vring
->size
) {
681 /* use struct vring_tx_desc for Rx as well,
682 * only field used, .dma.length, is the same
684 volatile struct vring_tx_desc
*d
=
685 &(vring
->va
[dbg_txdesc_index
].tx
);
686 volatile u32
*u
= (volatile u32
*)d
;
687 struct sk_buff
*skb
= vring
->ctx
[dbg_txdesc_index
].skb
;
690 seq_printf(s
, "Tx[%2d][%3d] = {\n", dbg_vring_index
,
693 seq_printf(s
, "Rx[%3d] = {\n", dbg_txdesc_index
);
694 seq_printf(s
, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
695 u
[0], u
[1], u
[2], u
[3]);
696 seq_printf(s
, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
697 u
[4], u
[5], u
[6], u
[7]);
698 seq_printf(s
, " SKB = 0x%p\n", skb
);
702 wil_seq_print_skb(s
, skb
);
705 seq_printf(s
, "}\n");
708 seq_printf(s
, "[%2d] TxDesc index (%d) >= size (%d)\n",
709 dbg_vring_index
, dbg_txdesc_index
,
712 seq_printf(s
, "RxDesc index (%d) >= size (%d)\n",
713 dbg_txdesc_index
, vring
->size
);
719 static int wil_txdesc_seq_open(struct inode
*inode
, struct file
*file
)
721 return single_open(file
, wil_txdesc_debugfs_show
, inode
->i_private
);
724 static const struct file_operations fops_txdesc
= {
725 .open
= wil_txdesc_seq_open
,
726 .release
= single_release
,
731 /*---------beamforming------------*/
732 static char *wil_bfstatus_str(u32 status
)
746 static bool is_all_zeros(void * const x_
, size_t sz
)
748 /* if reply is all-0, ignore this CID */
752 for (n
= 0; n
< sz
/ sizeof(*x
); n
++)
759 static int wil_bf_debugfs_show(struct seq_file
*s
, void *data
)
763 struct wil6210_priv
*wil
= s
->private;
764 struct wmi_notify_req_cmd cmd
= {
768 struct wil6210_mbox_hdr_wmi wmi
;
769 struct wmi_notify_req_done_event evt
;
772 for (i
= 0; i
< ARRAY_SIZE(wil
->sta
); i
++) {
776 rc
= wmi_call(wil
, WMI_NOTIFY_REQ_CMDID
, &cmd
, sizeof(cmd
),
777 WMI_NOTIFY_REQ_DONE_EVENTID
, &reply
,
779 /* if reply is all-0, ignore this CID */
780 if (rc
|| is_all_zeros(&reply
.evt
, sizeof(reply
.evt
)))
783 status
= le32_to_cpu(reply
.evt
.status
);
784 seq_printf(s
, "CID %d {\n"
786 " TxMCS = %2d TxTpt = %4d\n"
788 " Status = 0x%08x %s\n"
789 " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
790 " Goodput(rx:tx) %4d:%4d\n"
793 le64_to_cpu(reply
.evt
.tsf
),
794 le16_to_cpu(reply
.evt
.bf_mcs
),
795 le32_to_cpu(reply
.evt
.tx_tpt
),
797 status
, wil_bfstatus_str(status
),
798 le16_to_cpu(reply
.evt
.my_rx_sector
),
799 le16_to_cpu(reply
.evt
.my_tx_sector
),
800 le16_to_cpu(reply
.evt
.other_rx_sector
),
801 le16_to_cpu(reply
.evt
.other_tx_sector
),
802 le32_to_cpu(reply
.evt
.rx_goodput
),
803 le32_to_cpu(reply
.evt
.tx_goodput
));
808 static int wil_bf_seq_open(struct inode
*inode
, struct file
*file
)
810 return single_open(file
, wil_bf_debugfs_show
, inode
->i_private
);
813 static const struct file_operations fops_bf
= {
814 .open
= wil_bf_seq_open
,
815 .release
= single_release
,
819 /*---------SSID------------*/
820 static ssize_t
wil_read_file_ssid(struct file
*file
, char __user
*user_buf
,
821 size_t count
, loff_t
*ppos
)
823 struct wil6210_priv
*wil
= file
->private_data
;
824 struct wireless_dev
*wdev
= wil_to_wdev(wil
);
826 return simple_read_from_buffer(user_buf
, count
, ppos
,
827 wdev
->ssid
, wdev
->ssid_len
);
830 static ssize_t
wil_write_file_ssid(struct file
*file
, const char __user
*buf
,
831 size_t count
, loff_t
*ppos
)
833 struct wil6210_priv
*wil
= file
->private_data
;
834 struct wireless_dev
*wdev
= wil_to_wdev(wil
);
835 struct net_device
*ndev
= wil_to_ndev(wil
);
838 wil_err(wil
, "Unable to set SSID substring from [%d]\n",
843 if (count
> sizeof(wdev
->ssid
)) {
844 wil_err(wil
, "SSID too long, len = %d\n", (int)count
);
847 if (netif_running(ndev
)) {
848 wil_err(wil
, "Unable to change SSID on running interface\n");
852 wdev
->ssid_len
= count
;
853 return simple_write_to_buffer(wdev
->ssid
, wdev
->ssid_len
, ppos
,
857 static const struct file_operations fops_ssid
= {
858 .read
= wil_read_file_ssid
,
859 .write
= wil_write_file_ssid
,
863 /*---------temp------------*/
864 static void print_temp(struct seq_file
*s
, const char *prefix
, u32 t
)
869 seq_printf(s
, "%s N/A\n", prefix
);
872 seq_printf(s
, "%s %d.%03d\n", prefix
, t
/ 1000, t
% 1000);
877 static int wil_temp_debugfs_show(struct seq_file
*s
, void *data
)
879 struct wil6210_priv
*wil
= s
->private;
882 int rc
= wmi_get_temperature(wil
, &t_m
, &t_r
);
884 seq_printf(s
, "Failed\n");
888 print_temp(s
, "T_mac =", t_m
);
889 print_temp(s
, "T_radio =", t_r
);
894 static int wil_temp_seq_open(struct inode
*inode
, struct file
*file
)
896 return single_open(file
, wil_temp_debugfs_show
, inode
->i_private
);
899 static const struct file_operations fops_temp
= {
900 .open
= wil_temp_seq_open
,
901 .release
= single_release
,
906 /*---------freq------------*/
907 static int wil_freq_debugfs_show(struct seq_file
*s
, void *data
)
909 struct wil6210_priv
*wil
= s
->private;
910 struct wireless_dev
*wdev
= wil_to_wdev(wil
);
911 u16 freq
= wdev
->chandef
.chan
? wdev
->chandef
.chan
->center_freq
: 0;
913 seq_printf(s
, "Freq = %d\n", freq
);
918 static int wil_freq_seq_open(struct inode
*inode
, struct file
*file
)
920 return single_open(file
, wil_freq_debugfs_show
, inode
->i_private
);
923 static const struct file_operations fops_freq
= {
924 .open
= wil_freq_seq_open
,
925 .release
= single_release
,
930 /*---------link------------*/
931 static int wil_link_debugfs_show(struct seq_file
*s
, void *data
)
933 struct wil6210_priv
*wil
= s
->private;
934 struct station_info sinfo
;
937 for (i
= 0; i
< ARRAY_SIZE(wil
->sta
); i
++) {
938 struct wil_sta_info
*p
= &wil
->sta
[i
];
939 char *status
= "unknown";
944 case wil_sta_conn_pending
:
947 case wil_sta_connected
:
948 status
= "connected";
951 seq_printf(s
, "[%d] %pM %s%s\n", i
, p
->addr
, status
,
952 (p
->data_port_open
? " data_port_open" : ""));
954 if (p
->status
== wil_sta_connected
) {
955 rc
= wil_cid_fill_sinfo(wil
, i
, &sinfo
);
959 seq_printf(s
, " Tx_mcs = %d\n", sinfo
.txrate
.mcs
);
960 seq_printf(s
, " Rx_mcs = %d\n", sinfo
.rxrate
.mcs
);
961 seq_printf(s
, " SQ = %d\n", sinfo
.signal
);
968 static int wil_link_seq_open(struct inode
*inode
, struct file
*file
)
970 return single_open(file
, wil_link_debugfs_show
, inode
->i_private
);
973 static const struct file_operations fops_link
= {
974 .open
= wil_link_seq_open
,
975 .release
= single_release
,
980 /*---------info------------*/
981 static int wil_info_debugfs_show(struct seq_file
*s
, void *data
)
983 struct wil6210_priv
*wil
= s
->private;
984 struct net_device
*ndev
= wil_to_ndev(wil
);
985 int is_ac
= power_supply_is_system_supplied();
986 int rx
= atomic_xchg(&wil
->isr_count_rx
, 0);
987 int tx
= atomic_xchg(&wil
->isr_count_tx
, 0);
988 static ulong rxf_old
, txf_old
;
989 ulong rxf
= ndev
->stats
.rx_packets
;
990 ulong txf
= ndev
->stats
.tx_packets
;
993 /* >0 : AC; 0 : battery; <0 : error */
994 seq_printf(s
, "AC powered : %d\n", is_ac
);
995 seq_printf(s
, "Rx irqs:packets : %8d : %8ld\n", rx
, rxf
- rxf_old
);
996 seq_printf(s
, "Tx irqs:packets : %8d : %8ld\n", tx
, txf
- txf_old
);
1001 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1002 " " __stringify(x) : ""
1004 for (i
= 0; i
< ndev
->num_tx_queues
; i
++) {
1005 struct netdev_queue
*txq
= netdev_get_tx_queue(ndev
, i
);
1006 unsigned long state
= txq
->state
;
1008 seq_printf(s
, "Tx queue[%i] state : 0x%lx%s%s%s\n", i
, state
,
1009 CHECK_QSTATE(DRV_XOFF
),
1010 CHECK_QSTATE(STACK_XOFF
),
1011 CHECK_QSTATE(FROZEN
)
1018 static int wil_info_seq_open(struct inode
*inode
, struct file
*file
)
1020 return single_open(file
, wil_info_debugfs_show
, inode
->i_private
);
1023 static const struct file_operations fops_info
= {
1024 .open
= wil_info_seq_open
,
1025 .release
= single_release
,
1027 .llseek
= seq_lseek
,
1030 /*---------Station matrix------------*/
1031 static void wil_print_rxtid(struct seq_file
*s
, struct wil_tid_ampdu_rx
*r
)
1034 u16 index
= ((r
->head_seq_num
- r
->ssn
) & 0xfff) % r
->buf_size
;
1035 seq_printf(s
, "0x%03x [", r
->head_seq_num
);
1036 for (i
= 0; i
< r
->buf_size
; i
++) {
1038 seq_printf(s
, "%c", r
->reorder_buf
[i
] ? 'O' : '|');
1040 seq_printf(s
, "%c", r
->reorder_buf
[i
] ? '*' : '_');
1042 seq_printf(s
, "] last drop 0x%03x\n", r
->ssn_last_drop
);
1045 static int wil_sta_debugfs_show(struct seq_file
*s
, void *data
)
1047 struct wil6210_priv
*wil
= s
->private;
1050 for (i
= 0; i
< ARRAY_SIZE(wil
->sta
); i
++) {
1051 struct wil_sta_info
*p
= &wil
->sta
[i
];
1052 char *status
= "unknown";
1053 switch (p
->status
) {
1054 case wil_sta_unused
:
1057 case wil_sta_conn_pending
:
1058 status
= "pending ";
1060 case wil_sta_connected
:
1061 status
= "connected";
1064 seq_printf(s
, "[%d] %pM %s%s\n", i
, p
->addr
, status
,
1065 (p
->data_port_open
? " data_port_open" : ""));
1067 if (p
->status
== wil_sta_connected
) {
1068 for (tid
= 0; tid
< WIL_STA_TID_NUM
; tid
++) {
1069 struct wil_tid_ampdu_rx
*r
= p
->tid_rx
[tid
];
1071 seq_printf(s
, "[%2d] ", tid
);
1072 wil_print_rxtid(s
, r
);
1081 static int wil_sta_seq_open(struct inode
*inode
, struct file
*file
)
1083 return single_open(file
, wil_sta_debugfs_show
, inode
->i_private
);
1086 static const struct file_operations fops_sta
= {
1087 .open
= wil_sta_seq_open
,
1088 .release
= single_release
,
1090 .llseek
= seq_lseek
,
1093 /*----------------*/
1094 static void wil6210_debugfs_init_blobs(struct wil6210_priv
*wil
,
1100 for (i
= 0; i
< ARRAY_SIZE(fw_mapping
); i
++) {
1101 struct debugfs_blob_wrapper
*blob
= &wil
->blobs
[i
];
1102 const struct fw_map
*map
= &fw_mapping
[i
];
1107 blob
->data
= (void * __force
)wil
->csr
+ HOSTADDR(map
->host
);
1108 blob
->size
= map
->to
- map
->from
;
1109 snprintf(name
, sizeof(name
), "blob_%s", map
->name
);
1110 wil_debugfs_create_ioblob(name
, S_IRUGO
, dbg
, blob
);
1115 static const struct {
1118 const struct file_operations
*fops
;
1120 {"mbox", S_IRUGO
, &fops_mbox
},
1121 {"vrings", S_IRUGO
, &fops_vring
},
1122 {"stations", S_IRUGO
, &fops_sta
},
1123 {"desc", S_IRUGO
, &fops_txdesc
},
1124 {"bf", S_IRUGO
, &fops_bf
},
1125 {"ssid", S_IRUGO
| S_IWUSR
, &fops_ssid
},
1126 {"mem_val", S_IRUGO
, &fops_memread
},
1127 {"reset", S_IWUSR
, &fops_reset
},
1128 {"rxon", S_IWUSR
, &fops_rxon
},
1129 {"tx_mgmt", S_IWUSR
, &fops_txmgmt
},
1130 {"wmi_send", S_IWUSR
, &fops_wmi
},
1131 {"temp", S_IRUGO
, &fops_temp
},
1132 {"freq", S_IRUGO
, &fops_freq
},
1133 {"link", S_IRUGO
, &fops_link
},
1134 {"info", S_IRUGO
, &fops_info
},
1137 static void wil6210_debugfs_init_files(struct wil6210_priv
*wil
,
1142 for (i
= 0; i
< ARRAY_SIZE(dbg_files
); i
++)
1143 debugfs_create_file(dbg_files
[i
].name
, dbg_files
[i
].mode
, dbg
,
1144 wil
, dbg_files
[i
].fops
);
1147 /* interrupt control blocks */
1148 static const struct {
1152 {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR
)},
1153 {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR
)},
1154 {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR
)},
1155 {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR
)},
1158 static void wil6210_debugfs_init_isr(struct wil6210_priv
*wil
,
1163 for (i
= 0; i
< ARRAY_SIZE(dbg_icr
); i
++)
1164 wil6210_debugfs_create_ISR(wil
, dbg_icr
[i
].name
, dbg
,
1165 dbg_icr
[i
].icr_off
);
1168 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
1169 offsetof(struct wil6210_priv, name), type}
1171 /* fields in struct wil6210_priv */
1172 static const struct dbg_off dbg_wil_off
[] = {
1173 WIL_FIELD(secure_pcp
, S_IRUGO
| S_IWUSR
, doff_u32
),
1174 WIL_FIELD(status
, S_IRUGO
| S_IWUSR
, doff_ulong
),
1175 WIL_FIELD(fw_version
, S_IRUGO
, doff_u32
),
1176 WIL_FIELD(hw_version
, S_IRUGO
, doff_x32
),
1180 static const struct dbg_off dbg_wil_regs
[] = {
1181 {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO
, HOSTADDR(RGF_MAC_MTRL_COUNTER_0
),
1183 {"RGF_USER_USAGE_1", S_IRUGO
, HOSTADDR(RGF_USER_USAGE_1
), doff_io32
},
1187 /* static parameters */
1188 static const struct dbg_off dbg_statics
[] = {
1189 {"desc_index", S_IRUGO
| S_IWUSR
, (ulong
)&dbg_txdesc_index
, doff_u32
},
1190 {"vring_index", S_IRUGO
| S_IWUSR
, (ulong
)&dbg_vring_index
, doff_u32
},
1191 {"mem_addr", S_IRUGO
| S_IWUSR
, (ulong
)&mem_addr
, doff_u32
},
1195 int wil6210_debugfs_init(struct wil6210_priv
*wil
)
1197 struct dentry
*dbg
= wil
->debug
= debugfs_create_dir(WIL_NAME
,
1198 wil_to_wiphy(wil
)->debugfsdir
);
1200 if (IS_ERR_OR_NULL(dbg
))
1203 wil6210_debugfs_init_files(wil
, dbg
);
1204 wil6210_debugfs_init_isr(wil
, dbg
);
1205 wil6210_debugfs_init_blobs(wil
, dbg
);
1206 wil6210_debugfs_init_offset(wil
, dbg
, wil
, dbg_wil_off
);
1207 wil6210_debugfs_init_offset(wil
, dbg
, (void * __force
)wil
->csr
,
1209 wil6210_debugfs_init_offset(wil
, dbg
, NULL
, dbg_statics
);
1211 wil6210_debugfs_create_pseudo_ISR(wil
, dbg
);
1213 wil6210_debugfs_create_ITR_CNT(wil
, dbg
);
1218 void wil6210_debugfs_remove(struct wil6210_priv
*wil
)
1220 debugfs_remove_recursive(wil
->debug
);