xref: /openbmc/linux/drivers/net/wireless/ath/wil6210/debugfs.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1  // SPDX-License-Identifier: ISC
2  /*
3   * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
4   * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
5   */
6  
7  #include <linux/module.h>
8  #include <linux/debugfs.h>
9  #include <linux/seq_file.h>
10  #include <linux/pci.h>
11  #include <linux/rtnetlink.h>
12  #include <linux/power_supply.h>
13  #include "wil6210.h"
14  #include "wmi.h"
15  #include "txrx.h"
16  #include "pmc.h"
17  
18  /* Nasty hack. Better have per device instances */
19  static u32 mem_addr;
20  static u32 dbg_txdesc_index;
21  static u32 dbg_ring_index; /* 24+ for Rx, 0..23 for Tx */
22  static u32 dbg_status_msg_index;
23  /* 0..wil->num_rx_status_rings-1 for Rx, wil->tx_sring_idx for Tx */
24  static u32 dbg_sring_index;
25  
26  enum dbg_off_type {
27  	doff_u32 = 0,
28  	doff_x32 = 1,
29  	doff_ulong = 2,
30  	doff_io32 = 3,
31  	doff_u8 = 4
32  };
33  
34  /* offset to "wil" */
35  struct dbg_off {
36  	const char *name;
37  	umode_t mode;
38  	ulong off;
39  	enum dbg_off_type type;
40  };
41  
wil_print_desc_edma(struct seq_file * s,struct wil6210_priv * wil,struct wil_ring * ring,char _s,char _h,int idx)42  static void wil_print_desc_edma(struct seq_file *s, struct wil6210_priv *wil,
43  				struct wil_ring *ring,
44  				char _s, char _h, int idx)
45  {
46  	u8 num_of_descs;
47  	bool has_skb = false;
48  
49  	if (ring->is_rx) {
50  		struct wil_rx_enhanced_desc *rx_d =
51  			(struct wil_rx_enhanced_desc *)
52  			&ring->va[idx].rx.enhanced;
53  		u16 buff_id = le16_to_cpu(rx_d->mac.buff_id);
54  
55  		if (wil->rx_buff_mgmt.buff_arr &&
56  		    wil_val_in_range(buff_id, 0, wil->rx_buff_mgmt.size))
57  			has_skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
58  		seq_printf(s, "%c", (has_skb) ? _h : _s);
59  	} else {
60  		struct wil_tx_enhanced_desc *d =
61  			(struct wil_tx_enhanced_desc *)
62  			&ring->va[idx].tx.enhanced;
63  
64  		num_of_descs = (u8)d->mac.d[2];
65  		has_skb = ring->ctx && ring->ctx[idx].skb;
66  		if (num_of_descs >= 1)
67  			seq_printf(s, "%c", has_skb ? _h : _s);
68  		else
69  			/* num_of_descs == 0, it's a frag in a list of descs */
70  			seq_printf(s, "%c", has_skb ? 'h' : _s);
71  	}
72  }
73  
wil_print_ring(struct seq_file * s,struct wil6210_priv * wil,const char * name,struct wil_ring * ring,char _s,char _h)74  static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil,
75  			   const char *name, struct wil_ring *ring,
76  			   char _s, char _h)
77  {
78  	void __iomem *x;
79  	u32 v;
80  
81  	seq_printf(s, "RING %s = {\n", name);
82  	seq_printf(s, "  pa     = %pad\n", &ring->pa);
83  	seq_printf(s, "  va     = 0x%p\n", ring->va);
84  	seq_printf(s, "  size   = %d\n", ring->size);
85  	if (wil->use_enhanced_dma_hw && ring->is_rx)
86  		seq_printf(s, "  swtail = %u\n", *ring->edma_rx_swtail.va);
87  	else
88  		seq_printf(s, "  swtail = %d\n", ring->swtail);
89  	seq_printf(s, "  swhead = %d\n", ring->swhead);
90  	if (wil->use_enhanced_dma_hw) {
91  		int ring_id = ring->is_rx ?
92  			WIL_RX_DESC_RING_ID : ring - wil->ring_tx;
93  		/* SUBQ_CONS is a table of 32 entries, one for each Q pair.
94  		 * lower 16bits are for even ring_id and upper 16bits are for
95  		 * odd ring_id
96  		 */
97  		x = wmi_addr(wil, RGF_DMA_SCM_SUBQ_CONS + 4 * (ring_id / 2));
98  		v = readl_relaxed(x);
99  
100  		v = (ring_id % 2 ? (v >> 16) : (v & 0xffff));
101  		seq_printf(s, "  hwhead = %u\n", v);
102  	}
103  	seq_printf(s, "  hwtail = [0x%08x] -> ", ring->hwtail);
104  	x = wmi_addr(wil, ring->hwtail);
105  	if (x) {
106  		v = readl(x);
107  		seq_printf(s, "0x%08x = %d\n", v, v);
108  	} else {
109  		seq_puts(s, "???\n");
110  	}
111  
112  	if (ring->va && (ring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
113  		uint i;
114  
115  		for (i = 0; i < ring->size; i++) {
116  			if ((i % 128) == 0 && i != 0)
117  				seq_puts(s, "\n");
118  			if (wil->use_enhanced_dma_hw) {
119  				wil_print_desc_edma(s, wil, ring, _s, _h, i);
120  			} else {
121  				volatile struct vring_tx_desc *d =
122  					&ring->va[i].tx.legacy;
123  				seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
124  					   _s : (ring->ctx[i].skb ? _h : 'h'));
125  			}
126  		}
127  		seq_puts(s, "\n");
128  	}
129  	seq_puts(s, "}\n");
130  }
131  
ring_show(struct seq_file * s,void * data)132  static int ring_show(struct seq_file *s, void *data)
133  {
134  	uint i;
135  	struct wil6210_priv *wil = s->private;
136  
137  	wil_print_ring(s, wil, "rx", &wil->ring_rx, 'S', '_');
138  
139  	for (i = 0; i < ARRAY_SIZE(wil->ring_tx); i++) {
140  		struct wil_ring *ring = &wil->ring_tx[i];
141  		struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i];
142  
143  		if (ring->va) {
144  			int cid = wil->ring2cid_tid[i][0];
145  			int tid = wil->ring2cid_tid[i][1];
146  			u32 swhead = ring->swhead;
147  			u32 swtail = ring->swtail;
148  			int used = (ring->size + swhead - swtail)
149  				   % ring->size;
150  			int avail = ring->size - used - 1;
151  			char name[10];
152  			char sidle[10];
153  			/* performance monitoring */
154  			cycles_t now = get_cycles();
155  			uint64_t idle = txdata->idle * 100;
156  			uint64_t total = now - txdata->begin;
157  
158  			if (total != 0) {
159  				do_div(idle, total);
160  				snprintf(sidle, sizeof(sidle), "%3d%%",
161  					 (int)idle);
162  			} else {
163  				snprintf(sidle, sizeof(sidle), "N/A");
164  			}
165  			txdata->begin = now;
166  			txdata->idle = 0ULL;
167  
168  			snprintf(name, sizeof(name), "tx_%2d", i);
169  
170  			if (cid < wil->max_assoc_sta)
171  				seq_printf(s,
172  					   "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
173  					   wil->sta[cid].addr, cid, tid,
174  					   txdata->dot1x_open ? "+" : "-",
175  					   txdata->agg_wsize,
176  					   txdata->agg_timeout,
177  					   txdata->agg_amsdu ? "+" : "-",
178  					   used, avail, sidle);
179  			else
180  				seq_printf(s,
181  					   "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
182  					   txdata->dot1x_open ? "+" : "-",
183  					   used, avail, sidle);
184  
185  			wil_print_ring(s, wil, name, ring, '_', 'H');
186  		}
187  	}
188  
189  	return 0;
190  }
191  DEFINE_SHOW_ATTRIBUTE(ring);
192  
wil_print_sring(struct seq_file * s,struct wil6210_priv * wil,struct wil_status_ring * sring)193  static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil,
194  			    struct wil_status_ring *sring)
195  {
196  	void __iomem *x;
197  	int sring_idx = sring - wil->srings;
198  	u32 v;
199  
200  	seq_printf(s, "Status Ring %s [ %d ] = {\n",
201  		   sring->is_rx ? "RX" : "TX", sring_idx);
202  	seq_printf(s, "  pa     = %pad\n", &sring->pa);
203  	seq_printf(s, "  va     = 0x%pK\n", sring->va);
204  	seq_printf(s, "  size   = %d\n", sring->size);
205  	seq_printf(s, "  elem_size   = %zu\n", sring->elem_size);
206  	seq_printf(s, "  swhead = %d\n", sring->swhead);
207  	if (wil->use_enhanced_dma_hw) {
208  		/* COMPQ_PROD is a table of 32 entries, one for each Q pair.
209  		 * lower 16bits are for even ring_id and upper 16bits are for
210  		 * odd ring_id
211  		 */
212  		x = wmi_addr(wil, RGF_DMA_SCM_COMPQ_PROD + 4 * (sring_idx / 2));
213  		v = readl_relaxed(x);
214  
215  		v = (sring_idx % 2 ? (v >> 16) : (v & 0xffff));
216  		seq_printf(s, "  hwhead = %u\n", v);
217  	}
218  	seq_printf(s, "  hwtail = [0x%08x] -> ", sring->hwtail);
219  	x = wmi_addr(wil, sring->hwtail);
220  	if (x) {
221  		v = readl_relaxed(x);
222  		seq_printf(s, "0x%08x = %d\n", v, v);
223  	} else {
224  		seq_puts(s, "???\n");
225  	}
226  	seq_printf(s, "  desc_rdy_pol   = %d\n", sring->desc_rdy_pol);
227  	seq_printf(s, "  invalid_buff_id_cnt   = %d\n",
228  		   sring->invalid_buff_id_cnt);
229  
230  	if (sring->va && (sring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
231  		uint i;
232  
233  		for (i = 0; i < sring->size; i++) {
234  			u32 *sdword_0 =
235  				(u32 *)(sring->va + (sring->elem_size * i));
236  
237  			if ((i % 128) == 0 && i != 0)
238  				seq_puts(s, "\n");
239  			if (i == sring->swhead)
240  				seq_printf(s, "%c", (*sdword_0 & BIT(31)) ?
241  					   'X' : 'x');
242  			else
243  				seq_printf(s, "%c", (*sdword_0 & BIT(31)) ?
244  					   '1' : '0');
245  		}
246  		seq_puts(s, "\n");
247  	}
248  	seq_puts(s, "}\n");
249  }
250  
srings_show(struct seq_file * s,void * data)251  static int srings_show(struct seq_file *s, void *data)
252  {
253  	struct wil6210_priv *wil = s->private;
254  	int i = 0;
255  
256  	for (i = 0; i < WIL6210_MAX_STATUS_RINGS; i++)
257  		if (wil->srings[i].va)
258  			wil_print_sring(s, wil, &wil->srings[i]);
259  
260  	return 0;
261  }
262  DEFINE_SHOW_ATTRIBUTE(srings);
263  
wil_seq_hexdump(struct seq_file * s,void * p,int len,const char * prefix)264  static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
265  			    const char *prefix)
266  {
267  	seq_hex_dump(s, prefix, DUMP_PREFIX_NONE, 16, 1, p, len, false);
268  }
269  
wil_print_mbox_ring(struct seq_file * s,const char * prefix,void __iomem * off)270  static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,
271  				void __iomem *off)
272  {
273  	struct wil6210_priv *wil = s->private;
274  	struct wil6210_mbox_ring r;
275  	int rsize;
276  	uint i;
277  
278  	wil_halp_vote(wil);
279  
280  	if (wil_mem_access_lock(wil)) {
281  		wil_halp_unvote(wil);
282  		return;
283  	}
284  
285  	wil_memcpy_fromio_32(&r, off, sizeof(r));
286  	wil_mbox_ring_le2cpus(&r);
287  	/*
288  	 * we just read memory block from NIC. This memory may be
289  	 * garbage. Check validity before using it.
290  	 */
291  	rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
292  
293  	seq_printf(s, "ring %s = {\n", prefix);
294  	seq_printf(s, "  base = 0x%08x\n", r.base);
295  	seq_printf(s, "  size = 0x%04x bytes -> %d entries\n", r.size, rsize);
296  	seq_printf(s, "  tail = 0x%08x\n", r.tail);
297  	seq_printf(s, "  head = 0x%08x\n", r.head);
298  	seq_printf(s, "  entry size = %d\n", r.entry_size);
299  
300  	if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
301  		seq_printf(s, "  ??? size is not multiple of %zd, garbage?\n",
302  			   sizeof(struct wil6210_mbox_ring_desc));
303  		goto out;
304  	}
305  
306  	if (!wmi_addr(wil, r.base) ||
307  	    !wmi_addr(wil, r.tail) ||
308  	    !wmi_addr(wil, r.head)) {
309  		seq_puts(s, "  ??? pointers are garbage?\n");
310  		goto out;
311  	}
312  
313  	for (i = 0; i < rsize; i++) {
314  		struct wil6210_mbox_ring_desc d;
315  		struct wil6210_mbox_hdr hdr;
316  		size_t delta = i * sizeof(d);
317  		void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
318  
319  		wil_memcpy_fromio_32(&d, x, sizeof(d));
320  
321  		seq_printf(s, "  [%2x] %s %s%s 0x%08x", i,
322  			   d.sync ? "F" : "E",
323  			   (r.tail - r.base == delta) ? "t" : " ",
324  			   (r.head - r.base == delta) ? "h" : " ",
325  			   le32_to_cpu(d.addr));
326  		if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
327  			u16 len = le16_to_cpu(hdr.len);
328  
329  			seq_printf(s, " -> %04x %04x %04x %02x\n",
330  				   le16_to_cpu(hdr.seq), len,
331  				   le16_to_cpu(hdr.type), hdr.flags);
332  			if (len <= MAX_MBOXITEM_SIZE) {
333  				unsigned char databuf[MAX_MBOXITEM_SIZE];
334  				void __iomem *src = wmi_buffer(wil, d.addr) +
335  					sizeof(struct wil6210_mbox_hdr);
336  				/*
337  				 * No need to check @src for validity -
338  				 * we already validated @d.addr while
339  				 * reading header
340  				 */
341  				wil_memcpy_fromio_32(databuf, src, len);
342  				wil_seq_hexdump(s, databuf, len, "      : ");
343  			}
344  		} else {
345  			seq_puts(s, "\n");
346  		}
347  	}
348   out:
349  	seq_puts(s, "}\n");
350  	wil_mem_access_unlock(wil);
351  	wil_halp_unvote(wil);
352  }
353  
mbox_show(struct seq_file * s,void * data)354  static int mbox_show(struct seq_file *s, void *data)
355  {
356  	struct wil6210_priv *wil = s->private;
357  	int ret;
358  
359  	ret = wil_pm_runtime_get(wil);
360  	if (ret < 0)
361  		return ret;
362  
363  	wil_print_mbox_ring(s, "tx", wil->csr + HOST_MBOX +
364  		       offsetof(struct wil6210_mbox_ctl, tx));
365  	wil_print_mbox_ring(s, "rx", wil->csr + HOST_MBOX +
366  		       offsetof(struct wil6210_mbox_ctl, rx));
367  
368  	wil_pm_runtime_put(wil);
369  
370  	return 0;
371  }
372  DEFINE_SHOW_ATTRIBUTE(mbox);
373  
wil_debugfs_iomem_x32_set(void * data,u64 val)374  static int wil_debugfs_iomem_x32_set(void *data, u64 val)
375  {
376  	struct wil_debugfs_iomem_data *d = (struct
377  					    wil_debugfs_iomem_data *)data;
378  	struct wil6210_priv *wil = d->wil;
379  	int ret;
380  
381  	ret = wil_pm_runtime_get(wil);
382  	if (ret < 0)
383  		return ret;
384  
385  	writel_relaxed(val, (void __iomem *)d->offset);
386  
387  	wmb(); /* make sure write propagated to HW */
388  
389  	wil_pm_runtime_put(wil);
390  
391  	return 0;
392  }
393  
wil_debugfs_iomem_x32_get(void * data,u64 * val)394  static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
395  {
396  	struct wil_debugfs_iomem_data *d = (struct
397  					    wil_debugfs_iomem_data *)data;
398  	struct wil6210_priv *wil = d->wil;
399  	int ret;
400  
401  	ret = wil_pm_runtime_get(wil);
402  	if (ret < 0)
403  		return ret;
404  
405  	*val = readl((void __iomem *)d->offset);
406  
407  	wil_pm_runtime_put(wil);
408  
409  	return 0;
410  }
411  
412  DEFINE_DEBUGFS_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
413  			 wil_debugfs_iomem_x32_set, "0x%08llx\n");
414  
wil_debugfs_create_iomem_x32(const char * name,umode_t mode,struct dentry * parent,void * value,struct wil6210_priv * wil)415  static void wil_debugfs_create_iomem_x32(const char *name, umode_t mode,
416  					 struct dentry *parent, void *value,
417  					 struct wil6210_priv *wil)
418  {
419  	struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[
420  					      wil->dbg_data.iomem_data_count];
421  
422  	data->wil = wil;
423  	data->offset = value;
424  
425  	debugfs_create_file_unsafe(name, mode, parent, data, &fops_iomem_x32);
426  	wil->dbg_data.iomem_data_count++;
427  }
428  
wil_debugfs_ulong_set(void * data,u64 val)429  static int wil_debugfs_ulong_set(void *data, u64 val)
430  {
431  	*(ulong *)data = val;
432  	return 0;
433  }
434  
wil_debugfs_ulong_get(void * data,u64 * val)435  static int wil_debugfs_ulong_get(void *data, u64 *val)
436  {
437  	*val = *(ulong *)data;
438  	return 0;
439  }
440  
441  DEFINE_DEBUGFS_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
442  			 wil_debugfs_ulong_set, "0x%llx\n");
443  
444  /**
445   * wil6210_debugfs_init_offset - create set of debugfs files
446   * @wil: driver's context, used for printing
447   * @dbg: directory on the debugfs, where files will be created
448   * @base: base address used in address calculation
449   * @tbl: table with file descriptions. Should be terminated with empty element.
450   *
451   * Creates files accordingly to the @tbl.
452   */
wil6210_debugfs_init_offset(struct wil6210_priv * wil,struct dentry * dbg,void * base,const struct dbg_off * const tbl)453  static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
454  					struct dentry *dbg, void *base,
455  					const struct dbg_off * const tbl)
456  {
457  	int i;
458  
459  	for (i = 0; tbl[i].name; i++) {
460  		switch (tbl[i].type) {
461  		case doff_u32:
462  			debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
463  					   base + tbl[i].off);
464  			break;
465  		case doff_x32:
466  			debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
467  					   base + tbl[i].off);
468  			break;
469  		case doff_ulong:
470  			debugfs_create_file_unsafe(tbl[i].name, tbl[i].mode,
471  						   dbg, base + tbl[i].off,
472  						   &wil_fops_ulong);
473  			break;
474  		case doff_io32:
475  			wil_debugfs_create_iomem_x32(tbl[i].name, tbl[i].mode,
476  						     dbg, base + tbl[i].off,
477  						     wil);
478  			break;
479  		case doff_u8:
480  			debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
481  					  base + tbl[i].off);
482  			break;
483  		}
484  	}
485  }
486  
487  static const struct dbg_off isr_off[] = {
488  	{"ICC", 0644, offsetof(struct RGF_ICR, ICC), doff_io32},
489  	{"ICR", 0644, offsetof(struct RGF_ICR, ICR), doff_io32},
490  	{"ICM", 0644, offsetof(struct RGF_ICR, ICM), doff_io32},
491  	{"ICS",	0244, offsetof(struct RGF_ICR, ICS), doff_io32},
492  	{"IMV", 0644, offsetof(struct RGF_ICR, IMV), doff_io32},
493  	{"IMS",	0244, offsetof(struct RGF_ICR, IMS), doff_io32},
494  	{"IMC",	0244, offsetof(struct RGF_ICR, IMC), doff_io32},
495  	{},
496  };
497  
wil6210_debugfs_create_ISR(struct wil6210_priv * wil,const char * name,struct dentry * parent,u32 off)498  static void wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
499  				       const char *name, struct dentry *parent,
500  				       u32 off)
501  {
502  	struct dentry *d = debugfs_create_dir(name, parent);
503  
504  	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
505  				    isr_off);
506  }
507  
508  static const struct dbg_off pseudo_isr_off[] = {
509  	{"CAUSE",   0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
510  	{"MASK_SW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
511  	{"MASK_FW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
512  	{},
513  };
514  
wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv * wil,struct dentry * parent)515  static void wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
516  					      struct dentry *parent)
517  {
518  	struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
519  
520  	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
521  				    pseudo_isr_off);
522  }
523  
524  static const struct dbg_off lgc_itr_cnt_off[] = {
525  	{"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
526  	{"DATA", 0644, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
527  	{"CTL",  0644, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
528  	{},
529  };
530  
531  static const struct dbg_off tx_itr_cnt_off[] = {
532  	{"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
533  	 doff_io32},
534  	{"DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
535  	 doff_io32},
536  	{"CTL",  0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
537  	 doff_io32},
538  	{"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
539  	 doff_io32},
540  	{"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
541  	 doff_io32},
542  	{"IDL_CTL",  0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
543  	 doff_io32},
544  	{},
545  };
546  
547  static const struct dbg_off rx_itr_cnt_off[] = {
548  	{"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
549  	 doff_io32},
550  	{"DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
551  	 doff_io32},
552  	{"CTL",  0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
553  	 doff_io32},
554  	{"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
555  	 doff_io32},
556  	{"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
557  	 doff_io32},
558  	{"IDL_CTL",  0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
559  	 doff_io32},
560  	{},
561  };
562  
wil6210_debugfs_create_ITR_CNT(struct wil6210_priv * wil,struct dentry * parent)563  static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
564  					  struct dentry *parent)
565  {
566  	struct dentry *d, *dtx, *drx;
567  
568  	d = debugfs_create_dir("ITR_CNT", parent);
569  
570  	dtx = debugfs_create_dir("TX", d);
571  	drx = debugfs_create_dir("RX", d);
572  
573  	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
574  				    lgc_itr_cnt_off);
575  
576  	wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
577  				    tx_itr_cnt_off);
578  
579  	wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
580  				    rx_itr_cnt_off);
581  	return 0;
582  }
583  
memread_show(struct seq_file * s,void * data)584  static int memread_show(struct seq_file *s, void *data)
585  {
586  	struct wil6210_priv *wil = s->private;
587  	void __iomem *a;
588  	int ret;
589  
590  	ret = wil_pm_runtime_get(wil);
591  	if (ret < 0)
592  		return ret;
593  
594  	ret = wil_mem_access_lock(wil);
595  	if (ret) {
596  		wil_pm_runtime_put(wil);
597  		return ret;
598  	}
599  
600  	a = wmi_buffer(wil, cpu_to_le32(mem_addr));
601  
602  	if (a)
603  		seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a));
604  	else
605  		seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
606  
607  	wil_mem_access_unlock(wil);
608  	wil_pm_runtime_put(wil);
609  
610  	return 0;
611  }
612  DEFINE_SHOW_ATTRIBUTE(memread);
613  
wil_read_file_ioblob(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)614  static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
615  				    size_t count, loff_t *ppos)
616  {
617  	enum { max_count = 4096 };
618  	struct wil_blob_wrapper *wil_blob = file->private_data;
619  	struct wil6210_priv *wil = wil_blob->wil;
620  	loff_t aligned_pos, pos = *ppos;
621  	size_t available = wil_blob->blob.size;
622  	void *buf;
623  	size_t unaligned_bytes, aligned_count, ret;
624  	int rc;
625  
626  	if (pos < 0)
627  		return -EINVAL;
628  
629  	if (pos >= available || !count)
630  		return 0;
631  
632  	if (count > available - pos)
633  		count = available - pos;
634  	if (count > max_count)
635  		count = max_count;
636  
637  	/* set pos to 4 bytes aligned */
638  	unaligned_bytes = pos % 4;
639  	aligned_pos = pos - unaligned_bytes;
640  	aligned_count = count + unaligned_bytes;
641  
642  	buf = kmalloc(aligned_count, GFP_KERNEL);
643  	if (!buf)
644  		return -ENOMEM;
645  
646  	rc = wil_pm_runtime_get(wil);
647  	if (rc < 0) {
648  		kfree(buf);
649  		return rc;
650  	}
651  
652  	rc = wil_mem_access_lock(wil);
653  	if (rc) {
654  		kfree(buf);
655  		wil_pm_runtime_put(wil);
656  		return rc;
657  	}
658  
659  	wil_memcpy_fromio_32(buf, (const void __iomem *)
660  			     wil_blob->blob.data + aligned_pos, aligned_count);
661  
662  	ret = copy_to_user(user_buf, buf + unaligned_bytes, count);
663  
664  	wil_mem_access_unlock(wil);
665  	wil_pm_runtime_put(wil);
666  
667  	kfree(buf);
668  	if (ret == count)
669  		return -EFAULT;
670  
671  	count -= ret;
672  	*ppos = pos + count;
673  
674  	return count;
675  }
676  
677  static const struct file_operations fops_ioblob = {
678  	.read =		wil_read_file_ioblob,
679  	.open =		simple_open,
680  	.llseek =	default_llseek,
681  };
682  
683  static
wil_debugfs_create_ioblob(const char * name,umode_t mode,struct dentry * parent,struct wil_blob_wrapper * wil_blob)684  struct dentry *wil_debugfs_create_ioblob(const char *name,
685  					 umode_t mode,
686  					 struct dentry *parent,
687  					 struct wil_blob_wrapper *wil_blob)
688  {
689  	return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob);
690  }
691  
692  /*---write channel 1..4 to rxon for it, 0 to rxoff---*/
wil_write_file_rxon(struct file * file,const char __user * buf,size_t len,loff_t * ppos)693  static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
694  				   size_t len, loff_t *ppos)
695  {
696  	struct wil6210_priv *wil = file->private_data;
697  	int rc;
698  	long channel;
699  	bool on;
700  
701  	char *kbuf = memdup_user_nul(buf, len);
702  
703  	if (IS_ERR(kbuf))
704  		return PTR_ERR(kbuf);
705  	rc = kstrtol(kbuf, 0, &channel);
706  	kfree(kbuf);
707  	if (rc)
708  		return rc;
709  
710  	if ((channel < 0) || (channel > 4)) {
711  		wil_err(wil, "Invalid channel %ld\n", channel);
712  		return -EINVAL;
713  	}
714  	on = !!channel;
715  
716  	if (on) {
717  		rc = wmi_set_channel(wil, (int)channel);
718  		if (rc)
719  			return rc;
720  	}
721  
722  	rc = wmi_rxon(wil, on);
723  	if (rc)
724  		return rc;
725  
726  	return len;
727  }
728  
729  static const struct file_operations fops_rxon = {
730  	.write = wil_write_file_rxon,
731  	.open  = simple_open,
732  };
733  
wil_write_file_rbufcap(struct file * file,const char __user * buf,size_t count,loff_t * ppos)734  static ssize_t wil_write_file_rbufcap(struct file *file,
735  				      const char __user *buf,
736  				      size_t count, loff_t *ppos)
737  {
738  	struct wil6210_priv *wil = file->private_data;
739  	int val;
740  	int rc;
741  
742  	rc = kstrtoint_from_user(buf, count, 0, &val);
743  	if (rc) {
744  		wil_err(wil, "Invalid argument\n");
745  		return rc;
746  	}
747  	/* input value: negative to disable, 0 to use system default,
748  	 * 1..ring size to set descriptor threshold
749  	 */
750  	wil_info(wil, "%s RBUFCAP, descriptors threshold - %d\n",
751  		 val < 0 ? "Disabling" : "Enabling", val);
752  
753  	if (!wil->ring_rx.va || val > wil->ring_rx.size) {
754  		wil_err(wil, "Invalid descriptors threshold, %d\n", val);
755  		return -EINVAL;
756  	}
757  
758  	rc = wmi_rbufcap_cfg(wil, val < 0 ? 0 : 1, val < 0 ? 0 : val);
759  	if (rc) {
760  		wil_err(wil, "RBUFCAP config failed: %d\n", rc);
761  		return rc;
762  	}
763  
764  	return count;
765  }
766  
767  static const struct file_operations fops_rbufcap = {
768  	.write = wil_write_file_rbufcap,
769  	.open  = simple_open,
770  };
771  
772  /* block ack control, write:
773   * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
774   * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
775   * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
776   */
wil_write_back(struct file * file,const char __user * buf,size_t len,loff_t * ppos)777  static ssize_t wil_write_back(struct file *file, const char __user *buf,
778  			      size_t len, loff_t *ppos)
779  {
780  	struct wil6210_priv *wil = file->private_data;
781  	int rc;
782  	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
783  	char cmd[9];
784  	int p1, p2, p3;
785  
786  	if (!kbuf)
787  		return -ENOMEM;
788  
789  	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
790  	if (rc != len) {
791  		kfree(kbuf);
792  		return rc >= 0 ? -EIO : rc;
793  	}
794  
795  	kbuf[len] = '\0';
796  	rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
797  	kfree(kbuf);
798  
799  	if (rc < 0)
800  		return rc;
801  	if (rc < 2)
802  		return -EINVAL;
803  
804  	if ((strcmp(cmd, "add") == 0) ||
805  	    (strcmp(cmd, "del_tx") == 0)) {
806  		struct wil_ring_tx_data *txdata;
807  
808  		if (p1 < 0 || p1 >= WIL6210_MAX_TX_RINGS) {
809  			wil_err(wil, "BACK: invalid ring id %d\n", p1);
810  			return -EINVAL;
811  		}
812  		txdata = &wil->ring_tx_data[p1];
813  		if (strcmp(cmd, "add") == 0) {
814  			if (rc < 3) {
815  				wil_err(wil, "BACK: add require at least 2 params\n");
816  				return -EINVAL;
817  			}
818  			if (rc < 4)
819  				p3 = 0;
820  			wmi_addba(wil, txdata->mid, p1, p2, p3);
821  		} else {
822  			if (rc < 3)
823  				p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
824  			wmi_delba_tx(wil, txdata->mid, p1, p2);
825  		}
826  	} else if (strcmp(cmd, "del_rx") == 0) {
827  		struct wil_sta_info *sta;
828  
829  		if (rc < 3) {
830  			wil_err(wil,
831  				"BACK: del_rx require at least 2 params\n");
832  			return -EINVAL;
833  		}
834  		if (p1 < 0 || p1 >= wil->max_assoc_sta) {
835  			wil_err(wil, "BACK: invalid CID %d\n", p1);
836  			return -EINVAL;
837  		}
838  		if (rc < 4)
839  			p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
840  		sta = &wil->sta[p1];
841  		wmi_delba_rx(wil, sta->mid, p1, p2, p3);
842  	} else {
843  		wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
844  		return -EINVAL;
845  	}
846  
847  	return len;
848  }
849  
wil_read_back(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)850  static ssize_t wil_read_back(struct file *file, char __user *user_buf,
851  			     size_t count, loff_t *ppos)
852  {
853  	static const char text[] = "block ack control, write:\n"
854  	" - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
855  	"If missing, <timeout> defaults to 0\n"
856  	" - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
857  	" - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
858  	"If missing, <reason> set to \"STA_LEAVING\" (36)\n";
859  
860  	return simple_read_from_buffer(user_buf, count, ppos, text,
861  				       sizeof(text));
862  }
863  
864  static const struct file_operations fops_back = {
865  	.read = wil_read_back,
866  	.write = wil_write_back,
867  	.open  = simple_open,
868  };
869  
870  /* pmc control, write:
871   * - "alloc <num descriptors> <descriptor_size>" to allocate PMC
872   * - "free" to release memory allocated for PMC
873   */
wil_write_pmccfg(struct file * file,const char __user * buf,size_t len,loff_t * ppos)874  static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf,
875  				size_t len, loff_t *ppos)
876  {
877  	struct wil6210_priv *wil = file->private_data;
878  	int rc;
879  	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
880  	char cmd[9];
881  	int num_descs, desc_size;
882  
883  	if (!kbuf)
884  		return -ENOMEM;
885  
886  	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
887  	if (rc != len) {
888  		kfree(kbuf);
889  		return rc >= 0 ? -EIO : rc;
890  	}
891  
892  	kbuf[len] = '\0';
893  	rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size);
894  	kfree(kbuf);
895  
896  	if (rc < 0)
897  		return rc;
898  
899  	if (rc < 1) {
900  		wil_err(wil, "pmccfg: no params given\n");
901  		return -EINVAL;
902  	}
903  
904  	if (0 == strcmp(cmd, "alloc")) {
905  		if (rc != 3) {
906  			wil_err(wil, "pmccfg: alloc requires 2 params\n");
907  			return -EINVAL;
908  		}
909  		wil_pmc_alloc(wil, num_descs, desc_size);
910  	} else if (0 == strcmp(cmd, "free")) {
911  		if (rc != 1) {
912  			wil_err(wil, "pmccfg: free does not have any params\n");
913  			return -EINVAL;
914  		}
915  		wil_pmc_free(wil, true);
916  	} else {
917  		wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd);
918  		return -EINVAL;
919  	}
920  
921  	return len;
922  }
923  
wil_read_pmccfg(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)924  static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf,
925  			       size_t count, loff_t *ppos)
926  {
927  	struct wil6210_priv *wil = file->private_data;
928  	char text[256];
929  	char help[] = "pmc control, write:\n"
930  	" - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
931  	" - \"free\" to free memory allocated for pmc\n";
932  
933  	snprintf(text, sizeof(text), "Last command status: %d\n\n%s",
934  		 wil_pmc_last_cmd_status(wil), help);
935  
936  	return simple_read_from_buffer(user_buf, count, ppos, text,
937  				       strlen(text) + 1);
938  }
939  
940  static const struct file_operations fops_pmccfg = {
941  	.read = wil_read_pmccfg,
942  	.write = wil_write_pmccfg,
943  	.open  = simple_open,
944  };
945  
946  static const struct file_operations fops_pmcdata = {
947  	.open		= simple_open,
948  	.read		= wil_pmc_read,
949  	.llseek		= wil_pmc_llseek,
950  };
951  
wil_pmcring_seq_open(struct inode * inode,struct file * file)952  static int wil_pmcring_seq_open(struct inode *inode, struct file *file)
953  {
954  	return single_open(file, wil_pmcring_read, inode->i_private);
955  }
956  
957  static const struct file_operations fops_pmcring = {
958  	.open		= wil_pmcring_seq_open,
959  	.release	= single_release,
960  	.read		= seq_read,
961  	.llseek		= seq_lseek,
962  };
963  
964  /*---tx_mgmt---*/
965  /* Write mgmt frame to this file to send it */
wil_write_file_txmgmt(struct file * file,const char __user * buf,size_t len,loff_t * ppos)966  static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
967  				     size_t len, loff_t *ppos)
968  {
969  	struct wil6210_priv *wil = file->private_data;
970  	struct wiphy *wiphy = wil_to_wiphy(wil);
971  	struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
972  	struct cfg80211_mgmt_tx_params params;
973  	int rc;
974  	void *frame;
975  
976  	memset(&params, 0, sizeof(params));
977  
978  	if (!len)
979  		return -EINVAL;
980  
981  	frame = memdup_user(buf, len);
982  	if (IS_ERR(frame))
983  		return PTR_ERR(frame);
984  
985  	params.buf = frame;
986  	params.len = len;
987  
988  	rc = wil_cfg80211_mgmt_tx(wiphy, wdev, &params, NULL);
989  
990  	kfree(frame);
991  	wil_info(wil, "-> %d\n", rc);
992  
993  	return len;
994  }
995  
996  static const struct file_operations fops_txmgmt = {
997  	.write = wil_write_file_txmgmt,
998  	.open  = simple_open,
999  };
1000  
1001  /* Write WMI command (w/o mbox header) to this file to send it
1002   * WMI starts from wil6210_mbox_hdr_wmi header
1003   */
wil_write_file_wmi(struct file * file,const char __user * buf,size_t len,loff_t * ppos)1004  static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
1005  				  size_t len, loff_t *ppos)
1006  {
1007  	struct wil6210_priv *wil = file->private_data;
1008  	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
1009  	struct wmi_cmd_hdr *wmi;
1010  	void *cmd;
1011  	int cmdlen = len - sizeof(struct wmi_cmd_hdr);
1012  	u16 cmdid;
1013  	int rc1;
1014  
1015  	if (cmdlen < 0 || *ppos != 0)
1016  		return -EINVAL;
1017  
1018  	wmi = memdup_user(buf, len);
1019  	if (IS_ERR(wmi))
1020  		return PTR_ERR(wmi);
1021  
1022  	cmd = (cmdlen > 0) ? &wmi[1] : NULL;
1023  	cmdid = le16_to_cpu(wmi->command_id);
1024  
1025  	rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen);
1026  	kfree(wmi);
1027  
1028  	wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
1029  
1030  	return len;
1031  }
1032  
1033  static const struct file_operations fops_wmi = {
1034  	.write = wil_write_file_wmi,
1035  	.open  = simple_open,
1036  };
1037  
wil_seq_print_skb(struct seq_file * s,struct sk_buff * skb)1038  static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
1039  {
1040  	int i = 0;
1041  	int len = skb_headlen(skb);
1042  	void *p = skb->data;
1043  	int nr_frags = skb_shinfo(skb)->nr_frags;
1044  
1045  	seq_printf(s, "    len = %d\n", len);
1046  	wil_seq_hexdump(s, p, len, "      : ");
1047  
1048  	if (nr_frags) {
1049  		seq_printf(s, "    nr_frags = %d\n", nr_frags);
1050  		for (i = 0; i < nr_frags; i++) {
1051  			const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
1052  
1053  			len = skb_frag_size(frag);
1054  			p = skb_frag_address_safe(frag);
1055  			seq_printf(s, "    [%2d] : len = %d\n", i, len);
1056  			wil_seq_hexdump(s, p, len, "      : ");
1057  		}
1058  	}
1059  }
1060  
1061  /*---------Tx/Rx descriptor------------*/
txdesc_show(struct seq_file * s,void * data)1062  static int txdesc_show(struct seq_file *s, void *data)
1063  {
1064  	struct wil6210_priv *wil = s->private;
1065  	struct wil_ring *ring;
1066  	bool tx;
1067  	int ring_idx = dbg_ring_index;
1068  	int txdesc_idx = dbg_txdesc_index;
1069  	volatile struct vring_tx_desc *d;
1070  	volatile u32 *u;
1071  	struct sk_buff *skb;
1072  
1073  	if (wil->use_enhanced_dma_hw) {
1074  		/* RX ring index == 0 */
1075  		if (ring_idx >= WIL6210_MAX_TX_RINGS) {
1076  			seq_printf(s, "invalid ring index %d\n", ring_idx);
1077  			return 0;
1078  		}
1079  		tx = ring_idx > 0; /* desc ring 0 is reserved for RX */
1080  	} else {
1081  		/* RX ring index == WIL6210_MAX_TX_RINGS */
1082  		if (ring_idx > WIL6210_MAX_TX_RINGS) {
1083  			seq_printf(s, "invalid ring index %d\n", ring_idx);
1084  			return 0;
1085  		}
1086  		tx = (ring_idx < WIL6210_MAX_TX_RINGS);
1087  	}
1088  
1089  	ring = tx ? &wil->ring_tx[ring_idx] : &wil->ring_rx;
1090  
1091  	if (!ring->va) {
1092  		if (tx)
1093  			seq_printf(s, "No Tx[%2d] RING\n", ring_idx);
1094  		else
1095  			seq_puts(s, "No Rx RING\n");
1096  		return 0;
1097  	}
1098  
1099  	if (txdesc_idx >= ring->size) {
1100  		if (tx)
1101  			seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
1102  				   ring_idx, txdesc_idx, ring->size);
1103  		else
1104  			seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
1105  				   txdesc_idx, ring->size);
1106  		return 0;
1107  	}
1108  
1109  	/* use struct vring_tx_desc for Rx as well,
1110  	 * only field used, .dma.length, is the same
1111  	 */
1112  	d = &ring->va[txdesc_idx].tx.legacy;
1113  	u = (volatile u32 *)d;
1114  	skb = NULL;
1115  
1116  	if (wil->use_enhanced_dma_hw) {
1117  		if (tx) {
1118  			skb = ring->ctx ? ring->ctx[txdesc_idx].skb : NULL;
1119  		} else if (wil->rx_buff_mgmt.buff_arr) {
1120  			struct wil_rx_enhanced_desc *rx_d =
1121  				(struct wil_rx_enhanced_desc *)
1122  				&ring->va[txdesc_idx].rx.enhanced;
1123  			u16 buff_id = le16_to_cpu(rx_d->mac.buff_id);
1124  
1125  			if (!wil_val_in_range(buff_id, 0,
1126  					      wil->rx_buff_mgmt.size))
1127  				seq_printf(s, "invalid buff_id %d\n", buff_id);
1128  			else
1129  				skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
1130  		}
1131  	} else {
1132  		skb = ring->ctx[txdesc_idx].skb;
1133  	}
1134  	if (tx)
1135  		seq_printf(s, "Tx[%2d][%3d] = {\n", ring_idx,
1136  			   txdesc_idx);
1137  	else
1138  		seq_printf(s, "Rx[%3d] = {\n", txdesc_idx);
1139  	seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1140  		   u[0], u[1], u[2], u[3]);
1141  	seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1142  		   u[4], u[5], u[6], u[7]);
1143  	seq_printf(s, "  SKB = 0x%p\n", skb);
1144  
1145  	if (skb) {
1146  		skb_get(skb);
1147  		wil_seq_print_skb(s, skb);
1148  		kfree_skb(skb);
1149  	}
1150  	seq_puts(s, "}\n");
1151  
1152  	return 0;
1153  }
1154  DEFINE_SHOW_ATTRIBUTE(txdesc);
1155  
1156  /*---------Tx/Rx status message------------*/
status_msg_show(struct seq_file * s,void * data)1157  static int status_msg_show(struct seq_file *s, void *data)
1158  {
1159  	struct wil6210_priv *wil = s->private;
1160  	int sring_idx = dbg_sring_index;
1161  	struct wil_status_ring *sring;
1162  	bool tx;
1163  	u32 status_msg_idx = dbg_status_msg_index;
1164  	u32 *u;
1165  
1166  	if (sring_idx >= WIL6210_MAX_STATUS_RINGS) {
1167  		seq_printf(s, "invalid status ring index %d\n", sring_idx);
1168  		return 0;
1169  	}
1170  
1171  	sring = &wil->srings[sring_idx];
1172  	tx = !sring->is_rx;
1173  
1174  	if (!sring->va) {
1175  		seq_printf(s, "No %cX status ring\n", tx ? 'T' : 'R');
1176  		return 0;
1177  	}
1178  
1179  	if (status_msg_idx >= sring->size) {
1180  		seq_printf(s, "%cxDesc index (%d) >= size (%d)\n",
1181  			   tx ? 'T' : 'R', status_msg_idx, sring->size);
1182  		return 0;
1183  	}
1184  
1185  	u = sring->va + (sring->elem_size * status_msg_idx);
1186  
1187  	seq_printf(s, "%cx[%d][%3d] = {\n",
1188  		   tx ? 'T' : 'R', sring_idx, status_msg_idx);
1189  
1190  	seq_printf(s, "  0x%08x 0x%08x 0x%08x 0x%08x\n",
1191  		   u[0], u[1], u[2], u[3]);
1192  	if (!tx && !wil->use_compressed_rx_status)
1193  		seq_printf(s, "  0x%08x 0x%08x 0x%08x 0x%08x\n",
1194  			   u[4], u[5], u[6], u[7]);
1195  
1196  	seq_puts(s, "}\n");
1197  
1198  	return 0;
1199  }
1200  DEFINE_SHOW_ATTRIBUTE(status_msg);
1201  
wil_print_rx_buff(struct seq_file * s,struct list_head * lh)1202  static int wil_print_rx_buff(struct seq_file *s, struct list_head *lh)
1203  {
1204  	struct wil_rx_buff *it;
1205  	int i = 0;
1206  
1207  	list_for_each_entry(it, lh, list) {
1208  		if ((i % 16) == 0 && i != 0)
1209  			seq_puts(s, "\n    ");
1210  		seq_printf(s, "[%4d] ", it->id);
1211  		i++;
1212  	}
1213  	seq_printf(s, "\nNumber of buffers: %u\n", i);
1214  
1215  	return i;
1216  }
1217  
rx_buff_mgmt_show(struct seq_file * s,void * data)1218  static int rx_buff_mgmt_show(struct seq_file *s, void *data)
1219  {
1220  	struct wil6210_priv *wil = s->private;
1221  	struct wil_rx_buff_mgmt *rbm = &wil->rx_buff_mgmt;
1222  	int num_active;
1223  	int num_free;
1224  
1225  	if (!rbm->buff_arr)
1226  		return -EINVAL;
1227  
1228  	seq_printf(s, "  size = %zu\n", rbm->size);
1229  	seq_printf(s, "  free_list_empty_cnt = %lu\n",
1230  		   rbm->free_list_empty_cnt);
1231  
1232  	/* Print active list */
1233  	seq_puts(s, "  Active list:\n");
1234  	num_active = wil_print_rx_buff(s, &rbm->active);
1235  	seq_puts(s, "\n  Free list:\n");
1236  	num_free = wil_print_rx_buff(s, &rbm->free);
1237  
1238  	seq_printf(s, "  Total number of buffers: %u\n",
1239  		   num_active + num_free);
1240  
1241  	return 0;
1242  }
1243  DEFINE_SHOW_ATTRIBUTE(rx_buff_mgmt);
1244  
1245  /*---------beamforming------------*/
wil_bfstatus_str(u32 status)1246  static char *wil_bfstatus_str(u32 status)
1247  {
1248  	switch (status) {
1249  	case 0:
1250  		return "Failed";
1251  	case 1:
1252  		return "OK";
1253  	case 2:
1254  		return "Retrying";
1255  	default:
1256  		return "??";
1257  	}
1258  }
1259  
is_all_zeros(void * const x_,size_t sz)1260  static bool is_all_zeros(void * const x_, size_t sz)
1261  {
1262  	/* if reply is all-0, ignore this CID */
1263  	u32 *x = x_;
1264  	int n;
1265  
1266  	for (n = 0; n < sz / sizeof(*x); n++)
1267  		if (x[n])
1268  			return false;
1269  
1270  	return true;
1271  }
1272  
bf_show(struct seq_file * s,void * data)1273  static int bf_show(struct seq_file *s, void *data)
1274  {
1275  	int rc;
1276  	int i;
1277  	struct wil6210_priv *wil = s->private;
1278  	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
1279  	struct wmi_notify_req_cmd cmd = {
1280  		.interval_usec = 0,
1281  	};
1282  	struct {
1283  		struct wmi_cmd_hdr wmi;
1284  		struct wmi_notify_req_done_event evt;
1285  	} __packed reply;
1286  
1287  	memset(&reply, 0, sizeof(reply));
1288  
1289  	for (i = 0; i < wil->max_assoc_sta; i++) {
1290  		u32 status;
1291  		u8 bf_mcs;
1292  
1293  		cmd.cid = i;
1294  		rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid,
1295  			      &cmd, sizeof(cmd),
1296  			      WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
1297  			      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
1298  		/* if reply is all-0, ignore this CID */
1299  		if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
1300  			continue;
1301  
1302  		status = le32_to_cpu(reply.evt.status);
1303  		bf_mcs = le16_to_cpu(reply.evt.bf_mcs);
1304  		seq_printf(s, "CID %d {\n"
1305  			   "  TSF = 0x%016llx\n"
1306  			   "  TxMCS = %s TxTpt = %4d\n"
1307  			   "  SQI = %4d\n"
1308  			   "  RSSI = %4d\n"
1309  			   "  Status = 0x%08x %s\n"
1310  			   "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
1311  			   "  Goodput(rx:tx) %4d:%4d\n"
1312  			   "}\n",
1313  			   i,
1314  			   le64_to_cpu(reply.evt.tsf),
1315  			   WIL_EXTENDED_MCS_CHECK(bf_mcs),
1316  			   le32_to_cpu(reply.evt.tx_tpt),
1317  			   reply.evt.sqi,
1318  			   reply.evt.rssi,
1319  			   status, wil_bfstatus_str(status),
1320  			   le16_to_cpu(reply.evt.my_rx_sector),
1321  			   le16_to_cpu(reply.evt.my_tx_sector),
1322  			   le16_to_cpu(reply.evt.other_rx_sector),
1323  			   le16_to_cpu(reply.evt.other_tx_sector),
1324  			   le32_to_cpu(reply.evt.rx_goodput),
1325  			   le32_to_cpu(reply.evt.tx_goodput));
1326  	}
1327  	return 0;
1328  }
1329  DEFINE_SHOW_ATTRIBUTE(bf);
1330  
1331  /*---------temp------------*/
print_temp(struct seq_file * s,const char * prefix,s32 t)1332  static void print_temp(struct seq_file *s, const char *prefix, s32 t)
1333  {
1334  	switch (t) {
1335  	case 0:
1336  	case WMI_INVALID_TEMPERATURE:
1337  		seq_printf(s, "%s N/A\n", prefix);
1338  	break;
1339  	default:
1340  		seq_printf(s, "%s %s%d.%03d\n", prefix, (t < 0 ? "-" : ""),
1341  			   abs(t / 1000), abs(t % 1000));
1342  		break;
1343  	}
1344  }
1345  
temp_show(struct seq_file * s,void * data)1346  static int temp_show(struct seq_file *s, void *data)
1347  {
1348  	struct wil6210_priv *wil = s->private;
1349  	int rc, i;
1350  
1351  	if (test_bit(WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF,
1352  		     wil->fw_capabilities)) {
1353  		struct wmi_temp_sense_all_done_event sense_all_evt;
1354  
1355  		wil_dbg_misc(wil,
1356  			     "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is supported");
1357  		rc = wmi_get_all_temperatures(wil, &sense_all_evt);
1358  		if (rc) {
1359  			seq_puts(s, "Failed\n");
1360  			return 0;
1361  		}
1362  		print_temp(s, "T_mac   =",
1363  			   le32_to_cpu(sense_all_evt.baseband_t1000));
1364  		seq_printf(s, "Connected RFs [0x%08x]\n",
1365  			   sense_all_evt.rf_bitmap);
1366  		for (i = 0; i < WMI_MAX_XIF_PORTS_NUM; i++) {
1367  			seq_printf(s, "RF[%d]   = ", i);
1368  			print_temp(s, "",
1369  				   le32_to_cpu(sense_all_evt.rf_t1000[i]));
1370  		}
1371  	} else {
1372  		s32 t_m, t_r;
1373  
1374  		wil_dbg_misc(wil,
1375  			     "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is not supported");
1376  		rc = wmi_get_temperature(wil, &t_m, &t_r);
1377  		if (rc) {
1378  			seq_puts(s, "Failed\n");
1379  			return 0;
1380  		}
1381  		print_temp(s, "T_mac   =", t_m);
1382  		print_temp(s, "T_radio =", t_r);
1383  	}
1384  	return 0;
1385  }
1386  DEFINE_SHOW_ATTRIBUTE(temp);
1387  
1388  /*---------link------------*/
link_show(struct seq_file * s,void * data)1389  static int link_show(struct seq_file *s, void *data)
1390  {
1391  	struct wil6210_priv *wil = s->private;
1392  	struct station_info *sinfo;
1393  	int i, rc = 0;
1394  
1395  	sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
1396  	if (!sinfo)
1397  		return -ENOMEM;
1398  
1399  	for (i = 0; i < wil->max_assoc_sta; i++) {
1400  		struct wil_sta_info *p = &wil->sta[i];
1401  		char *status = "unknown";
1402  		struct wil6210_vif *vif;
1403  		u8 mid;
1404  
1405  		switch (p->status) {
1406  		case wil_sta_unused:
1407  			status = "unused   ";
1408  			break;
1409  		case wil_sta_conn_pending:
1410  			status = "pending  ";
1411  			break;
1412  		case wil_sta_connected:
1413  			status = "connected";
1414  			break;
1415  		}
1416  		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
1417  		seq_printf(s, "[%d][MID %d] %pM %s\n",
1418  			   i, mid, p->addr, status);
1419  
1420  		if (p->status != wil_sta_connected)
1421  			continue;
1422  
1423  		vif = (mid < GET_MAX_VIFS(wil)) ? wil->vifs[mid] : NULL;
1424  		if (vif) {
1425  			rc = wil_cid_fill_sinfo(vif, i, sinfo);
1426  			if (rc)
1427  				goto out;
1428  
1429  			seq_printf(s, "  Tx_mcs = %s\n",
1430  				   WIL_EXTENDED_MCS_CHECK(sinfo->txrate.mcs));
1431  			seq_printf(s, "  Rx_mcs = %s\n",
1432  				   WIL_EXTENDED_MCS_CHECK(sinfo->rxrate.mcs));
1433  			seq_printf(s, "  SQ     = %d\n", sinfo->signal);
1434  		} else {
1435  			seq_puts(s, "  INVALID MID\n");
1436  		}
1437  	}
1438  
1439  out:
1440  	kfree(sinfo);
1441  	return rc;
1442  }
1443  DEFINE_SHOW_ATTRIBUTE(link);
1444  
1445  /*---------info------------*/
info_show(struct seq_file * s,void * data)1446  static int info_show(struct seq_file *s, void *data)
1447  {
1448  	struct wil6210_priv *wil = s->private;
1449  	struct net_device *ndev = wil->main_ndev;
1450  	int is_ac = power_supply_is_system_supplied();
1451  	int rx = atomic_xchg(&wil->isr_count_rx, 0);
1452  	int tx = atomic_xchg(&wil->isr_count_tx, 0);
1453  	static ulong rxf_old, txf_old;
1454  	ulong rxf = ndev->stats.rx_packets;
1455  	ulong txf = ndev->stats.tx_packets;
1456  	unsigned int i;
1457  
1458  	/* >0 : AC; 0 : battery; <0 : error */
1459  	seq_printf(s, "AC powered : %d\n", is_ac);
1460  	seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
1461  	seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
1462  	rxf_old = rxf;
1463  	txf_old = txf;
1464  
1465  #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
1466  	" " __stringify(x) : ""
1467  
1468  	for (i = 0; i < ndev->num_tx_queues; i++) {
1469  		struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
1470  		unsigned long state = txq->state;
1471  
1472  		seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
1473  			   CHECK_QSTATE(DRV_XOFF),
1474  			   CHECK_QSTATE(STACK_XOFF),
1475  			   CHECK_QSTATE(FROZEN)
1476  			  );
1477  	}
1478  #undef CHECK_QSTATE
1479  	return 0;
1480  }
1481  DEFINE_SHOW_ATTRIBUTE(info);
1482  
1483  /*---------recovery------------*/
1484  /* mode = [manual|auto]
1485   * state = [idle|pending|running]
1486   */
wil_read_file_recovery(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1487  static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
1488  				      size_t count, loff_t *ppos)
1489  {
1490  	struct wil6210_priv *wil = file->private_data;
1491  	char buf[80];
1492  	int n;
1493  	static const char * const sstate[] = {"idle", "pending", "running"};
1494  
1495  	n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
1496  		     no_fw_recovery ? "manual" : "auto",
1497  		     sstate[wil->recovery_state]);
1498  
1499  	n = min_t(int, n, sizeof(buf));
1500  
1501  	return simple_read_from_buffer(user_buf, count, ppos,
1502  				       buf, n);
1503  }
1504  
wil_write_file_recovery(struct file * file,const char __user * buf_,size_t count,loff_t * ppos)1505  static ssize_t wil_write_file_recovery(struct file *file,
1506  				       const char __user *buf_,
1507  				       size_t count, loff_t *ppos)
1508  {
1509  	struct wil6210_priv *wil = file->private_data;
1510  	static const char run_command[] = "run";
1511  	char buf[sizeof(run_command) + 1]; /* to detect "runx" */
1512  	ssize_t rc;
1513  
1514  	if (wil->recovery_state != fw_recovery_pending) {
1515  		wil_err(wil, "No recovery pending\n");
1516  		return -EINVAL;
1517  	}
1518  
1519  	if (*ppos != 0) {
1520  		wil_err(wil, "Offset [%d]\n", (int)*ppos);
1521  		return -EINVAL;
1522  	}
1523  
1524  	if (count > sizeof(buf)) {
1525  		wil_err(wil, "Input too long, len = %d\n", (int)count);
1526  		return -EINVAL;
1527  	}
1528  
1529  	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
1530  	if (rc < 0)
1531  		return rc;
1532  
1533  	buf[rc] = '\0';
1534  	if (0 == strcmp(buf, run_command))
1535  		wil_set_recovery_state(wil, fw_recovery_running);
1536  	else
1537  		wil_err(wil, "Bad recovery command \"%s\"\n", buf);
1538  
1539  	return rc;
1540  }
1541  
1542  static const struct file_operations fops_recovery = {
1543  	.read = wil_read_file_recovery,
1544  	.write = wil_write_file_recovery,
1545  	.open  = simple_open,
1546  };
1547  
1548  /*---------Station matrix------------*/
wil_print_rxtid(struct seq_file * s,struct wil_tid_ampdu_rx * r)1549  static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
1550  {
1551  	int i;
1552  	u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
1553  	unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old;
1554  	unsigned long long drop_dup_mcast = r->drop_dup_mcast;
1555  
1556  	seq_printf(s, "([%2d]) 0x%03x [", r->buf_size, r->head_seq_num);
1557  	for (i = 0; i < r->buf_size; i++) {
1558  		if (i == index)
1559  			seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
1560  		else
1561  			seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
1562  	}
1563  	seq_printf(s,
1564  		   "] total %llu drop %llu (dup %llu + old %llu + dup mcast %llu) last 0x%03x\n",
1565  		   r->total, drop_dup + drop_old + drop_dup_mcast, drop_dup,
1566  		   drop_old, drop_dup_mcast, r->ssn_last_drop);
1567  }
1568  
wil_print_rxtid_crypto(struct seq_file * s,int tid,struct wil_tid_crypto_rx * c)1569  static void wil_print_rxtid_crypto(struct seq_file *s, int tid,
1570  				   struct wil_tid_crypto_rx *c)
1571  {
1572  	int i;
1573  
1574  	for (i = 0; i < 4; i++) {
1575  		struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
1576  
1577  		if (cc->key_set)
1578  			goto has_keys;
1579  	}
1580  	return;
1581  
1582  has_keys:
1583  	if (tid < WIL_STA_TID_NUM)
1584  		seq_printf(s, "  [%2d] PN", tid);
1585  	else
1586  		seq_puts(s, "  [GR] PN");
1587  
1588  	for (i = 0; i < 4; i++) {
1589  		struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
1590  
1591  		seq_printf(s, " [%i%s]%6phN", i, cc->key_set ? "+" : "-",
1592  			   cc->pn);
1593  	}
1594  	seq_puts(s, "\n");
1595  }
1596  
sta_show(struct seq_file * s,void * data)1597  static int sta_show(struct seq_file *s, void *data)
1598  __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1599  {
1600  	struct wil6210_priv *wil = s->private;
1601  	int i, tid, mcs;
1602  
1603  	for (i = 0; i < wil->max_assoc_sta; i++) {
1604  		struct wil_sta_info *p = &wil->sta[i];
1605  		char *status = "unknown";
1606  		u8 aid = 0;
1607  		u8 mid;
1608  		bool sta_connected = false;
1609  
1610  		switch (p->status) {
1611  		case wil_sta_unused:
1612  			status = "unused   ";
1613  			break;
1614  		case wil_sta_conn_pending:
1615  			status = "pending  ";
1616  			break;
1617  		case wil_sta_connected:
1618  			status = "connected";
1619  			aid = p->aid;
1620  			break;
1621  		}
1622  		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
1623  		if (mid < GET_MAX_VIFS(wil)) {
1624  			struct wil6210_vif *vif = wil->vifs[mid];
1625  
1626  			if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
1627  			    p->status == wil_sta_connected)
1628  				sta_connected = true;
1629  		}
1630  		/* print roam counter only for connected stations */
1631  		if (sta_connected)
1632  			seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n",
1633  				   i, p->addr, p->stats.ft_roams, mid, aid);
1634  		else
1635  			seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i,
1636  				   p->addr, status, mid, aid);
1637  
1638  		if (p->status == wil_sta_connected) {
1639  			spin_lock_bh(&p->tid_rx_lock);
1640  			for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
1641  				struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
1642  				struct wil_tid_crypto_rx *c =
1643  						&p->tid_crypto_rx[tid];
1644  
1645  				if (r) {
1646  					seq_printf(s, "  [%2d] ", tid);
1647  					wil_print_rxtid(s, r);
1648  				}
1649  
1650  				wil_print_rxtid_crypto(s, tid, c);
1651  			}
1652  			wil_print_rxtid_crypto(s, WIL_STA_TID_NUM,
1653  					       &p->group_crypto_rx);
1654  			spin_unlock_bh(&p->tid_rx_lock);
1655  			seq_printf(s,
1656  				   "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n",
1657  				   p->stats.rx_non_data_frame,
1658  				   p->stats.rx_short_frame,
1659  				   p->stats.rx_large_frame,
1660  				   p->stats.rx_replay);
1661  			seq_printf(s,
1662  				   "mic error %lu, key error %lu, amsdu error %lu, csum error %lu\n",
1663  				   p->stats.rx_mic_error,
1664  				   p->stats.rx_key_error,
1665  				   p->stats.rx_amsdu_error,
1666  				   p->stats.rx_csum_err);
1667  
1668  			seq_puts(s, "Rx/MCS:");
1669  			for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
1670  			     mcs++)
1671  				seq_printf(s, " %lld",
1672  					   p->stats.rx_per_mcs[mcs]);
1673  			seq_puts(s, "\n");
1674  		}
1675  	}
1676  
1677  	return 0;
1678  }
1679  DEFINE_SHOW_ATTRIBUTE(sta);
1680  
mids_show(struct seq_file * s,void * data)1681  static int mids_show(struct seq_file *s, void *data)
1682  {
1683  	struct wil6210_priv *wil = s->private;
1684  	struct wil6210_vif *vif;
1685  	struct net_device *ndev;
1686  	int i;
1687  
1688  	mutex_lock(&wil->vif_mutex);
1689  	for (i = 0; i < GET_MAX_VIFS(wil); i++) {
1690  		vif = wil->vifs[i];
1691  
1692  		if (vif) {
1693  			ndev = vif_to_ndev(vif);
1694  			seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr,
1695  				   ndev->name);
1696  		} else {
1697  			seq_printf(s, "[%d] unused\n", i);
1698  		}
1699  	}
1700  	mutex_unlock(&wil->vif_mutex);
1701  
1702  	return 0;
1703  }
1704  DEFINE_SHOW_ATTRIBUTE(mids);
1705  
wil_tx_latency_debugfs_show(struct seq_file * s,void * data)1706  static int wil_tx_latency_debugfs_show(struct seq_file *s, void *data)
1707  __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
1708  {
1709  	struct wil6210_priv *wil = s->private;
1710  	int i, bin;
1711  
1712  	for (i = 0; i < wil->max_assoc_sta; i++) {
1713  		struct wil_sta_info *p = &wil->sta[i];
1714  		char *status = "unknown";
1715  		u8 aid = 0;
1716  		u8 mid;
1717  
1718  		if (!p->tx_latency_bins)
1719  			continue;
1720  
1721  		switch (p->status) {
1722  		case wil_sta_unused:
1723  			status = "unused   ";
1724  			break;
1725  		case wil_sta_conn_pending:
1726  			status = "pending  ";
1727  			break;
1728  		case wil_sta_connected:
1729  			status = "connected";
1730  			aid = p->aid;
1731  			break;
1732  		}
1733  		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
1734  		seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
1735  			   mid, aid);
1736  
1737  		if (p->status == wil_sta_connected) {
1738  			u64 num_packets = 0;
1739  			u64 tx_latency_avg = p->stats.tx_latency_total_us;
1740  
1741  			seq_puts(s, "Tx/Latency bin:");
1742  			for (bin = 0; bin < WIL_NUM_LATENCY_BINS; bin++) {
1743  				seq_printf(s, " %lld",
1744  					   p->tx_latency_bins[bin]);
1745  				num_packets += p->tx_latency_bins[bin];
1746  			}
1747  			seq_puts(s, "\n");
1748  			if (!num_packets)
1749  				continue;
1750  			do_div(tx_latency_avg, num_packets);
1751  			seq_printf(s, "Tx/Latency min/avg/max (us): %d/%lld/%d",
1752  				   p->stats.tx_latency_min_us,
1753  				   tx_latency_avg,
1754  				   p->stats.tx_latency_max_us);
1755  
1756  			seq_puts(s, "\n");
1757  		}
1758  	}
1759  
1760  	return 0;
1761  }
1762  
wil_tx_latency_seq_open(struct inode * inode,struct file * file)1763  static int wil_tx_latency_seq_open(struct inode *inode, struct file *file)
1764  {
1765  	return single_open(file, wil_tx_latency_debugfs_show,
1766  			   inode->i_private);
1767  }
1768  
wil_tx_latency_write(struct file * file,const char __user * buf,size_t len,loff_t * ppos)1769  static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf,
1770  				    size_t len, loff_t *ppos)
1771  {
1772  	struct seq_file *s = file->private_data;
1773  	struct wil6210_priv *wil = s->private;
1774  	int val, rc, i;
1775  	bool enable;
1776  
1777  	rc = kstrtoint_from_user(buf, len, 0, &val);
1778  	if (rc) {
1779  		wil_err(wil, "Invalid argument\n");
1780  		return rc;
1781  	}
1782  	if (val == 1)
1783  		/* default resolution */
1784  		val = 500;
1785  	if (val && (val < 50 || val > 1000)) {
1786  		wil_err(wil, "Invalid resolution %d\n", val);
1787  		return -EINVAL;
1788  	}
1789  
1790  	enable = !!val;
1791  	if (wil->tx_latency == enable)
1792  		return len;
1793  
1794  	wil_info(wil, "%s TX latency measurements (resolution %dusec)\n",
1795  		 enable ? "Enabling" : "Disabling", val);
1796  
1797  	if (enable) {
1798  		size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS;
1799  
1800  		wil->tx_latency_res = val;
1801  		for (i = 0; i < wil->max_assoc_sta; i++) {
1802  			struct wil_sta_info *sta = &wil->sta[i];
1803  
1804  			kfree(sta->tx_latency_bins);
1805  			sta->tx_latency_bins = kzalloc(sz, GFP_KERNEL);
1806  			if (!sta->tx_latency_bins)
1807  				return -ENOMEM;
1808  			sta->stats.tx_latency_min_us = U32_MAX;
1809  			sta->stats.tx_latency_max_us = 0;
1810  			sta->stats.tx_latency_total_us = 0;
1811  		}
1812  	}
1813  	wil->tx_latency = enable;
1814  
1815  	return len;
1816  }
1817  
1818  static const struct file_operations fops_tx_latency = {
1819  	.open		= wil_tx_latency_seq_open,
1820  	.release	= single_release,
1821  	.read		= seq_read,
1822  	.write		= wil_tx_latency_write,
1823  	.llseek		= seq_lseek,
1824  };
1825  
wil_link_stats_print_basic(struct wil6210_vif * vif,struct seq_file * s,struct wmi_link_stats_basic * basic)1826  static void wil_link_stats_print_basic(struct wil6210_vif *vif,
1827  				       struct seq_file *s,
1828  				       struct wmi_link_stats_basic *basic)
1829  {
1830  	char per[5] = "?";
1831  
1832  	if (basic->per_average != 0xff)
1833  		snprintf(per, sizeof(per), "%d%%", basic->per_average);
1834  
1835  	seq_printf(s, "CID %d {\n"
1836  		   "\tTxMCS %s TxTpt %d\n"
1837  		   "\tGoodput(rx:tx) %d:%d\n"
1838  		   "\tRxBcastFrames %d\n"
1839  		   "\tRSSI %d SQI %d SNR %d PER %s\n"
1840  		   "\tRx RFC %d Ant num %d\n"
1841  		   "\tSectors(rx:tx) my %d:%d peer %d:%d\n"
1842  		   "}\n",
1843  		   basic->cid,
1844  		   WIL_EXTENDED_MCS_CHECK(basic->bf_mcs),
1845  		   le32_to_cpu(basic->tx_tpt),
1846  		   le32_to_cpu(basic->rx_goodput),
1847  		   le32_to_cpu(basic->tx_goodput),
1848  		   le32_to_cpu(basic->rx_bcast_frames),
1849  		   basic->rssi, basic->sqi, basic->snr, per,
1850  		   basic->selected_rfc, basic->rx_effective_ant_num,
1851  		   basic->my_rx_sector, basic->my_tx_sector,
1852  		   basic->other_rx_sector, basic->other_tx_sector);
1853  }
1854  
wil_link_stats_print_global(struct wil6210_priv * wil,struct seq_file * s,struct wmi_link_stats_global * global)1855  static void wil_link_stats_print_global(struct wil6210_priv *wil,
1856  					struct seq_file *s,
1857  					struct wmi_link_stats_global *global)
1858  {
1859  	seq_printf(s, "Frames(rx:tx) %d:%d\n"
1860  		   "BA Frames(rx:tx) %d:%d\n"
1861  		   "Beacons %d\n"
1862  		   "Rx Errors (MIC:CRC) %d:%d\n"
1863  		   "Tx Errors (no ack) %d\n",
1864  		   le32_to_cpu(global->rx_frames),
1865  		   le32_to_cpu(global->tx_frames),
1866  		   le32_to_cpu(global->rx_ba_frames),
1867  		   le32_to_cpu(global->tx_ba_frames),
1868  		   le32_to_cpu(global->tx_beacons),
1869  		   le32_to_cpu(global->rx_mic_errors),
1870  		   le32_to_cpu(global->rx_crc_errors),
1871  		   le32_to_cpu(global->tx_fail_no_ack));
1872  }
1873  
wil_link_stats_debugfs_show_vif(struct wil6210_vif * vif,struct seq_file * s)1874  static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif,
1875  					    struct seq_file *s)
1876  {
1877  	struct wil6210_priv *wil = vif_to_wil(vif);
1878  	struct wmi_link_stats_basic *stats;
1879  	int i;
1880  
1881  	if (!vif->fw_stats_ready) {
1882  		seq_puts(s, "no statistics\n");
1883  		return;
1884  	}
1885  
1886  	seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf);
1887  	for (i = 0; i < wil->max_assoc_sta; i++) {
1888  		if (wil->sta[i].status == wil_sta_unused)
1889  			continue;
1890  		if (wil->sta[i].mid != vif->mid)
1891  			continue;
1892  
1893  		stats = &wil->sta[i].fw_stats_basic;
1894  		wil_link_stats_print_basic(vif, s, stats);
1895  	}
1896  }
1897  
wil_link_stats_debugfs_show(struct seq_file * s,void * data)1898  static int wil_link_stats_debugfs_show(struct seq_file *s, void *data)
1899  {
1900  	struct wil6210_priv *wil = s->private;
1901  	struct wil6210_vif *vif;
1902  	int i, rc;
1903  
1904  	rc = mutex_lock_interruptible(&wil->vif_mutex);
1905  	if (rc)
1906  		return rc;
1907  
1908  	/* iterate over all MIDs and show per-cid statistics. Then show the
1909  	 * global statistics
1910  	 */
1911  	for (i = 0; i < GET_MAX_VIFS(wil); i++) {
1912  		vif = wil->vifs[i];
1913  
1914  		seq_printf(s, "MID %d ", i);
1915  		if (!vif) {
1916  			seq_puts(s, "unused\n");
1917  			continue;
1918  		}
1919  
1920  		wil_link_stats_debugfs_show_vif(vif, s);
1921  	}
1922  
1923  	mutex_unlock(&wil->vif_mutex);
1924  
1925  	return 0;
1926  }
1927  
wil_link_stats_seq_open(struct inode * inode,struct file * file)1928  static int wil_link_stats_seq_open(struct inode *inode, struct file *file)
1929  {
1930  	return single_open(file, wil_link_stats_debugfs_show, inode->i_private);
1931  }
1932  
wil_link_stats_write(struct file * file,const char __user * buf,size_t len,loff_t * ppos)1933  static ssize_t wil_link_stats_write(struct file *file, const char __user *buf,
1934  				    size_t len, loff_t *ppos)
1935  {
1936  	struct seq_file *s = file->private_data;
1937  	struct wil6210_priv *wil = s->private;
1938  	int cid, interval, rc, i;
1939  	struct wil6210_vif *vif;
1940  	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
1941  
1942  	if (!kbuf)
1943  		return -ENOMEM;
1944  
1945  	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
1946  	if (rc != len) {
1947  		kfree(kbuf);
1948  		return rc >= 0 ? -EIO : rc;
1949  	}
1950  
1951  	kbuf[len] = '\0';
1952  	/* specify cid (use -1 for all cids) and snapshot interval in ms */
1953  	rc = sscanf(kbuf, "%d %d", &cid, &interval);
1954  	kfree(kbuf);
1955  	if (rc < 0)
1956  		return rc;
1957  	if (rc < 2 || interval < 0)
1958  		return -EINVAL;
1959  
1960  	wil_info(wil, "request link statistics, cid %d interval %d\n",
1961  		 cid, interval);
1962  
1963  	rc = mutex_lock_interruptible(&wil->vif_mutex);
1964  	if (rc)
1965  		return rc;
1966  
1967  	for (i = 0; i < GET_MAX_VIFS(wil); i++) {
1968  		vif = wil->vifs[i];
1969  		if (!vif)
1970  			continue;
1971  
1972  		rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_BASIC,
1973  					(cid == -1 ? 0xff : cid), interval);
1974  		if (rc)
1975  			wil_err(wil, "link statistics failed for mid %d\n", i);
1976  	}
1977  	mutex_unlock(&wil->vif_mutex);
1978  
1979  	return len;
1980  }
1981  
1982  static const struct file_operations fops_link_stats = {
1983  	.open		= wil_link_stats_seq_open,
1984  	.release	= single_release,
1985  	.read		= seq_read,
1986  	.write		= wil_link_stats_write,
1987  	.llseek		= seq_lseek,
1988  };
1989  
1990  static int
wil_link_stats_global_debugfs_show(struct seq_file * s,void * data)1991  wil_link_stats_global_debugfs_show(struct seq_file *s, void *data)
1992  {
1993  	struct wil6210_priv *wil = s->private;
1994  
1995  	if (!wil->fw_stats_global.ready)
1996  		return 0;
1997  
1998  	seq_printf(s, "TSF %lld\n", wil->fw_stats_global.tsf);
1999  	wil_link_stats_print_global(wil, s, &wil->fw_stats_global.stats);
2000  
2001  	return 0;
2002  }
2003  
2004  static int
wil_link_stats_global_seq_open(struct inode * inode,struct file * file)2005  wil_link_stats_global_seq_open(struct inode *inode, struct file *file)
2006  {
2007  	return single_open(file, wil_link_stats_global_debugfs_show,
2008  			   inode->i_private);
2009  }
2010  
2011  static ssize_t
wil_link_stats_global_write(struct file * file,const char __user * buf,size_t len,loff_t * ppos)2012  wil_link_stats_global_write(struct file *file, const char __user *buf,
2013  			    size_t len, loff_t *ppos)
2014  {
2015  	struct seq_file *s = file->private_data;
2016  	struct wil6210_priv *wil = s->private;
2017  	int interval, rc;
2018  	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2019  
2020  	/* specify snapshot interval in ms */
2021  	rc = kstrtoint_from_user(buf, len, 0, &interval);
2022  	if (rc || interval < 0) {
2023  		wil_err(wil, "Invalid argument\n");
2024  		return -EINVAL;
2025  	}
2026  
2027  	wil_info(wil, "request global link stats, interval %d\n", interval);
2028  
2029  	rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_GLOBAL, 0, interval);
2030  	if (rc)
2031  		wil_err(wil, "global link stats failed %d\n", rc);
2032  
2033  	return rc ? rc : len;
2034  }
2035  
2036  static const struct file_operations fops_link_stats_global = {
2037  	.open		= wil_link_stats_global_seq_open,
2038  	.release	= single_release,
2039  	.read		= seq_read,
2040  	.write		= wil_link_stats_global_write,
2041  	.llseek		= seq_lseek,
2042  };
2043  
wil_read_file_led_cfg(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)2044  static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
2045  				     size_t count, loff_t *ppos)
2046  {
2047  	char buf[80];
2048  	int n;
2049  
2050  	n = snprintf(buf, sizeof(buf),
2051  		     "led_id is set to %d, echo 1 to enable, 0 to disable\n",
2052  		     led_id);
2053  
2054  	n = min_t(int, n, sizeof(buf));
2055  
2056  	return simple_read_from_buffer(user_buf, count, ppos,
2057  				       buf, n);
2058  }
2059  
wil_write_file_led_cfg(struct file * file,const char __user * buf_,size_t count,loff_t * ppos)2060  static ssize_t wil_write_file_led_cfg(struct file *file,
2061  				      const char __user *buf_,
2062  				      size_t count, loff_t *ppos)
2063  {
2064  	struct wil6210_priv *wil = file->private_data;
2065  	int val;
2066  	int rc;
2067  
2068  	rc = kstrtoint_from_user(buf_, count, 0, &val);
2069  	if (rc) {
2070  		wil_err(wil, "Invalid argument\n");
2071  		return rc;
2072  	}
2073  
2074  	wil_info(wil, "%s led %d\n", val ? "Enabling" : "Disabling", led_id);
2075  	rc = wmi_led_cfg(wil, val);
2076  	if (rc) {
2077  		wil_info(wil, "%s led %d failed\n",
2078  			 val ? "Enabling" : "Disabling", led_id);
2079  		return rc;
2080  	}
2081  
2082  	return count;
2083  }
2084  
2085  static const struct file_operations fops_led_cfg = {
2086  	.read = wil_read_file_led_cfg,
2087  	.write = wil_write_file_led_cfg,
2088  	.open  = simple_open,
2089  };
2090  
2091  /* led_blink_time, write:
2092   * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
2093   */
wil_write_led_blink_time(struct file * file,const char __user * buf,size_t len,loff_t * ppos)2094  static ssize_t wil_write_led_blink_time(struct file *file,
2095  					const char __user *buf,
2096  					size_t len, loff_t *ppos)
2097  {
2098  	int rc;
2099  	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
2100  
2101  	if (!kbuf)
2102  		return -ENOMEM;
2103  
2104  	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
2105  	if (rc != len) {
2106  		kfree(kbuf);
2107  		return rc >= 0 ? -EIO : rc;
2108  	}
2109  
2110  	kbuf[len] = '\0';
2111  	rc = sscanf(kbuf, "%d %d %d %d %d %d",
2112  		    &led_blink_time[WIL_LED_TIME_SLOW].on_ms,
2113  		    &led_blink_time[WIL_LED_TIME_SLOW].off_ms,
2114  		    &led_blink_time[WIL_LED_TIME_MED].on_ms,
2115  		    &led_blink_time[WIL_LED_TIME_MED].off_ms,
2116  		    &led_blink_time[WIL_LED_TIME_FAST].on_ms,
2117  		    &led_blink_time[WIL_LED_TIME_FAST].off_ms);
2118  	kfree(kbuf);
2119  
2120  	if (rc < 0)
2121  		return rc;
2122  	if (rc < 6)
2123  		return -EINVAL;
2124  
2125  	return len;
2126  }
2127  
wil_read_led_blink_time(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)2128  static ssize_t wil_read_led_blink_time(struct file *file, char __user *user_buf,
2129  				       size_t count, loff_t *ppos)
2130  {
2131  	static char text[400];
2132  
2133  	snprintf(text, sizeof(text),
2134  		 "To set led blink on/off time variables write:\n"
2135  		 "<blink_on_slow> <blink_off_slow> <blink_on_med> "
2136  		 "<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
2137  		 "The current values are:\n"
2138  		 "%d %d %d %d %d %d\n",
2139  		 led_blink_time[WIL_LED_TIME_SLOW].on_ms,
2140  		 led_blink_time[WIL_LED_TIME_SLOW].off_ms,
2141  		 led_blink_time[WIL_LED_TIME_MED].on_ms,
2142  		 led_blink_time[WIL_LED_TIME_MED].off_ms,
2143  		 led_blink_time[WIL_LED_TIME_FAST].on_ms,
2144  		 led_blink_time[WIL_LED_TIME_FAST].off_ms);
2145  
2146  	return simple_read_from_buffer(user_buf, count, ppos, text,
2147  				       sizeof(text));
2148  }
2149  
2150  static const struct file_operations fops_led_blink_time = {
2151  	.read = wil_read_led_blink_time,
2152  	.write = wil_write_led_blink_time,
2153  	.open  = simple_open,
2154  };
2155  
2156  /*---------FW capabilities------------*/
fw_capabilities_show(struct seq_file * s,void * data)2157  static int fw_capabilities_show(struct seq_file *s, void *data)
2158  {
2159  	struct wil6210_priv *wil = s->private;
2160  
2161  	seq_printf(s, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX,
2162  		   wil->fw_capabilities);
2163  
2164  	return 0;
2165  }
2166  DEFINE_SHOW_ATTRIBUTE(fw_capabilities);
2167  
2168  /*---------FW version------------*/
fw_version_show(struct seq_file * s,void * data)2169  static int fw_version_show(struct seq_file *s, void *data)
2170  {
2171  	struct wil6210_priv *wil = s->private;
2172  
2173  	if (wil->fw_version[0])
2174  		seq_printf(s, "%s\n", wil->fw_version);
2175  	else
2176  		seq_puts(s, "N/A\n");
2177  
2178  	return 0;
2179  }
2180  DEFINE_SHOW_ATTRIBUTE(fw_version);
2181  
2182  /*---------suspend_stats---------*/
wil_write_suspend_stats(struct file * file,const char __user * buf,size_t len,loff_t * ppos)2183  static ssize_t wil_write_suspend_stats(struct file *file,
2184  				       const char __user *buf,
2185  				       size_t len, loff_t *ppos)
2186  {
2187  	struct wil6210_priv *wil = file->private_data;
2188  
2189  	memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
2190  
2191  	return len;
2192  }
2193  
wil_read_suspend_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)2194  static ssize_t wil_read_suspend_stats(struct file *file,
2195  				      char __user *user_buf,
2196  				      size_t count, loff_t *ppos)
2197  {
2198  	struct wil6210_priv *wil = file->private_data;
2199  	char *text;
2200  	int n, ret, text_size = 500;
2201  
2202  	text = kmalloc(text_size, GFP_KERNEL);
2203  	if (!text)
2204  		return -ENOMEM;
2205  
2206  	n = snprintf(text, text_size,
2207  		     "Radio on suspend statistics:\n"
2208  		     "successful suspends:%ld failed suspends:%ld\n"
2209  		     "successful resumes:%ld failed resumes:%ld\n"
2210  		     "rejected by device:%ld\n"
2211  		     "Radio off suspend statistics:\n"
2212  		     "successful suspends:%ld failed suspends:%ld\n"
2213  		     "successful resumes:%ld failed resumes:%ld\n"
2214  		     "General statistics:\n"
2215  		     "rejected by host:%ld\n",
2216  		     wil->suspend_stats.r_on.successful_suspends,
2217  		     wil->suspend_stats.r_on.failed_suspends,
2218  		     wil->suspend_stats.r_on.successful_resumes,
2219  		     wil->suspend_stats.r_on.failed_resumes,
2220  		     wil->suspend_stats.rejected_by_device,
2221  		     wil->suspend_stats.r_off.successful_suspends,
2222  		     wil->suspend_stats.r_off.failed_suspends,
2223  		     wil->suspend_stats.r_off.successful_resumes,
2224  		     wil->suspend_stats.r_off.failed_resumes,
2225  		     wil->suspend_stats.rejected_by_host);
2226  
2227  	n = min_t(int, n, text_size);
2228  
2229  	ret = simple_read_from_buffer(user_buf, count, ppos, text, n);
2230  
2231  	kfree(text);
2232  
2233  	return ret;
2234  }
2235  
2236  static const struct file_operations fops_suspend_stats = {
2237  	.read = wil_read_suspend_stats,
2238  	.write = wil_write_suspend_stats,
2239  	.open  = simple_open,
2240  };
2241  
2242  /*---------compressed_rx_status---------*/
wil_compressed_rx_status_write(struct file * file,const char __user * buf,size_t len,loff_t * ppos)2243  static ssize_t wil_compressed_rx_status_write(struct file *file,
2244  					      const char __user *buf,
2245  					      size_t len, loff_t *ppos)
2246  {
2247  	struct seq_file *s = file->private_data;
2248  	struct wil6210_priv *wil = s->private;
2249  	int compressed_rx_status;
2250  	int rc;
2251  
2252  	rc = kstrtoint_from_user(buf, len, 0, &compressed_rx_status);
2253  	if (rc) {
2254  		wil_err(wil, "Invalid argument\n");
2255  		return rc;
2256  	}
2257  
2258  	if (wil_has_active_ifaces(wil, true, false)) {
2259  		wil_err(wil, "cannot change edma config after iface is up\n");
2260  		return -EPERM;
2261  	}
2262  
2263  	wil_info(wil, "%sable compressed_rx_status\n",
2264  		 compressed_rx_status ? "En" : "Dis");
2265  
2266  	wil->use_compressed_rx_status = compressed_rx_status;
2267  
2268  	return len;
2269  }
2270  
2271  static int
wil_compressed_rx_status_show(struct seq_file * s,void * data)2272  wil_compressed_rx_status_show(struct seq_file *s, void *data)
2273  {
2274  	struct wil6210_priv *wil = s->private;
2275  
2276  	seq_printf(s, "%d\n", wil->use_compressed_rx_status);
2277  
2278  	return 0;
2279  }
2280  
2281  static int
wil_compressed_rx_status_seq_open(struct inode * inode,struct file * file)2282  wil_compressed_rx_status_seq_open(struct inode *inode, struct file *file)
2283  {
2284  	return single_open(file, wil_compressed_rx_status_show,
2285  			   inode->i_private);
2286  }
2287  
2288  static const struct file_operations fops_compressed_rx_status = {
2289  	.open  = wil_compressed_rx_status_seq_open,
2290  	.release = single_release,
2291  	.read = seq_read,
2292  	.write = wil_compressed_rx_status_write,
2293  	.llseek	= seq_lseek,
2294  };
2295  
2296  /*----------------*/
wil6210_debugfs_init_blobs(struct wil6210_priv * wil,struct dentry * dbg)2297  static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
2298  				       struct dentry *dbg)
2299  {
2300  	int i;
2301  	char name[32];
2302  
2303  	for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
2304  		struct wil_blob_wrapper *wil_blob = &wil->blobs[i];
2305  		struct debugfs_blob_wrapper *blob = &wil_blob->blob;
2306  		const struct fw_map *map = &fw_mapping[i];
2307  
2308  		if (!map->name)
2309  			continue;
2310  
2311  		wil_blob->wil = wil;
2312  		blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
2313  		blob->size = map->to - map->from;
2314  		snprintf(name, sizeof(name), "blob_%s", map->name);
2315  		wil_debugfs_create_ioblob(name, 0444, dbg, wil_blob);
2316  	}
2317  }
2318  
2319  /* misc files */
2320  static const struct {
2321  	const char *name;
2322  	umode_t mode;
2323  	const struct file_operations *fops;
2324  } dbg_files[] = {
2325  	{"mbox",	0444,		&mbox_fops},
2326  	{"rings",	0444,		&ring_fops},
2327  	{"stations", 0444,		&sta_fops},
2328  	{"mids",	0444,		&mids_fops},
2329  	{"desc",	0444,		&txdesc_fops},
2330  	{"bf",		0444,		&bf_fops},
2331  	{"mem_val",	0644,		&memread_fops},
2332  	{"rxon",	0244,		&fops_rxon},
2333  	{"tx_mgmt",	0244,		&fops_txmgmt},
2334  	{"wmi_send", 0244,		&fops_wmi},
2335  	{"back",	0644,		&fops_back},
2336  	{"pmccfg",	0644,		&fops_pmccfg},
2337  	{"pmcdata",	0444,		&fops_pmcdata},
2338  	{"pmcring",	0444,		&fops_pmcring},
2339  	{"temp",	0444,		&temp_fops},
2340  	{"link",	0444,		&link_fops},
2341  	{"info",	0444,		&info_fops},
2342  	{"recovery", 0644,		&fops_recovery},
2343  	{"led_cfg",	0644,		&fops_led_cfg},
2344  	{"led_blink_time",	0644,	&fops_led_blink_time},
2345  	{"fw_capabilities",	0444,	&fw_capabilities_fops},
2346  	{"fw_version",	0444,		&fw_version_fops},
2347  	{"suspend_stats",	0644,	&fops_suspend_stats},
2348  	{"compressed_rx_status", 0644,	&fops_compressed_rx_status},
2349  	{"srings",	0444,		&srings_fops},
2350  	{"status_msg",	0444,		&status_msg_fops},
2351  	{"rx_buff_mgmt",	0444,	&rx_buff_mgmt_fops},
2352  	{"tx_latency",	0644,		&fops_tx_latency},
2353  	{"link_stats",	0644,		&fops_link_stats},
2354  	{"link_stats_global",	0644,	&fops_link_stats_global},
2355  	{"rbufcap",	0244,		&fops_rbufcap},
2356  };
2357  
wil6210_debugfs_init_files(struct wil6210_priv * wil,struct dentry * dbg)2358  static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
2359  				       struct dentry *dbg)
2360  {
2361  	int i;
2362  
2363  	for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
2364  		debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
2365  				    wil, dbg_files[i].fops);
2366  }
2367  
2368  /* interrupt control blocks */
2369  static const struct {
2370  	const char *name;
2371  	u32 icr_off;
2372  } dbg_icr[] = {
2373  	{"USER_ICR",		HOSTADDR(RGF_USER_USER_ICR)},
2374  	{"DMA_EP_TX_ICR",	HOSTADDR(RGF_DMA_EP_TX_ICR)},
2375  	{"DMA_EP_RX_ICR",	HOSTADDR(RGF_DMA_EP_RX_ICR)},
2376  	{"DMA_EP_MISC_ICR",	HOSTADDR(RGF_DMA_EP_MISC_ICR)},
2377  };
2378  
wil6210_debugfs_init_isr(struct wil6210_priv * wil,struct dentry * dbg)2379  static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
2380  				     struct dentry *dbg)
2381  {
2382  	int i;
2383  
2384  	for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
2385  		wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
2386  					   dbg_icr[i].icr_off);
2387  }
2388  
2389  #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
2390  	offsetof(struct wil6210_priv, name), type}
2391  
2392  /* fields in struct wil6210_priv */
2393  static const struct dbg_off dbg_wil_off[] = {
2394  	WIL_FIELD(status[0],	0644,	doff_ulong),
2395  	WIL_FIELD(hw_version,	0444,	doff_x32),
2396  	WIL_FIELD(recovery_count, 0444,	doff_u32),
2397  	WIL_FIELD(discovery_mode, 0644,	doff_u8),
2398  	WIL_FIELD(chip_revision, 0444,	doff_u8),
2399  	WIL_FIELD(abft_len, 0644,		doff_u8),
2400  	WIL_FIELD(wakeup_trigger, 0644,		doff_u8),
2401  	WIL_FIELD(ring_idle_trsh, 0644,	doff_u32),
2402  	WIL_FIELD(num_rx_status_rings, 0644,	doff_u8),
2403  	WIL_FIELD(rx_status_ring_order, 0644,	doff_u32),
2404  	WIL_FIELD(tx_status_ring_order, 0644,	doff_u32),
2405  	WIL_FIELD(rx_buff_id_count, 0644,	doff_u32),
2406  	WIL_FIELD(amsdu_en, 0644,	doff_u8),
2407  	{},
2408  };
2409  
2410  static const struct dbg_off dbg_wil_regs[] = {
2411  	{"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
2412  		doff_io32},
2413  	{"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
2414  	{"RGF_USER_USAGE_2", 0444, HOSTADDR(RGF_USER_USAGE_2), doff_io32},
2415  	{},
2416  };
2417  
2418  /* static parameters */
2419  static const struct dbg_off dbg_statics[] = {
2420  	{"desc_index",	0644, (ulong)&dbg_txdesc_index, doff_u32},
2421  	{"ring_index",	0644, (ulong)&dbg_ring_index, doff_u32},
2422  	{"mem_addr",	0644, (ulong)&mem_addr, doff_u32},
2423  	{"led_polarity", 0644, (ulong)&led_polarity, doff_u8},
2424  	{"status_index", 0644, (ulong)&dbg_status_msg_index, doff_u32},
2425  	{"sring_index",	0644, (ulong)&dbg_sring_index, doff_u32},
2426  	{"drop_if_ring_full", 0644, (ulong)&drop_if_ring_full, doff_u8},
2427  	{},
2428  };
2429  
2430  static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) +
2431  				ARRAY_SIZE(dbg_wil_regs) - 1 +
2432  				ARRAY_SIZE(pseudo_isr_off) - 1 +
2433  				ARRAY_SIZE(lgc_itr_cnt_off) - 1 +
2434  				ARRAY_SIZE(tx_itr_cnt_off) - 1 +
2435  				ARRAY_SIZE(rx_itr_cnt_off) - 1;
2436  
wil6210_debugfs_init(struct wil6210_priv * wil)2437  int wil6210_debugfs_init(struct wil6210_priv *wil)
2438  {
2439  	struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
2440  			wil_to_wiphy(wil)->debugfsdir);
2441  	if (IS_ERR_OR_NULL(dbg))
2442  		return -ENODEV;
2443  
2444  	wil->dbg_data.data_arr = kcalloc(dbg_off_count,
2445  					 sizeof(struct wil_debugfs_iomem_data),
2446  					 GFP_KERNEL);
2447  	if (!wil->dbg_data.data_arr) {
2448  		debugfs_remove_recursive(dbg);
2449  		wil->debug = NULL;
2450  		return -ENOMEM;
2451  	}
2452  
2453  	wil->dbg_data.iomem_data_count = 0;
2454  
2455  	wil_pmc_init(wil);
2456  
2457  	wil6210_debugfs_init_files(wil, dbg);
2458  	wil6210_debugfs_init_isr(wil, dbg);
2459  	wil6210_debugfs_init_blobs(wil, dbg);
2460  	wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
2461  	wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
2462  				    dbg_wil_regs);
2463  	wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
2464  
2465  	wil6210_debugfs_create_pseudo_ISR(wil, dbg);
2466  
2467  	wil6210_debugfs_create_ITR_CNT(wil, dbg);
2468  
2469  	return 0;
2470  }
2471  
wil6210_debugfs_remove(struct wil6210_priv * wil)2472  void wil6210_debugfs_remove(struct wil6210_priv *wil)
2473  {
2474  	int i;
2475  
2476  	debugfs_remove_recursive(wil->debug);
2477  	wil->debug = NULL;
2478  
2479  	kfree(wil->dbg_data.data_arr);
2480  	for (i = 0; i < wil->max_assoc_sta; i++)
2481  		kfree(wil->sta[i].tx_latency_bins);
2482  
2483  	/* free pmc memory without sending command to fw, as it will
2484  	 * be reset on the way down anyway
2485  	 */
2486  	wil_pmc_free(wil, false);
2487  }
2488