1/*
2 * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
3 *
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.
7 *
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.
15 */
16
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>
23
24#include "wil6210.h"
25#include "wmi.h"
26#include "txrx.h"
27
28/* Nasty hack. Better have per device instances */
29static u32 mem_addr;
30static u32 dbg_txdesc_index;
31static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
32u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */
33
34enum dbg_off_type {
35	doff_u32 = 0,
36	doff_x32 = 1,
37	doff_ulong = 2,
38	doff_io32 = 3,
39};
40
41/* offset to "wil" */
42struct dbg_off {
43	const char *name;
44	umode_t mode;
45	ulong off;
46	enum dbg_off_type type;
47};
48
49static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
50			    const char *name, struct vring *vring,
51			    char _s, char _h)
52{
53	void __iomem *x = wmi_addr(wil, vring->hwtail);
54	u32 v;
55
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);
63	if (x) {
64		v = ioread32(x);
65		seq_printf(s, "0x%08x = %d\n", v, v);
66	} else {
67		seq_puts(s, "???\n");
68	}
69
70	if (vring->va && (vring->size < 1025)) {
71		uint i;
72
73		for (i = 0; i < vring->size; i++) {
74			volatile struct vring_tx_desc *d = &vring->va[i].tx;
75
76			if ((i % 64) == 0 && (i != 0))
77				seq_puts(s, "\n");
78			seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
79					_s : (vring->ctx[i].skb ? _h : 'h'));
80		}
81		seq_puts(s, "\n");
82	}
83	seq_puts(s, "}\n");
84}
85
86static int wil_vring_debugfs_show(struct seq_file *s, void *data)
87{
88	uint i;
89	struct wil6210_priv *wil = s->private;
90
91	wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
92
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];
96
97		if (vring->va) {
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)
103				   % vring->size;
104			int avail = vring->size - used - 1;
105			char name[10];
106			char sidle[10];
107			/* performance monitoring */
108			cycles_t now = get_cycles();
109			uint64_t idle = txdata->idle * 100;
110			uint64_t total = now - txdata->begin;
111
112			if (total != 0) {
113				do_div(idle, total);
114				snprintf(sidle, sizeof(sidle), "%3d%%",
115					 (int)idle);
116			} else {
117				snprintf(sidle, sizeof(sidle), "N/A");
118			}
119			txdata->begin = now;
120			txdata->idle = 0ULL;
121
122			snprintf(name, sizeof(name), "tx_%2d", i);
123
124			if (cid < WIL6210_MAX_CID)
125				seq_printf(s,
126					   "\n%pM CID %d TID %d BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
127					   wil->sta[cid].addr, cid, tid,
128					   txdata->agg_wsize,
129					   txdata->agg_timeout,
130					   txdata->agg_amsdu ? "+" : "-",
131					   used, avail, sidle);
132			else
133				seq_printf(s,
134					   "\nBroadcast [%3d|%3d] idle %s\n",
135					   used, avail, sidle);
136
137			wil_print_vring(s, wil, name, vring, '_', 'H');
138		}
139	}
140
141	return 0;
142}
143
144static int wil_vring_seq_open(struct inode *inode, struct file *file)
145{
146	return single_open(file, wil_vring_debugfs_show, inode->i_private);
147}
148
149static const struct file_operations fops_vring = {
150	.open		= wil_vring_seq_open,
151	.release	= single_release,
152	.read		= seq_read,
153	.llseek		= seq_lseek,
154};
155
156static void wil_print_ring(struct seq_file *s, const char *prefix,
157			   void __iomem *off)
158{
159	struct wil6210_priv *wil = s->private;
160	struct wil6210_mbox_ring r;
161	int rsize;
162	uint i;
163
164	wil_memcpy_fromio_32(&r, off, sizeof(r));
165	wil_mbox_ring_le2cpus(&r);
166	/*
167	 * we just read memory block from NIC. This memory may be
168	 * garbage. Check validity before using it.
169	 */
170	rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
171
172	seq_printf(s, "ring %s = {\n", prefix);
173	seq_printf(s, "  base = 0x%08x\n", r.base);
174	seq_printf(s, "  size = 0x%04x bytes -> %d entries\n", r.size, rsize);
175	seq_printf(s, "  tail = 0x%08x\n", r.tail);
176	seq_printf(s, "  head = 0x%08x\n", r.head);
177	seq_printf(s, "  entry size = %d\n", r.entry_size);
178
179	if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
180		seq_printf(s, "  ??? size is not multiple of %zd, garbage?\n",
181			   sizeof(struct wil6210_mbox_ring_desc));
182		goto out;
183	}
184
185	if (!wmi_addr(wil, r.base) ||
186	    !wmi_addr(wil, r.tail) ||
187	    !wmi_addr(wil, r.head)) {
188		seq_puts(s, "  ??? pointers are garbage?\n");
189		goto out;
190	}
191
192	for (i = 0; i < rsize; i++) {
193		struct wil6210_mbox_ring_desc d;
194		struct wil6210_mbox_hdr hdr;
195		size_t delta = i * sizeof(d);
196		void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
197
198		wil_memcpy_fromio_32(&d, x, sizeof(d));
199
200		seq_printf(s, "  [%2x] %s %s%s 0x%08x", i,
201			   d.sync ? "F" : "E",
202			   (r.tail - r.base == delta) ? "t" : " ",
203			   (r.head - r.base == delta) ? "h" : " ",
204			   le32_to_cpu(d.addr));
205		if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
206			u16 len = le16_to_cpu(hdr.len);
207
208			seq_printf(s, " -> %04x %04x %04x %02x\n",
209				   le16_to_cpu(hdr.seq), len,
210				   le16_to_cpu(hdr.type), hdr.flags);
211			if (len <= MAX_MBOXITEM_SIZE) {
212				int n = 0;
213				char printbuf[16 * 3 + 2];
214				unsigned char databuf[MAX_MBOXITEM_SIZE];
215				void __iomem *src = wmi_buffer(wil, d.addr) +
216					sizeof(struct wil6210_mbox_hdr);
217				/*
218				 * No need to check @src for validity -
219				 * we already validated @d.addr while
220				 * reading header
221				 */
222				wil_memcpy_fromio_32(databuf, src, len);
223				while (n < len) {
224					int l = min(len - n, 16);
225
226					hex_dump_to_buffer(databuf + n, l,
227							   16, 1, printbuf,
228							   sizeof(printbuf),
229							   false);
230					seq_printf(s, "      : %s\n", printbuf);
231					n += l;
232				}
233			}
234		} else {
235			seq_puts(s, "\n");
236		}
237	}
238 out:
239	seq_puts(s, "}\n");
240}
241
242static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
243{
244	struct wil6210_priv *wil = s->private;
245
246	wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
247		       offsetof(struct wil6210_mbox_ctl, tx));
248	wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
249		       offsetof(struct wil6210_mbox_ctl, rx));
250
251	return 0;
252}
253
254static int wil_mbox_seq_open(struct inode *inode, struct file *file)
255{
256	return single_open(file, wil_mbox_debugfs_show, inode->i_private);
257}
258
259static const struct file_operations fops_mbox = {
260	.open		= wil_mbox_seq_open,
261	.release	= single_release,
262	.read		= seq_read,
263	.llseek		= seq_lseek,
264};
265
266static int wil_debugfs_iomem_x32_set(void *data, u64 val)
267{
268	iowrite32(val, (void __iomem *)data);
269	wmb(); /* make sure write propagated to HW */
270
271	return 0;
272}
273
274static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
275{
276	*val = ioread32((void __iomem *)data);
277
278	return 0;
279}
280
281DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
282			wil_debugfs_iomem_x32_set, "0x%08llx\n");
283
284static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
285						   umode_t mode,
286						   struct dentry *parent,
287						   void *value)
288{
289	return debugfs_create_file(name, mode, parent, value,
290				   &fops_iomem_x32);
291}
292
293static int wil_debugfs_ulong_set(void *data, u64 val)
294{
295	*(ulong *)data = val;
296	return 0;
297}
298
299static int wil_debugfs_ulong_get(void *data, u64 *val)
300{
301	*val = *(ulong *)data;
302	return 0;
303}
304
305DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
306			wil_debugfs_ulong_set, "%llu\n");
307
308static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
309					       struct dentry *parent,
310					       ulong *value)
311{
312	return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
313}
314
315/**
316 * wil6210_debugfs_init_offset - create set of debugfs files
317 * @wil - driver's context, used for printing
318 * @dbg - directory on the debugfs, where files will be created
319 * @base - base address used in address calculation
320 * @tbl - table with file descriptions. Should be terminated with empty element.
321 *
322 * Creates files accordingly to the @tbl.
323 */
324static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
325					struct dentry *dbg, void *base,
326					const struct dbg_off * const tbl)
327{
328	int i;
329
330	for (i = 0; tbl[i].name; i++) {
331		struct dentry *f;
332
333		switch (tbl[i].type) {
334		case doff_u32:
335			f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
336					       base + tbl[i].off);
337			break;
338		case doff_x32:
339			f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
340					       base + tbl[i].off);
341			break;
342		case doff_ulong:
343			f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
344						     dbg, base + tbl[i].off);
345			break;
346		case doff_io32:
347			f = wil_debugfs_create_iomem_x32(tbl[i].name,
348							 tbl[i].mode, dbg,
349							 base + tbl[i].off);
350			break;
351		default:
352			f = ERR_PTR(-EINVAL);
353		}
354		if (IS_ERR_OR_NULL(f))
355			wil_err(wil, "Create file \"%s\": err %ld\n",
356				tbl[i].name, PTR_ERR(f));
357	}
358}
359
360static const struct dbg_off isr_off[] = {
361	{"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
362	{"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
363	{"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
364	{"ICS",		  S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
365	{"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
366	{"IMS",		  S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
367	{"IMC",		  S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
368	{},
369};
370
371static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
372				      const char *name,
373				      struct dentry *parent, u32 off)
374{
375	struct dentry *d = debugfs_create_dir(name, parent);
376
377	if (IS_ERR_OR_NULL(d))
378		return -ENODEV;
379
380	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
381				    isr_off);
382
383	return 0;
384}
385
386static const struct dbg_off pseudo_isr_off[] = {
387	{"CAUSE",   S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
388	{"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
389	{"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
390	{},
391};
392
393static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
394					     struct dentry *parent)
395{
396	struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
397
398	if (IS_ERR_OR_NULL(d))
399		return -ENODEV;
400
401	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
402				    pseudo_isr_off);
403
404	return 0;
405}
406
407static const struct dbg_off lgc_itr_cnt_off[] = {
408	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
409	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
410	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
411	{},
412};
413
414static const struct dbg_off tx_itr_cnt_off[] = {
415	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
416	 doff_io32},
417	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
418	 doff_io32},
419	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
420	 doff_io32},
421	{"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
422	 doff_io32},
423	{"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
424	 doff_io32},
425	{"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
426	 doff_io32},
427	{},
428};
429
430static const struct dbg_off rx_itr_cnt_off[] = {
431	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
432	 doff_io32},
433	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
434	 doff_io32},
435	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
436	 doff_io32},
437	{"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
438	 doff_io32},
439	{"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
440	 doff_io32},
441	{"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
442	 doff_io32},
443	{},
444};
445
446static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
447					  struct dentry *parent)
448{
449	struct dentry *d, *dtx, *drx;
450
451	d = debugfs_create_dir("ITR_CNT", parent);
452	if (IS_ERR_OR_NULL(d))
453		return -ENODEV;
454
455	dtx = debugfs_create_dir("TX", d);
456	drx = debugfs_create_dir("RX", d);
457	if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
458		return -ENODEV;
459
460	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
461				    lgc_itr_cnt_off);
462
463	wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
464				    tx_itr_cnt_off);
465
466	wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
467				    rx_itr_cnt_off);
468	return 0;
469}
470
471static int wil_memread_debugfs_show(struct seq_file *s, void *data)
472{
473	struct wil6210_priv *wil = s->private;
474	void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
475
476	if (a)
477		seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a));
478	else
479		seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
480
481	return 0;
482}
483
484static int wil_memread_seq_open(struct inode *inode, struct file *file)
485{
486	return single_open(file, wil_memread_debugfs_show, inode->i_private);
487}
488
489static const struct file_operations fops_memread = {
490	.open		= wil_memread_seq_open,
491	.release	= single_release,
492	.read		= seq_read,
493	.llseek		= seq_lseek,
494};
495
496static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
497				    size_t count, loff_t *ppos)
498{
499	enum { max_count = 4096 };
500	struct debugfs_blob_wrapper *blob = file->private_data;
501	loff_t pos = *ppos;
502	size_t available = blob->size;
503	void *buf;
504	size_t ret;
505
506	if (pos < 0)
507		return -EINVAL;
508
509	if (pos >= available || !count)
510		return 0;
511
512	if (count > available - pos)
513		count = available - pos;
514	if (count > max_count)
515		count = max_count;
516
517	buf = kmalloc(count, GFP_KERNEL);
518	if (!buf)
519		return -ENOMEM;
520
521	wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data +
522			     pos, count);
523
524	ret = copy_to_user(user_buf, buf, count);
525	kfree(buf);
526	if (ret == count)
527		return -EFAULT;
528
529	count -= ret;
530	*ppos = pos + count;
531
532	return count;
533}
534
535static const struct file_operations fops_ioblob = {
536	.read =		wil_read_file_ioblob,
537	.open =		simple_open,
538	.llseek =	default_llseek,
539};
540
541static
542struct dentry *wil_debugfs_create_ioblob(const char *name,
543					 umode_t mode,
544					 struct dentry *parent,
545					 struct debugfs_blob_wrapper *blob)
546{
547	return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
548}
549
550/*---reset---*/
551static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
552				    size_t len, loff_t *ppos)
553{
554	struct wil6210_priv *wil = file->private_data;
555	struct net_device *ndev = wil_to_ndev(wil);
556
557	/**
558	 * BUG:
559	 * this code does NOT sync device state with the rest of system
560	 * use with care, debug only!!!
561	 */
562	rtnl_lock();
563	dev_close(ndev);
564	ndev->flags &= ~IFF_UP;
565	rtnl_unlock();
566	wil_reset(wil, true);
567
568	return len;
569}
570
571static const struct file_operations fops_reset = {
572	.write = wil_write_file_reset,
573	.open  = simple_open,
574};
575
576/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
577static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
578				   size_t len, loff_t *ppos)
579{
580	struct wil6210_priv *wil = file->private_data;
581	int rc;
582	long channel;
583	bool on;
584
585	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
586
587	if (!kbuf)
588		return -ENOMEM;
589	if (copy_from_user(kbuf, buf, len)) {
590		kfree(kbuf);
591		return -EIO;
592	}
593
594	kbuf[len] = '\0';
595	rc = kstrtol(kbuf, 0, &channel);
596	kfree(kbuf);
597	if (rc)
598		return rc;
599
600	if ((channel < 0) || (channel > 4)) {
601		wil_err(wil, "Invalid channel %ld\n", channel);
602		return -EINVAL;
603	}
604	on = !!channel;
605
606	if (on) {
607		rc = wmi_set_channel(wil, (int)channel);
608		if (rc)
609			return rc;
610	}
611
612	rc = wmi_rxon(wil, on);
613	if (rc)
614		return rc;
615
616	return len;
617}
618
619static const struct file_operations fops_rxon = {
620	.write = wil_write_file_rxon,
621	.open  = simple_open,
622};
623
624/* block ack control, write:
625 * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
626 * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
627 * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
628 */
629static ssize_t wil_write_back(struct file *file, const char __user *buf,
630			      size_t len, loff_t *ppos)
631{
632	struct wil6210_priv *wil = file->private_data;
633	int rc;
634	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
635	char cmd[9];
636	int p1, p2, p3;
637
638	if (!kbuf)
639		return -ENOMEM;
640
641	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
642	if (rc != len) {
643		kfree(kbuf);
644		return rc >= 0 ? -EIO : rc;
645	}
646
647	kbuf[len] = '\0';
648	rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
649	kfree(kbuf);
650
651	if (rc < 0)
652		return rc;
653	if (rc < 2)
654		return -EINVAL;
655
656	if (0 == strcmp(cmd, "add")) {
657		if (rc < 3) {
658			wil_err(wil, "BACK: add require at least 2 params\n");
659			return -EINVAL;
660		}
661		if (rc < 4)
662			p3 = 0;
663		wmi_addba(wil, p1, p2, p3);
664	} else if (0 == strcmp(cmd, "del_tx")) {
665		if (rc < 3)
666			p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
667		wmi_delba_tx(wil, p1, p2);
668	} else if (0 == strcmp(cmd, "del_rx")) {
669		if (rc < 3) {
670			wil_err(wil,
671				"BACK: del_rx require at least 2 params\n");
672			return -EINVAL;
673		}
674		if (rc < 4)
675			p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
676		wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
677	} else {
678		wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
679		return -EINVAL;
680	}
681
682	return len;
683}
684
685static ssize_t wil_read_back(struct file *file, char __user *user_buf,
686			     size_t count, loff_t *ppos)
687{
688	static const char text[] = "block ack control, write:\n"
689	" - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
690	"If missing, <timeout> defaults to 0\n"
691	" - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
692	" - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
693	"If missing, <reason> set to \"STA_LEAVING\" (36)\n";
694
695	return simple_read_from_buffer(user_buf, count, ppos, text,
696				       sizeof(text));
697}
698
699static const struct file_operations fops_back = {
700	.read = wil_read_back,
701	.write = wil_write_back,
702	.open  = simple_open,
703};
704
705/*---tx_mgmt---*/
706/* Write mgmt frame to this file to send it */
707static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
708				     size_t len, loff_t *ppos)
709{
710	struct wil6210_priv *wil = file->private_data;
711	struct wiphy *wiphy = wil_to_wiphy(wil);
712	struct wireless_dev *wdev = wil_to_wdev(wil);
713	struct cfg80211_mgmt_tx_params params;
714	int rc;
715	void *frame = kmalloc(len, GFP_KERNEL);
716
717	if (!frame)
718		return -ENOMEM;
719
720	if (copy_from_user(frame, buf, len)) {
721		kfree(frame);
722		return -EIO;
723	}
724
725	params.buf = frame;
726	params.len = len;
727	params.chan = wdev->preset_chandef.chan;
728
729	rc = wil_cfg80211_mgmt_tx(wiphy, wdev, &params, NULL);
730
731	kfree(frame);
732	wil_info(wil, "%s() -> %d\n", __func__, rc);
733
734	return len;
735}
736
737static const struct file_operations fops_txmgmt = {
738	.write = wil_write_file_txmgmt,
739	.open  = simple_open,
740};
741
742/* Write WMI command (w/o mbox header) to this file to send it
743 * WMI starts from wil6210_mbox_hdr_wmi header
744 */
745static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
746				  size_t len, loff_t *ppos)
747{
748	struct wil6210_priv *wil = file->private_data;
749	struct wil6210_mbox_hdr_wmi *wmi;
750	void *cmd;
751	int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi);
752	u16 cmdid;
753	int rc, rc1;
754
755	if (cmdlen <= 0)
756		return -EINVAL;
757
758	wmi = kmalloc(len, GFP_KERNEL);
759	if (!wmi)
760		return -ENOMEM;
761
762	rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
763	if (rc < 0) {
764		kfree(wmi);
765		return rc;
766	}
767
768	cmd = &wmi[1];
769	cmdid = le16_to_cpu(wmi->id);
770
771	rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
772	kfree(wmi);
773
774	wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1);
775
776	return rc;
777}
778
779static const struct file_operations fops_wmi = {
780	.write = wil_write_file_wmi,
781	.open  = simple_open,
782};
783
784static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
785			    const char *prefix)
786{
787	char printbuf[16 * 3 + 2];
788	int i = 0;
789
790	while (i < len) {
791		int l = min(len - i, 16);
792
793		hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
794				   sizeof(printbuf), false);
795		seq_printf(s, "%s%s\n", prefix, printbuf);
796		i += l;
797	}
798}
799
800static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
801{
802	int i = 0;
803	int len = skb_headlen(skb);
804	void *p = skb->data;
805	int nr_frags = skb_shinfo(skb)->nr_frags;
806
807	seq_printf(s, "    len = %d\n", len);
808	wil_seq_hexdump(s, p, len, "      : ");
809
810	if (nr_frags) {
811		seq_printf(s, "    nr_frags = %d\n", nr_frags);
812		for (i = 0; i < nr_frags; i++) {
813			const struct skb_frag_struct *frag =
814					&skb_shinfo(skb)->frags[i];
815
816			len = skb_frag_size(frag);
817			p = skb_frag_address_safe(frag);
818			seq_printf(s, "    [%2d] : len = %d\n", i, len);
819			wil_seq_hexdump(s, p, len, "      : ");
820		}
821	}
822}
823
824/*---------Tx/Rx descriptor------------*/
825static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
826{
827	struct wil6210_priv *wil = s->private;
828	struct vring *vring;
829	bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
830
831	vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
832
833	if (!vring->va) {
834		if (tx)
835			seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index);
836		else
837			seq_puts(s, "No Rx VRING\n");
838		return 0;
839	}
840
841	if (dbg_txdesc_index < vring->size) {
842		/* use struct vring_tx_desc for Rx as well,
843		 * only field used, .dma.length, is the same
844		 */
845		volatile struct vring_tx_desc *d =
846				&vring->va[dbg_txdesc_index].tx;
847		volatile u32 *u = (volatile u32 *)d;
848		struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
849
850		if (tx)
851			seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index,
852				   dbg_txdesc_index);
853		else
854			seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);
855		seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
856			   u[0], u[1], u[2], u[3]);
857		seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
858			   u[4], u[5], u[6], u[7]);
859		seq_printf(s, "  SKB = 0x%p\n", skb);
860
861		if (skb) {
862			skb_get(skb);
863			wil_seq_print_skb(s, skb);
864			kfree_skb(skb);
865		}
866		seq_puts(s, "}\n");
867	} else {
868		if (tx)
869			seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
870				   dbg_vring_index, dbg_txdesc_index,
871				   vring->size);
872		else
873			seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
874				   dbg_txdesc_index, vring->size);
875	}
876
877	return 0;
878}
879
880static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
881{
882	return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
883}
884
885static const struct file_operations fops_txdesc = {
886	.open		= wil_txdesc_seq_open,
887	.release	= single_release,
888	.read		= seq_read,
889	.llseek		= seq_lseek,
890};
891
892/*---------beamforming------------*/
893static char *wil_bfstatus_str(u32 status)
894{
895	switch (status) {
896	case 0:
897		return "Failed";
898	case 1:
899		return "OK";
900	case 2:
901		return "Retrying";
902	default:
903		return "??";
904	}
905}
906
907static bool is_all_zeros(void * const x_, size_t sz)
908{
909	/* if reply is all-0, ignore this CID */
910	u32 *x = x_;
911	int n;
912
913	for (n = 0; n < sz / sizeof(*x); n++)
914		if (x[n])
915			return false;
916
917	return true;
918}
919
920static int wil_bf_debugfs_show(struct seq_file *s, void *data)
921{
922	int rc;
923	int i;
924	struct wil6210_priv *wil = s->private;
925	struct wmi_notify_req_cmd cmd = {
926		.interval_usec = 0,
927	};
928	struct {
929		struct wil6210_mbox_hdr_wmi wmi;
930		struct wmi_notify_req_done_event evt;
931	} __packed reply;
932
933	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
934		u32 status;
935
936		cmd.cid = i;
937		rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
938			      WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
939			      sizeof(reply), 20);
940		/* if reply is all-0, ignore this CID */
941		if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
942			continue;
943
944		status = le32_to_cpu(reply.evt.status);
945		seq_printf(s, "CID %d {\n"
946			   "  TSF = 0x%016llx\n"
947			   "  TxMCS = %2d TxTpt = %4d\n"
948			   "  SQI = %4d\n"
949			   "  Status = 0x%08x %s\n"
950			   "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
951			   "  Goodput(rx:tx) %4d:%4d\n"
952			   "}\n",
953			   i,
954			   le64_to_cpu(reply.evt.tsf),
955			   le16_to_cpu(reply.evt.bf_mcs),
956			   le32_to_cpu(reply.evt.tx_tpt),
957			   reply.evt.sqi,
958			   status, wil_bfstatus_str(status),
959			   le16_to_cpu(reply.evt.my_rx_sector),
960			   le16_to_cpu(reply.evt.my_tx_sector),
961			   le16_to_cpu(reply.evt.other_rx_sector),
962			   le16_to_cpu(reply.evt.other_tx_sector),
963			   le32_to_cpu(reply.evt.rx_goodput),
964			   le32_to_cpu(reply.evt.tx_goodput));
965	}
966	return 0;
967}
968
969static int wil_bf_seq_open(struct inode *inode, struct file *file)
970{
971	return single_open(file, wil_bf_debugfs_show, inode->i_private);
972}
973
974static const struct file_operations fops_bf = {
975	.open		= wil_bf_seq_open,
976	.release	= single_release,
977	.read		= seq_read,
978	.llseek		= seq_lseek,
979};
980
981/*---------SSID------------*/
982static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
983				  size_t count, loff_t *ppos)
984{
985	struct wil6210_priv *wil = file->private_data;
986	struct wireless_dev *wdev = wil_to_wdev(wil);
987
988	return simple_read_from_buffer(user_buf, count, ppos,
989				       wdev->ssid, wdev->ssid_len);
990}
991
992static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf,
993				   size_t count, loff_t *ppos)
994{
995	struct wil6210_priv *wil = file->private_data;
996	struct wireless_dev *wdev = wil_to_wdev(wil);
997	struct net_device *ndev = wil_to_ndev(wil);
998
999	if (*ppos != 0) {
1000		wil_err(wil, "Unable to set SSID substring from [%d]\n",
1001			(int)*ppos);
1002		return -EINVAL;
1003	}
1004
1005	if (count > sizeof(wdev->ssid)) {
1006		wil_err(wil, "SSID too long, len = %d\n", (int)count);
1007		return -EINVAL;
1008	}
1009	if (netif_running(ndev)) {
1010		wil_err(wil, "Unable to change SSID on running interface\n");
1011		return -EINVAL;
1012	}
1013
1014	wdev->ssid_len = count;
1015	return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos,
1016				      buf, count);
1017}
1018
1019static const struct file_operations fops_ssid = {
1020	.read = wil_read_file_ssid,
1021	.write = wil_write_file_ssid,
1022	.open  = simple_open,
1023};
1024
1025/*---------temp------------*/
1026static void print_temp(struct seq_file *s, const char *prefix, u32 t)
1027{
1028	switch (t) {
1029	case 0:
1030	case ~(u32)0:
1031		seq_printf(s, "%s N/A\n", prefix);
1032	break;
1033	default:
1034		seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000);
1035		break;
1036	}
1037}
1038
1039static int wil_temp_debugfs_show(struct seq_file *s, void *data)
1040{
1041	struct wil6210_priv *wil = s->private;
1042	u32 t_m, t_r;
1043	int rc = wmi_get_temperature(wil, &t_m, &t_r);
1044
1045	if (rc) {
1046		seq_puts(s, "Failed\n");
1047		return 0;
1048	}
1049
1050	print_temp(s, "T_mac   =", t_m);
1051	print_temp(s, "T_radio =", t_r);
1052
1053	return 0;
1054}
1055
1056static int wil_temp_seq_open(struct inode *inode, struct file *file)
1057{
1058	return single_open(file, wil_temp_debugfs_show, inode->i_private);
1059}
1060
1061static const struct file_operations fops_temp = {
1062	.open		= wil_temp_seq_open,
1063	.release	= single_release,
1064	.read		= seq_read,
1065	.llseek		= seq_lseek,
1066};
1067
1068/*---------freq------------*/
1069static int wil_freq_debugfs_show(struct seq_file *s, void *data)
1070{
1071	struct wil6210_priv *wil = s->private;
1072	struct wireless_dev *wdev = wil_to_wdev(wil);
1073	u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
1074
1075	seq_printf(s, "Freq = %d\n", freq);
1076
1077	return 0;
1078}
1079
1080static int wil_freq_seq_open(struct inode *inode, struct file *file)
1081{
1082	return single_open(file, wil_freq_debugfs_show, inode->i_private);
1083}
1084
1085static const struct file_operations fops_freq = {
1086	.open		= wil_freq_seq_open,
1087	.release	= single_release,
1088	.read		= seq_read,
1089	.llseek		= seq_lseek,
1090};
1091
1092/*---------link------------*/
1093static int wil_link_debugfs_show(struct seq_file *s, void *data)
1094{
1095	struct wil6210_priv *wil = s->private;
1096	struct station_info sinfo;
1097	int i, rc;
1098
1099	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1100		struct wil_sta_info *p = &wil->sta[i];
1101		char *status = "unknown";
1102
1103		switch (p->status) {
1104		case wil_sta_unused:
1105			status = "unused   ";
1106			break;
1107		case wil_sta_conn_pending:
1108			status = "pending  ";
1109			break;
1110		case wil_sta_connected:
1111			status = "connected";
1112			break;
1113		}
1114		seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
1115			   (p->data_port_open ? " data_port_open" : ""));
1116
1117		if (p->status == wil_sta_connected) {
1118			rc = wil_cid_fill_sinfo(wil, i, &sinfo);
1119			if (rc)
1120				return rc;
1121
1122			seq_printf(s, "  Tx_mcs = %d\n", sinfo.txrate.mcs);
1123			seq_printf(s, "  Rx_mcs = %d\n", sinfo.rxrate.mcs);
1124			seq_printf(s, "  SQ     = %d\n", sinfo.signal);
1125		}
1126	}
1127
1128	return 0;
1129}
1130
1131static int wil_link_seq_open(struct inode *inode, struct file *file)
1132{
1133	return single_open(file, wil_link_debugfs_show, inode->i_private);
1134}
1135
1136static const struct file_operations fops_link = {
1137	.open		= wil_link_seq_open,
1138	.release	= single_release,
1139	.read		= seq_read,
1140	.llseek		= seq_lseek,
1141};
1142
1143/*---------info------------*/
1144static int wil_info_debugfs_show(struct seq_file *s, void *data)
1145{
1146	struct wil6210_priv *wil = s->private;
1147	struct net_device *ndev = wil_to_ndev(wil);
1148	int is_ac = power_supply_is_system_supplied();
1149	int rx = atomic_xchg(&wil->isr_count_rx, 0);
1150	int tx = atomic_xchg(&wil->isr_count_tx, 0);
1151	static ulong rxf_old, txf_old;
1152	ulong rxf = ndev->stats.rx_packets;
1153	ulong txf = ndev->stats.tx_packets;
1154	unsigned int i;
1155
1156	/* >0 : AC; 0 : battery; <0 : error */
1157	seq_printf(s, "AC powered : %d\n", is_ac);
1158	seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
1159	seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
1160	rxf_old = rxf;
1161	txf_old = txf;
1162
1163#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1164	" " __stringify(x) : ""
1165
1166	for (i = 0; i < ndev->num_tx_queues; i++) {
1167		struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
1168		unsigned long state = txq->state;
1169
1170		seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
1171			   CHECK_QSTATE(DRV_XOFF),
1172			   CHECK_QSTATE(STACK_XOFF),
1173			   CHECK_QSTATE(FROZEN)
1174			  );
1175	}
1176#undef CHECK_QSTATE
1177	return 0;
1178}
1179
1180static int wil_info_seq_open(struct inode *inode, struct file *file)
1181{
1182	return single_open(file, wil_info_debugfs_show, inode->i_private);
1183}
1184
1185static const struct file_operations fops_info = {
1186	.open		= wil_info_seq_open,
1187	.release	= single_release,
1188	.read		= seq_read,
1189	.llseek		= seq_lseek,
1190};
1191
1192/*---------recovery------------*/
1193/* mode = [manual|auto]
1194 * state = [idle|pending|running]
1195 */
1196static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
1197				      size_t count, loff_t *ppos)
1198{
1199	struct wil6210_priv *wil = file->private_data;
1200	char buf[80];
1201	int n;
1202	static const char * const sstate[] = {"idle", "pending", "running"};
1203
1204	n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
1205		     no_fw_recovery ? "manual" : "auto",
1206		     sstate[wil->recovery_state]);
1207
1208	n = min_t(int, n, sizeof(buf));
1209
1210	return simple_read_from_buffer(user_buf, count, ppos,
1211				       buf, n);
1212}
1213
1214static ssize_t wil_write_file_recovery(struct file *file,
1215				       const char __user *buf_,
1216				       size_t count, loff_t *ppos)
1217{
1218	struct wil6210_priv *wil = file->private_data;
1219	static const char run_command[] = "run";
1220	char buf[sizeof(run_command) + 1]; /* to detect "runx" */
1221	ssize_t rc;
1222
1223	if (wil->recovery_state != fw_recovery_pending) {
1224		wil_err(wil, "No recovery pending\n");
1225		return -EINVAL;
1226	}
1227
1228	if (*ppos != 0) {
1229		wil_err(wil, "Offset [%d]\n", (int)*ppos);
1230		return -EINVAL;
1231	}
1232
1233	if (count > sizeof(buf)) {
1234		wil_err(wil, "Input too long, len = %d\n", (int)count);
1235		return -EINVAL;
1236	}
1237
1238	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
1239	if (rc < 0)
1240		return rc;
1241
1242	buf[rc] = '\0';
1243	if (0 == strcmp(buf, run_command))
1244		wil_set_recovery_state(wil, fw_recovery_running);
1245	else
1246		wil_err(wil, "Bad recovery command \"%s\"\n", buf);
1247
1248	return rc;
1249}
1250
1251static const struct file_operations fops_recovery = {
1252	.read = wil_read_file_recovery,
1253	.write = wil_write_file_recovery,
1254	.open  = simple_open,
1255};
1256
1257/*---------Station matrix------------*/
1258static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
1259{
1260	int i;
1261	u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
1262
1263	seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout,
1264		   r->head_seq_num);
1265	for (i = 0; i < r->buf_size; i++) {
1266		if (i == index)
1267			seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
1268		else
1269			seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
1270	}
1271	seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop);
1272}
1273
1274static int wil_sta_debugfs_show(struct seq_file *s, void *data)
1275__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1276{
1277	struct wil6210_priv *wil = s->private;
1278	int i, tid;
1279
1280	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1281		struct wil_sta_info *p = &wil->sta[i];
1282		char *status = "unknown";
1283
1284		switch (p->status) {
1285		case wil_sta_unused:
1286			status = "unused   ";
1287			break;
1288		case wil_sta_conn_pending:
1289			status = "pending  ";
1290			break;
1291		case wil_sta_connected:
1292			status = "connected";
1293			break;
1294		}
1295		seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
1296			   (p->data_port_open ? " data_port_open" : ""));
1297
1298		if (p->status == wil_sta_connected) {
1299			spin_lock_bh(&p->tid_rx_lock);
1300			for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
1301				struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
1302
1303				if (r) {
1304					seq_printf(s, "[%2d] ", tid);
1305					wil_print_rxtid(s, r);
1306				}
1307			}
1308			spin_unlock_bh(&p->tid_rx_lock);
1309		}
1310	}
1311
1312	return 0;
1313}
1314
1315static int wil_sta_seq_open(struct inode *inode, struct file *file)
1316{
1317	return single_open(file, wil_sta_debugfs_show, inode->i_private);
1318}
1319
1320static const struct file_operations fops_sta = {
1321	.open		= wil_sta_seq_open,
1322	.release	= single_release,
1323	.read		= seq_read,
1324	.llseek		= seq_lseek,
1325};
1326
1327/*----------------*/
1328static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
1329				       struct dentry *dbg)
1330{
1331	int i;
1332	char name[32];
1333
1334	for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
1335		struct debugfs_blob_wrapper *blob = &wil->blobs[i];
1336		const struct fw_map *map = &fw_mapping[i];
1337
1338		if (!map->name)
1339			continue;
1340
1341		blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
1342		blob->size = map->to - map->from;
1343		snprintf(name, sizeof(name), "blob_%s", map->name);
1344		wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob);
1345	}
1346}
1347
1348/* misc files */
1349static const struct {
1350	const char *name;
1351	umode_t mode;
1352	const struct file_operations *fops;
1353} dbg_files[] = {
1354	{"mbox",	S_IRUGO,		&fops_mbox},
1355	{"vrings",	S_IRUGO,		&fops_vring},
1356	{"stations",	S_IRUGO,		&fops_sta},
1357	{"desc",	S_IRUGO,		&fops_txdesc},
1358	{"bf",		S_IRUGO,		&fops_bf},
1359	{"ssid",	S_IRUGO | S_IWUSR,	&fops_ssid},
1360	{"mem_val",	S_IRUGO,		&fops_memread},
1361	{"reset",		  S_IWUSR,	&fops_reset},
1362	{"rxon",		  S_IWUSR,	&fops_rxon},
1363	{"tx_mgmt",		  S_IWUSR,	&fops_txmgmt},
1364	{"wmi_send",		  S_IWUSR,	&fops_wmi},
1365	{"back",	S_IRUGO | S_IWUSR,	&fops_back},
1366	{"temp",	S_IRUGO,		&fops_temp},
1367	{"freq",	S_IRUGO,		&fops_freq},
1368	{"link",	S_IRUGO,		&fops_link},
1369	{"info",	S_IRUGO,		&fops_info},
1370	{"recovery",	S_IRUGO | S_IWUSR,	&fops_recovery},
1371};
1372
1373static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
1374				       struct dentry *dbg)
1375{
1376	int i;
1377
1378	for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
1379		debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
1380				    wil, dbg_files[i].fops);
1381}
1382
1383/* interrupt control blocks */
1384static const struct {
1385	const char *name;
1386	u32 icr_off;
1387} dbg_icr[] = {
1388	{"USER_ICR",		HOSTADDR(RGF_USER_USER_ICR)},
1389	{"DMA_EP_TX_ICR",	HOSTADDR(RGF_DMA_EP_TX_ICR)},
1390	{"DMA_EP_RX_ICR",	HOSTADDR(RGF_DMA_EP_RX_ICR)},
1391	{"DMA_EP_MISC_ICR",	HOSTADDR(RGF_DMA_EP_MISC_ICR)},
1392};
1393
1394static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
1395				     struct dentry *dbg)
1396{
1397	int i;
1398
1399	for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
1400		wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
1401					   dbg_icr[i].icr_off);
1402}
1403
1404#define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
1405	offsetof(struct wil6210_priv, name), type}
1406
1407/* fields in struct wil6210_priv */
1408static const struct dbg_off dbg_wil_off[] = {
1409	WIL_FIELD(privacy,	S_IRUGO,		doff_u32),
1410	WIL_FIELD(status[0],	S_IRUGO | S_IWUSR,	doff_ulong),
1411	WIL_FIELD(fw_version,	S_IRUGO,		doff_u32),
1412	WIL_FIELD(hw_version,	S_IRUGO,		doff_x32),
1413	WIL_FIELD(recovery_count, S_IRUGO,		doff_u32),
1414	WIL_FIELD(ap_isolate,	S_IRUGO,		doff_u32),
1415	{},
1416};
1417
1418static const struct dbg_off dbg_wil_regs[] = {
1419	{"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
1420		doff_io32},
1421	{"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
1422	{},
1423};
1424
1425/* static parameters */
1426static const struct dbg_off dbg_statics[] = {
1427	{"desc_index",	S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
1428	{"vring_index",	S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
1429	{"mem_addr",	S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
1430	{"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh,
1431	 doff_u32},
1432	{},
1433};
1434
1435int wil6210_debugfs_init(struct wil6210_priv *wil)
1436{
1437	struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
1438			wil_to_wiphy(wil)->debugfsdir);
1439
1440	if (IS_ERR_OR_NULL(dbg))
1441		return -ENODEV;
1442
1443	wil6210_debugfs_init_files(wil, dbg);
1444	wil6210_debugfs_init_isr(wil, dbg);
1445	wil6210_debugfs_init_blobs(wil, dbg);
1446	wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
1447	wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
1448				    dbg_wil_regs);
1449	wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
1450
1451	wil6210_debugfs_create_pseudo_ISR(wil, dbg);
1452
1453	wil6210_debugfs_create_ITR_CNT(wil, dbg);
1454
1455	return 0;
1456}
1457
1458void wil6210_debugfs_remove(struct wil6210_priv *wil)
1459{
1460	debugfs_remove_recursive(wil->debug);
1461	wil->debug = NULL;
1462}
1463