2 * Copyright (c) 2012 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>
26 /* Nasty hack. Better have per device instances */
28 static u32 dbg_txdesc_index
;
30 static void wil_print_vring(struct seq_file
*s
, struct wil6210_priv
*wil
,
31 const char *name
, struct vring
*vring
)
33 void __iomem
*x
= wmi_addr(wil
, vring
->hwtail
);
35 seq_printf(s
, "VRING %s = {\n", name
);
36 seq_printf(s
, " pa = 0x%016llx\n", (unsigned long long)vring
->pa
);
37 seq_printf(s
, " va = 0x%p\n", vring
->va
);
38 seq_printf(s
, " size = %d\n", vring
->size
);
39 seq_printf(s
, " swtail = %d\n", vring
->swtail
);
40 seq_printf(s
, " swhead = %d\n", vring
->swhead
);
41 seq_printf(s
, " hwtail = [0x%08x] -> ", vring
->hwtail
);
43 seq_printf(s
, "0x%08x\n", ioread32(x
));
45 seq_printf(s
, "???\n");
47 if (vring
->va
&& (vring
->size
< 1025)) {
49 for (i
= 0; i
< vring
->size
; i
++) {
50 volatile struct vring_tx_desc
*d
= &vring
->va
[i
].tx
;
51 if ((i
% 64) == 0 && (i
!= 0))
53 seq_printf(s
, "%s", (d
->dma
.status
& BIT(0)) ?
54 "S" : (vring
->ctx
[i
].skb
? "H" : "h"));
61 static int wil_vring_debugfs_show(struct seq_file
*s
, void *data
)
64 struct wil6210_priv
*wil
= s
->private;
66 wil_print_vring(s
, wil
, "rx", &wil
->vring_rx
);
68 for (i
= 0; i
< ARRAY_SIZE(wil
->vring_tx
); i
++) {
69 struct vring
*vring
= &(wil
->vring_tx
[i
]);
72 snprintf(name
, sizeof(name
), "tx_%2d", i
);
73 wil_print_vring(s
, wil
, name
, vring
);
80 static int wil_vring_seq_open(struct inode
*inode
, struct file
*file
)
82 return single_open(file
, wil_vring_debugfs_show
, inode
->i_private
);
85 static const struct file_operations fops_vring
= {
86 .open
= wil_vring_seq_open
,
87 .release
= single_release
,
92 static void wil_print_ring(struct seq_file
*s
, const char *prefix
,
95 struct wil6210_priv
*wil
= s
->private;
96 struct wil6210_mbox_ring r
;
100 wil_memcpy_fromio_32(&r
, off
, sizeof(r
));
101 wil_mbox_ring_le2cpus(&r
);
103 * we just read memory block from NIC. This memory may be
104 * garbage. Check validity before using it.
106 rsize
= r
.size
/ sizeof(struct wil6210_mbox_ring_desc
);
108 seq_printf(s
, "ring %s = {\n", prefix
);
109 seq_printf(s
, " base = 0x%08x\n", r
.base
);
110 seq_printf(s
, " size = 0x%04x bytes -> %d entries\n", r
.size
, rsize
);
111 seq_printf(s
, " tail = 0x%08x\n", r
.tail
);
112 seq_printf(s
, " head = 0x%08x\n", r
.head
);
113 seq_printf(s
, " entry size = %d\n", r
.entry_size
);
115 if (r
.size
% sizeof(struct wil6210_mbox_ring_desc
)) {
116 seq_printf(s
, " ??? size is not multiple of %zd, garbage?\n",
117 sizeof(struct wil6210_mbox_ring_desc
));
121 if (!wmi_addr(wil
, r
.base
) ||
122 !wmi_addr(wil
, r
.tail
) ||
123 !wmi_addr(wil
, r
.head
)) {
124 seq_printf(s
, " ??? pointers are garbage?\n");
128 for (i
= 0; i
< rsize
; i
++) {
129 struct wil6210_mbox_ring_desc d
;
130 struct wil6210_mbox_hdr hdr
;
131 size_t delta
= i
* sizeof(d
);
132 void __iomem
*x
= wil
->csr
+ HOSTADDR(r
.base
) + delta
;
134 wil_memcpy_fromio_32(&d
, x
, sizeof(d
));
136 seq_printf(s
, " [%2x] %s %s%s 0x%08x", i
,
138 (r
.tail
- r
.base
== delta
) ? "t" : " ",
139 (r
.head
- r
.base
== delta
) ? "h" : " ",
140 le32_to_cpu(d
.addr
));
141 if (0 == wmi_read_hdr(wil
, d
.addr
, &hdr
)) {
142 u16 len
= le16_to_cpu(hdr
.len
);
143 seq_printf(s
, " -> %04x %04x %04x %02x\n",
144 le16_to_cpu(hdr
.seq
), len
,
145 le16_to_cpu(hdr
.type
), hdr
.flags
);
146 if (len
<= MAX_MBOXITEM_SIZE
) {
148 char printbuf
[16 * 3 + 2];
149 unsigned char databuf
[MAX_MBOXITEM_SIZE
];
150 void __iomem
*src
= wmi_buffer(wil
, d
.addr
) +
151 sizeof(struct wil6210_mbox_hdr
);
153 * No need to check @src for validity -
154 * we already validated @d.addr while
157 wil_memcpy_fromio_32(databuf
, src
, len
);
159 int l
= min(len
- n
, 16);
160 hex_dump_to_buffer(databuf
+ n
, l
,
164 seq_printf(s
, " : %s\n", printbuf
);
173 seq_printf(s
, "}\n");
176 static int wil_mbox_debugfs_show(struct seq_file
*s
, void *data
)
178 struct wil6210_priv
*wil
= s
->private;
180 wil_print_ring(s
, "tx", wil
->csr
+ HOST_MBOX
+
181 offsetof(struct wil6210_mbox_ctl
, tx
));
182 wil_print_ring(s
, "rx", wil
->csr
+ HOST_MBOX
+
183 offsetof(struct wil6210_mbox_ctl
, rx
));
188 static int wil_mbox_seq_open(struct inode
*inode
, struct file
*file
)
190 return single_open(file
, wil_mbox_debugfs_show
, inode
->i_private
);
193 static const struct file_operations fops_mbox
= {
194 .open
= wil_mbox_seq_open
,
195 .release
= single_release
,
200 static int wil_debugfs_iomem_x32_set(void *data
, u64 val
)
202 iowrite32(val
, (void __iomem
*)data
);
203 wmb(); /* make sure write propagated to HW */
208 static int wil_debugfs_iomem_x32_get(void *data
, u64
*val
)
210 *val
= ioread32((void __iomem
*)data
);
215 DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32
, wil_debugfs_iomem_x32_get
,
216 wil_debugfs_iomem_x32_set
, "0x%08llx\n");
218 static struct dentry
*wil_debugfs_create_iomem_x32(const char *name
,
220 struct dentry
*parent
,
223 return debugfs_create_file(name
, mode
, parent
, (void * __force
)value
,
227 static int wil6210_debugfs_create_ISR(struct wil6210_priv
*wil
,
229 struct dentry
*parent
, u32 off
)
231 struct dentry
*d
= debugfs_create_dir(name
, parent
);
233 if (IS_ERR_OR_NULL(d
))
236 wil_debugfs_create_iomem_x32("ICC", S_IRUGO
| S_IWUSR
, d
,
238 wil_debugfs_create_iomem_x32("ICR", S_IRUGO
| S_IWUSR
, d
,
240 wil_debugfs_create_iomem_x32("ICM", S_IRUGO
| S_IWUSR
, d
,
242 wil_debugfs_create_iomem_x32("ICS", S_IWUSR
, d
,
243 wil
->csr
+ off
+ 12);
244 wil_debugfs_create_iomem_x32("IMV", S_IRUGO
| S_IWUSR
, d
,
245 wil
->csr
+ off
+ 16);
246 wil_debugfs_create_iomem_x32("IMS", S_IWUSR
, d
,
247 wil
->csr
+ off
+ 20);
248 wil_debugfs_create_iomem_x32("IMC", S_IWUSR
, d
,
249 wil
->csr
+ off
+ 24);
254 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv
*wil
,
255 struct dentry
*parent
)
257 struct dentry
*d
= debugfs_create_dir("PSEUDO_ISR", parent
);
259 if (IS_ERR_OR_NULL(d
))
262 wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO
, d
, wil
->csr
+
263 HOSTADDR(RGF_DMA_PSEUDO_CAUSE
));
264 wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO
, d
, wil
->csr
+
265 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW
));
266 wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO
, d
, wil
->csr
+
267 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW
));
272 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv
*wil
,
273 struct dentry
*parent
)
275 struct dentry
*d
= debugfs_create_dir("ITR_CNT", parent
);
277 if (IS_ERR_OR_NULL(d
))
280 wil_debugfs_create_iomem_x32("TRSH", S_IRUGO
, d
, wil
->csr
+
281 HOSTADDR(RGF_DMA_ITR_CNT_TRSH
));
282 wil_debugfs_create_iomem_x32("DATA", S_IRUGO
, d
, wil
->csr
+
283 HOSTADDR(RGF_DMA_ITR_CNT_DATA
));
284 wil_debugfs_create_iomem_x32("CTL", S_IRUGO
, d
, wil
->csr
+
285 HOSTADDR(RGF_DMA_ITR_CNT_CRL
));
290 static int wil_memread_debugfs_show(struct seq_file
*s
, void *data
)
292 struct wil6210_priv
*wil
= s
->private;
293 void __iomem
*a
= wmi_buffer(wil
, cpu_to_le32(mem_addr
));
296 seq_printf(s
, "[0x%08x] = 0x%08x\n", mem_addr
, ioread32(a
));
298 seq_printf(s
, "[0x%08x] = INVALID\n", mem_addr
);
303 static int wil_memread_seq_open(struct inode
*inode
, struct file
*file
)
305 return single_open(file
, wil_memread_debugfs_show
, inode
->i_private
);
308 static const struct file_operations fops_memread
= {
309 .open
= wil_memread_seq_open
,
310 .release
= single_release
,
315 static ssize_t
wil_read_file_ioblob(struct file
*file
, char __user
*user_buf
,
316 size_t count
, loff_t
*ppos
)
318 enum { max_count
= 4096 };
319 struct debugfs_blob_wrapper
*blob
= file
->private_data
;
321 size_t available
= blob
->size
;
328 if (pos
>= available
|| !count
)
331 if (count
> available
- pos
)
332 count
= available
- pos
;
333 if (count
> max_count
)
336 buf
= kmalloc(count
, GFP_KERNEL
);
340 wil_memcpy_fromio_32(buf
, (const volatile void __iomem
*)blob
->data
+
343 ret
= copy_to_user(user_buf
, buf
, count
);
354 static const struct file_operations fops_ioblob
= {
355 .read
= wil_read_file_ioblob
,
357 .llseek
= default_llseek
,
361 struct dentry
*wil_debugfs_create_ioblob(const char *name
,
363 struct dentry
*parent
,
364 struct debugfs_blob_wrapper
*blob
)
366 return debugfs_create_file(name
, mode
, parent
, blob
, &fops_ioblob
);
369 static ssize_t
wil_write_file_reset(struct file
*file
, const char __user
*buf
,
370 size_t len
, loff_t
*ppos
)
372 struct wil6210_priv
*wil
= file
->private_data
;
373 struct net_device
*ndev
= wil_to_ndev(wil
);
377 * this code does NOT sync device state with the rest of system
378 * use with care, debug only!!!
382 ndev
->flags
&= ~IFF_UP
;
389 static const struct file_operations fops_reset
= {
390 .write
= wil_write_file_reset
,
393 /*---------Tx descriptor------------*/
395 static int wil_txdesc_debugfs_show(struct seq_file
*s
, void *data
)
397 struct wil6210_priv
*wil
= s
->private;
398 struct vring
*vring
= &(wil
->vring_tx
[0]);
401 seq_printf(s
, "No Tx VRING\n");
405 if (dbg_txdesc_index
< vring
->size
) {
406 volatile struct vring_tx_desc
*d
=
407 &(vring
->va
[dbg_txdesc_index
].tx
);
408 volatile u32
*u
= (volatile u32
*)d
;
409 struct sk_buff
*skb
= vring
->ctx
[dbg_txdesc_index
].skb
;
411 seq_printf(s
, "Tx[%3d] = {\n", dbg_txdesc_index
);
412 seq_printf(s
, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
413 u
[0], u
[1], u
[2], u
[3]);
414 seq_printf(s
, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
415 u
[4], u
[5], u
[6], u
[7]);
416 seq_printf(s
, " SKB = %p\n", skb
);
419 char printbuf
[16 * 3 + 2];
421 int len
= le16_to_cpu(d
->dma
.length
);
424 if (len
!= skb_headlen(skb
)) {
425 seq_printf(s
, "!!! len: desc = %d skb = %d\n",
426 len
, skb_headlen(skb
));
427 len
= min_t(int, len
, skb_headlen(skb
));
430 seq_printf(s
, " len = %d\n", len
);
433 int l
= min(len
- i
, 16);
434 hex_dump_to_buffer(p
+ i
, l
, 16, 1, printbuf
,
435 sizeof(printbuf
), false);
436 seq_printf(s
, " : %s\n", printbuf
);
440 seq_printf(s
, "}\n");
442 seq_printf(s
, "TxDesc index (%d) >= size (%d)\n",
443 dbg_txdesc_index
, vring
->size
);
449 static int wil_txdesc_seq_open(struct inode
*inode
, struct file
*file
)
451 return single_open(file
, wil_txdesc_debugfs_show
, inode
->i_private
);
454 static const struct file_operations fops_txdesc
= {
455 .open
= wil_txdesc_seq_open
,
456 .release
= single_release
,
461 /*---------beamforming------------*/
462 static int wil_bf_debugfs_show(struct seq_file
*s
, void *data
)
464 struct wil6210_priv
*wil
= s
->private;
468 "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n",
469 wil
->stats
.tsf
, wil
->stats
.bf_mcs
,
470 wil
->stats
.my_rx_sector
, wil
->stats
.my_tx_sector
,
471 wil
->stats
.peer_rx_sector
, wil
->stats
.peer_tx_sector
);
475 static int wil_bf_seq_open(struct inode
*inode
, struct file
*file
)
477 return single_open(file
, wil_bf_debugfs_show
, inode
->i_private
);
480 static const struct file_operations fops_bf
= {
481 .open
= wil_bf_seq_open
,
482 .release
= single_release
,
486 /*---------SSID------------*/
487 static ssize_t
wil_read_file_ssid(struct file
*file
, char __user
*user_buf
,
488 size_t count
, loff_t
*ppos
)
490 struct wil6210_priv
*wil
= file
->private_data
;
491 struct wireless_dev
*wdev
= wil_to_wdev(wil
);
493 return simple_read_from_buffer(user_buf
, count
, ppos
,
494 wdev
->ssid
, wdev
->ssid_len
);
497 static ssize_t
wil_write_file_ssid(struct file
*file
, const char __user
*buf
,
498 size_t count
, loff_t
*ppos
)
500 struct wil6210_priv
*wil
= file
->private_data
;
501 struct wireless_dev
*wdev
= wil_to_wdev(wil
);
502 struct net_device
*ndev
= wil_to_ndev(wil
);
505 wil_err(wil
, "Unable to set SSID substring from [%d]\n",
510 if (count
> sizeof(wdev
->ssid
)) {
511 wil_err(wil
, "SSID too long, len = %d\n", (int)count
);
514 if (netif_running(ndev
)) {
515 wil_err(wil
, "Unable to change SSID on running interface\n");
519 wdev
->ssid_len
= count
;
520 return simple_write_to_buffer(wdev
->ssid
, wdev
->ssid_len
, ppos
,
524 static const struct file_operations fops_ssid
= {
525 .read
= wil_read_file_ssid
,
526 .write
= wil_write_file_ssid
,
530 /*---------temp------------*/
531 static void print_temp(struct seq_file
*s
, const char *prefix
, u32 t
)
536 seq_printf(s
, "%s N/A\n", prefix
);
539 seq_printf(s
, "%s %d.%03d\n", prefix
, t
/ 1000, t
% 1000);
544 static int wil_temp_debugfs_show(struct seq_file
*s
, void *data
)
546 struct wil6210_priv
*wil
= s
->private;
549 int rc
= wmi_get_temperature(wil
, &t_m
, &t_r
);
551 seq_printf(s
, "Failed\n");
555 print_temp(s
, "MAC temperature :", t_m
);
556 print_temp(s
, "Radio temperature :", t_r
);
561 static int wil_temp_seq_open(struct inode
*inode
, struct file
*file
)
563 return single_open(file
, wil_temp_debugfs_show
, inode
->i_private
);
566 static const struct file_operations fops_temp
= {
567 .open
= wil_temp_seq_open
,
568 .release
= single_release
,
574 int wil6210_debugfs_init(struct wil6210_priv
*wil
)
576 struct dentry
*dbg
= wil
->debug
= debugfs_create_dir(WIL_NAME
,
577 wil_to_wiphy(wil
)->debugfsdir
);
579 if (IS_ERR_OR_NULL(dbg
))
582 debugfs_create_file("mbox", S_IRUGO
, dbg
, wil
, &fops_mbox
);
583 debugfs_create_file("vrings", S_IRUGO
, dbg
, wil
, &fops_vring
);
584 debugfs_create_file("txdesc", S_IRUGO
, dbg
, wil
, &fops_txdesc
);
585 debugfs_create_u32("txdesc_index", S_IRUGO
| S_IWUSR
, dbg
,
587 debugfs_create_file("bf", S_IRUGO
, dbg
, wil
, &fops_bf
);
588 debugfs_create_file("ssid", S_IRUGO
| S_IWUSR
, dbg
, wil
, &fops_ssid
);
589 debugfs_create_u32("secure_pcp", S_IRUGO
| S_IWUSR
, dbg
,
592 wil6210_debugfs_create_ISR(wil
, "USER_ICR", dbg
,
593 HOSTADDR(RGF_USER_USER_ICR
));
594 wil6210_debugfs_create_ISR(wil
, "DMA_EP_TX_ICR", dbg
,
595 HOSTADDR(RGF_DMA_EP_TX_ICR
));
596 wil6210_debugfs_create_ISR(wil
, "DMA_EP_RX_ICR", dbg
,
597 HOSTADDR(RGF_DMA_EP_RX_ICR
));
598 wil6210_debugfs_create_ISR(wil
, "DMA_EP_MISC_ICR", dbg
,
599 HOSTADDR(RGF_DMA_EP_MISC_ICR
));
600 wil6210_debugfs_create_pseudo_ISR(wil
, dbg
);
601 wil6210_debugfs_create_ITR_CNT(wil
, dbg
);
603 debugfs_create_u32("mem_addr", S_IRUGO
| S_IWUSR
, dbg
, &mem_addr
);
604 debugfs_create_file("mem_val", S_IRUGO
, dbg
, wil
, &fops_memread
);
606 debugfs_create_file("reset", S_IWUSR
, dbg
, wil
, &fops_reset
);
607 debugfs_create_file("temp", S_IRUGO
, dbg
, wil
, &fops_temp
);
609 wil
->rgf_blob
.data
= (void * __force
)wil
->csr
+ 0;
610 wil
->rgf_blob
.size
= 0xa000;
611 wil_debugfs_create_ioblob("blob_rgf", S_IRUGO
, dbg
, &wil
->rgf_blob
);
613 wil
->fw_code_blob
.data
= (void * __force
)wil
->csr
+ 0x40000;
614 wil
->fw_code_blob
.size
= 0x40000;
615 wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO
, dbg
,
618 wil
->fw_data_blob
.data
= (void * __force
)wil
->csr
+ 0x80000;
619 wil
->fw_data_blob
.size
= 0x8000;
620 wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO
, dbg
,
623 wil
->fw_peri_blob
.data
= (void * __force
)wil
->csr
+ 0x88000;
624 wil
->fw_peri_blob
.size
= 0x18000;
625 wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO
, dbg
,
628 wil
->uc_code_blob
.data
= (void * __force
)wil
->csr
+ 0xa0000;
629 wil
->uc_code_blob
.size
= 0x10000;
630 wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO
, dbg
,
633 wil
->uc_data_blob
.data
= (void * __force
)wil
->csr
+ 0xb0000;
634 wil
->uc_data_blob
.size
= 0x4000;
635 wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO
, dbg
,
641 void wil6210_debugfs_remove(struct wil6210_priv
*wil
)
643 debugfs_remove_recursive(wil
->debug
);