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