cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

debugfs.c (64279B)


      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 */
     19static u32 mem_addr;
     20static u32 dbg_txdesc_index;
     21static u32 dbg_ring_index; /* 24+ for Rx, 0..23 for Tx */
     22static u32 dbg_status_msg_index;
     23/* 0..wil->num_rx_status_rings-1 for Rx, wil->tx_sring_idx for Tx */
     24static u32 dbg_sring_index;
     25
     26enum 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" */
     35struct dbg_off {
     36	const char *name;
     37	umode_t mode;
     38	ulong off;
     39	enum dbg_off_type type;
     40};
     41
     42static 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
     74static 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
    132static 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}
    191DEFINE_SHOW_ATTRIBUTE(ring);
    192
    193static 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
    251static 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}
    262DEFINE_SHOW_ATTRIBUTE(srings);
    263
    264static 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
    270static 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
    354static 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}
    372DEFINE_SHOW_ATTRIBUTE(mbox);
    373
    374static 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
    394static 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
    412DEFINE_DEBUGFS_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
    413			 wil_debugfs_iomem_x32_set, "0x%08llx\n");
    414
    415static 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
    429static int wil_debugfs_ulong_set(void *data, u64 val)
    430{
    431	*(ulong *)data = val;
    432	return 0;
    433}
    434
    435static int wil_debugfs_ulong_get(void *data, u64 *val)
    436{
    437	*val = *(ulong *)data;
    438	return 0;
    439}
    440
    441DEFINE_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 */
    453static 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
    487static 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
    498static 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
    508static 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
    515static 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
    524static 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
    531static 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
    547static 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
    563static 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
    584static 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}
    612DEFINE_SHOW_ATTRIBUTE(memread);
    613
    614static 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
    677static const struct file_operations fops_ioblob = {
    678	.read =		wil_read_file_ioblob,
    679	.open =		simple_open,
    680	.llseek =	default_llseek,
    681};
    682
    683static
    684struct 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---*/
    693static 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
    729static const struct file_operations fops_rxon = {
    730	.write = wil_write_file_rxon,
    731	.open  = simple_open,
    732};
    733
    734static 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
    767static 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 */
    777static 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
    850static 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
    864static 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 */
    874static 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
    924static 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
    940static const struct file_operations fops_pmccfg = {
    941	.read = wil_read_pmccfg,
    942	.write = wil_write_pmccfg,
    943	.open  = simple_open,
    944};
    945
    946static const struct file_operations fops_pmcdata = {
    947	.open		= simple_open,
    948	.read		= wil_pmc_read,
    949	.llseek		= wil_pmc_llseek,
    950};
    951
    952static 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
    957static 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 */
    966static 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
    996static 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 */
   1004static 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 rc, rc1;
   1014
   1015	if (cmdlen < 0)
   1016		return -EINVAL;
   1017
   1018	wmi = kmalloc(len, GFP_KERNEL);
   1019	if (!wmi)
   1020		return -ENOMEM;
   1021
   1022	rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
   1023	if (rc < 0) {
   1024		kfree(wmi);
   1025		return rc;
   1026	}
   1027
   1028	cmd = (cmdlen > 0) ? &wmi[1] : NULL;
   1029	cmdid = le16_to_cpu(wmi->command_id);
   1030
   1031	rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen);
   1032	kfree(wmi);
   1033
   1034	wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
   1035
   1036	return rc;
   1037}
   1038
   1039static const struct file_operations fops_wmi = {
   1040	.write = wil_write_file_wmi,
   1041	.open  = simple_open,
   1042};
   1043
   1044static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
   1045{
   1046	int i = 0;
   1047	int len = skb_headlen(skb);
   1048	void *p = skb->data;
   1049	int nr_frags = skb_shinfo(skb)->nr_frags;
   1050
   1051	seq_printf(s, "    len = %d\n", len);
   1052	wil_seq_hexdump(s, p, len, "      : ");
   1053
   1054	if (nr_frags) {
   1055		seq_printf(s, "    nr_frags = %d\n", nr_frags);
   1056		for (i = 0; i < nr_frags; i++) {
   1057			const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
   1058
   1059			len = skb_frag_size(frag);
   1060			p = skb_frag_address_safe(frag);
   1061			seq_printf(s, "    [%2d] : len = %d\n", i, len);
   1062			wil_seq_hexdump(s, p, len, "      : ");
   1063		}
   1064	}
   1065}
   1066
   1067/*---------Tx/Rx descriptor------------*/
   1068static int txdesc_show(struct seq_file *s, void *data)
   1069{
   1070	struct wil6210_priv *wil = s->private;
   1071	struct wil_ring *ring;
   1072	bool tx;
   1073	int ring_idx = dbg_ring_index;
   1074	int txdesc_idx = dbg_txdesc_index;
   1075	volatile struct vring_tx_desc *d;
   1076	volatile u32 *u;
   1077	struct sk_buff *skb;
   1078
   1079	if (wil->use_enhanced_dma_hw) {
   1080		/* RX ring index == 0 */
   1081		if (ring_idx >= WIL6210_MAX_TX_RINGS) {
   1082			seq_printf(s, "invalid ring index %d\n", ring_idx);
   1083			return 0;
   1084		}
   1085		tx = ring_idx > 0; /* desc ring 0 is reserved for RX */
   1086	} else {
   1087		/* RX ring index == WIL6210_MAX_TX_RINGS */
   1088		if (ring_idx > WIL6210_MAX_TX_RINGS) {
   1089			seq_printf(s, "invalid ring index %d\n", ring_idx);
   1090			return 0;
   1091		}
   1092		tx = (ring_idx < WIL6210_MAX_TX_RINGS);
   1093	}
   1094
   1095	ring = tx ? &wil->ring_tx[ring_idx] : &wil->ring_rx;
   1096
   1097	if (!ring->va) {
   1098		if (tx)
   1099			seq_printf(s, "No Tx[%2d] RING\n", ring_idx);
   1100		else
   1101			seq_puts(s, "No Rx RING\n");
   1102		return 0;
   1103	}
   1104
   1105	if (txdesc_idx >= ring->size) {
   1106		if (tx)
   1107			seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
   1108				   ring_idx, txdesc_idx, ring->size);
   1109		else
   1110			seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
   1111				   txdesc_idx, ring->size);
   1112		return 0;
   1113	}
   1114
   1115	/* use struct vring_tx_desc for Rx as well,
   1116	 * only field used, .dma.length, is the same
   1117	 */
   1118	d = &ring->va[txdesc_idx].tx.legacy;
   1119	u = (volatile u32 *)d;
   1120	skb = NULL;
   1121
   1122	if (wil->use_enhanced_dma_hw) {
   1123		if (tx) {
   1124			skb = ring->ctx ? ring->ctx[txdesc_idx].skb : NULL;
   1125		} else if (wil->rx_buff_mgmt.buff_arr) {
   1126			struct wil_rx_enhanced_desc *rx_d =
   1127				(struct wil_rx_enhanced_desc *)
   1128				&ring->va[txdesc_idx].rx.enhanced;
   1129			u16 buff_id = le16_to_cpu(rx_d->mac.buff_id);
   1130
   1131			if (!wil_val_in_range(buff_id, 0,
   1132					      wil->rx_buff_mgmt.size))
   1133				seq_printf(s, "invalid buff_id %d\n", buff_id);
   1134			else
   1135				skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
   1136		}
   1137	} else {
   1138		skb = ring->ctx[txdesc_idx].skb;
   1139	}
   1140	if (tx)
   1141		seq_printf(s, "Tx[%2d][%3d] = {\n", ring_idx,
   1142			   txdesc_idx);
   1143	else
   1144		seq_printf(s, "Rx[%3d] = {\n", txdesc_idx);
   1145	seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
   1146		   u[0], u[1], u[2], u[3]);
   1147	seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
   1148		   u[4], u[5], u[6], u[7]);
   1149	seq_printf(s, "  SKB = 0x%p\n", skb);
   1150
   1151	if (skb) {
   1152		skb_get(skb);
   1153		wil_seq_print_skb(s, skb);
   1154		kfree_skb(skb);
   1155	}
   1156	seq_puts(s, "}\n");
   1157
   1158	return 0;
   1159}
   1160DEFINE_SHOW_ATTRIBUTE(txdesc);
   1161
   1162/*---------Tx/Rx status message------------*/
   1163static int status_msg_show(struct seq_file *s, void *data)
   1164{
   1165	struct wil6210_priv *wil = s->private;
   1166	int sring_idx = dbg_sring_index;
   1167	struct wil_status_ring *sring;
   1168	bool tx;
   1169	u32 status_msg_idx = dbg_status_msg_index;
   1170	u32 *u;
   1171
   1172	if (sring_idx >= WIL6210_MAX_STATUS_RINGS) {
   1173		seq_printf(s, "invalid status ring index %d\n", sring_idx);
   1174		return 0;
   1175	}
   1176
   1177	sring = &wil->srings[sring_idx];
   1178	tx = !sring->is_rx;
   1179
   1180	if (!sring->va) {
   1181		seq_printf(s, "No %cX status ring\n", tx ? 'T' : 'R');
   1182		return 0;
   1183	}
   1184
   1185	if (status_msg_idx >= sring->size) {
   1186		seq_printf(s, "%cxDesc index (%d) >= size (%d)\n",
   1187			   tx ? 'T' : 'R', status_msg_idx, sring->size);
   1188		return 0;
   1189	}
   1190
   1191	u = sring->va + (sring->elem_size * status_msg_idx);
   1192
   1193	seq_printf(s, "%cx[%d][%3d] = {\n",
   1194		   tx ? 'T' : 'R', sring_idx, status_msg_idx);
   1195
   1196	seq_printf(s, "  0x%08x 0x%08x 0x%08x 0x%08x\n",
   1197		   u[0], u[1], u[2], u[3]);
   1198	if (!tx && !wil->use_compressed_rx_status)
   1199		seq_printf(s, "  0x%08x 0x%08x 0x%08x 0x%08x\n",
   1200			   u[4], u[5], u[6], u[7]);
   1201
   1202	seq_puts(s, "}\n");
   1203
   1204	return 0;
   1205}
   1206DEFINE_SHOW_ATTRIBUTE(status_msg);
   1207
   1208static int wil_print_rx_buff(struct seq_file *s, struct list_head *lh)
   1209{
   1210	struct wil_rx_buff *it;
   1211	int i = 0;
   1212
   1213	list_for_each_entry(it, lh, list) {
   1214		if ((i % 16) == 0 && i != 0)
   1215			seq_puts(s, "\n    ");
   1216		seq_printf(s, "[%4d] ", it->id);
   1217		i++;
   1218	}
   1219	seq_printf(s, "\nNumber of buffers: %u\n", i);
   1220
   1221	return i;
   1222}
   1223
   1224static int rx_buff_mgmt_show(struct seq_file *s, void *data)
   1225{
   1226	struct wil6210_priv *wil = s->private;
   1227	struct wil_rx_buff_mgmt *rbm = &wil->rx_buff_mgmt;
   1228	int num_active;
   1229	int num_free;
   1230
   1231	if (!rbm->buff_arr)
   1232		return -EINVAL;
   1233
   1234	seq_printf(s, "  size = %zu\n", rbm->size);
   1235	seq_printf(s, "  free_list_empty_cnt = %lu\n",
   1236		   rbm->free_list_empty_cnt);
   1237
   1238	/* Print active list */
   1239	seq_puts(s, "  Active list:\n");
   1240	num_active = wil_print_rx_buff(s, &rbm->active);
   1241	seq_puts(s, "\n  Free list:\n");
   1242	num_free = wil_print_rx_buff(s, &rbm->free);
   1243
   1244	seq_printf(s, "  Total number of buffers: %u\n",
   1245		   num_active + num_free);
   1246
   1247	return 0;
   1248}
   1249DEFINE_SHOW_ATTRIBUTE(rx_buff_mgmt);
   1250
   1251/*---------beamforming------------*/
   1252static char *wil_bfstatus_str(u32 status)
   1253{
   1254	switch (status) {
   1255	case 0:
   1256		return "Failed";
   1257	case 1:
   1258		return "OK";
   1259	case 2:
   1260		return "Retrying";
   1261	default:
   1262		return "??";
   1263	}
   1264}
   1265
   1266static bool is_all_zeros(void * const x_, size_t sz)
   1267{
   1268	/* if reply is all-0, ignore this CID */
   1269	u32 *x = x_;
   1270	int n;
   1271
   1272	for (n = 0; n < sz / sizeof(*x); n++)
   1273		if (x[n])
   1274			return false;
   1275
   1276	return true;
   1277}
   1278
   1279static int bf_show(struct seq_file *s, void *data)
   1280{
   1281	int rc;
   1282	int i;
   1283	struct wil6210_priv *wil = s->private;
   1284	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
   1285	struct wmi_notify_req_cmd cmd = {
   1286		.interval_usec = 0,
   1287	};
   1288	struct {
   1289		struct wmi_cmd_hdr wmi;
   1290		struct wmi_notify_req_done_event evt;
   1291	} __packed reply;
   1292
   1293	memset(&reply, 0, sizeof(reply));
   1294
   1295	for (i = 0; i < wil->max_assoc_sta; i++) {
   1296		u32 status;
   1297		u8 bf_mcs;
   1298
   1299		cmd.cid = i;
   1300		rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid,
   1301			      &cmd, sizeof(cmd),
   1302			      WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
   1303			      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
   1304		/* if reply is all-0, ignore this CID */
   1305		if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
   1306			continue;
   1307
   1308		status = le32_to_cpu(reply.evt.status);
   1309		bf_mcs = le16_to_cpu(reply.evt.bf_mcs);
   1310		seq_printf(s, "CID %d {\n"
   1311			   "  TSF = 0x%016llx\n"
   1312			   "  TxMCS = %s TxTpt = %4d\n"
   1313			   "  SQI = %4d\n"
   1314			   "  RSSI = %4d\n"
   1315			   "  Status = 0x%08x %s\n"
   1316			   "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
   1317			   "  Goodput(rx:tx) %4d:%4d\n"
   1318			   "}\n",
   1319			   i,
   1320			   le64_to_cpu(reply.evt.tsf),
   1321			   WIL_EXTENDED_MCS_CHECK(bf_mcs),
   1322			   le32_to_cpu(reply.evt.tx_tpt),
   1323			   reply.evt.sqi,
   1324			   reply.evt.rssi,
   1325			   status, wil_bfstatus_str(status),
   1326			   le16_to_cpu(reply.evt.my_rx_sector),
   1327			   le16_to_cpu(reply.evt.my_tx_sector),
   1328			   le16_to_cpu(reply.evt.other_rx_sector),
   1329			   le16_to_cpu(reply.evt.other_tx_sector),
   1330			   le32_to_cpu(reply.evt.rx_goodput),
   1331			   le32_to_cpu(reply.evt.tx_goodput));
   1332	}
   1333	return 0;
   1334}
   1335DEFINE_SHOW_ATTRIBUTE(bf);
   1336
   1337/*---------temp------------*/
   1338static void print_temp(struct seq_file *s, const char *prefix, s32 t)
   1339{
   1340	switch (t) {
   1341	case 0:
   1342	case WMI_INVALID_TEMPERATURE:
   1343		seq_printf(s, "%s N/A\n", prefix);
   1344	break;
   1345	default:
   1346		seq_printf(s, "%s %s%d.%03d\n", prefix, (t < 0 ? "-" : ""),
   1347			   abs(t / 1000), abs(t % 1000));
   1348		break;
   1349	}
   1350}
   1351
   1352static int temp_show(struct seq_file *s, void *data)
   1353{
   1354	struct wil6210_priv *wil = s->private;
   1355	int rc, i;
   1356
   1357	if (test_bit(WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF,
   1358		     wil->fw_capabilities)) {
   1359		struct wmi_temp_sense_all_done_event sense_all_evt;
   1360
   1361		wil_dbg_misc(wil,
   1362			     "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is supported");
   1363		rc = wmi_get_all_temperatures(wil, &sense_all_evt);
   1364		if (rc) {
   1365			seq_puts(s, "Failed\n");
   1366			return 0;
   1367		}
   1368		print_temp(s, "T_mac   =",
   1369			   le32_to_cpu(sense_all_evt.baseband_t1000));
   1370		seq_printf(s, "Connected RFs [0x%08x]\n",
   1371			   sense_all_evt.rf_bitmap);
   1372		for (i = 0; i < WMI_MAX_XIF_PORTS_NUM; i++) {
   1373			seq_printf(s, "RF[%d]   = ", i);
   1374			print_temp(s, "",
   1375				   le32_to_cpu(sense_all_evt.rf_t1000[i]));
   1376		}
   1377	} else {
   1378		s32 t_m, t_r;
   1379
   1380		wil_dbg_misc(wil,
   1381			     "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is not supported");
   1382		rc = wmi_get_temperature(wil, &t_m, &t_r);
   1383		if (rc) {
   1384			seq_puts(s, "Failed\n");
   1385			return 0;
   1386		}
   1387		print_temp(s, "T_mac   =", t_m);
   1388		print_temp(s, "T_radio =", t_r);
   1389	}
   1390	return 0;
   1391}
   1392DEFINE_SHOW_ATTRIBUTE(temp);
   1393
   1394/*---------link------------*/
   1395static int link_show(struct seq_file *s, void *data)
   1396{
   1397	struct wil6210_priv *wil = s->private;
   1398	struct station_info *sinfo;
   1399	int i, rc = 0;
   1400
   1401	sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
   1402	if (!sinfo)
   1403		return -ENOMEM;
   1404
   1405	for (i = 0; i < wil->max_assoc_sta; i++) {
   1406		struct wil_sta_info *p = &wil->sta[i];
   1407		char *status = "unknown";
   1408		struct wil6210_vif *vif;
   1409		u8 mid;
   1410
   1411		switch (p->status) {
   1412		case wil_sta_unused:
   1413			status = "unused   ";
   1414			break;
   1415		case wil_sta_conn_pending:
   1416			status = "pending  ";
   1417			break;
   1418		case wil_sta_connected:
   1419			status = "connected";
   1420			break;
   1421		}
   1422		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
   1423		seq_printf(s, "[%d][MID %d] %pM %s\n",
   1424			   i, mid, p->addr, status);
   1425
   1426		if (p->status != wil_sta_connected)
   1427			continue;
   1428
   1429		vif = (mid < GET_MAX_VIFS(wil)) ? wil->vifs[mid] : NULL;
   1430		if (vif) {
   1431			rc = wil_cid_fill_sinfo(vif, i, sinfo);
   1432			if (rc)
   1433				goto out;
   1434
   1435			seq_printf(s, "  Tx_mcs = %s\n",
   1436				   WIL_EXTENDED_MCS_CHECK(sinfo->txrate.mcs));
   1437			seq_printf(s, "  Rx_mcs = %s\n",
   1438				   WIL_EXTENDED_MCS_CHECK(sinfo->rxrate.mcs));
   1439			seq_printf(s, "  SQ     = %d\n", sinfo->signal);
   1440		} else {
   1441			seq_puts(s, "  INVALID MID\n");
   1442		}
   1443	}
   1444
   1445out:
   1446	kfree(sinfo);
   1447	return rc;
   1448}
   1449DEFINE_SHOW_ATTRIBUTE(link);
   1450
   1451/*---------info------------*/
   1452static int info_show(struct seq_file *s, void *data)
   1453{
   1454	struct wil6210_priv *wil = s->private;
   1455	struct net_device *ndev = wil->main_ndev;
   1456	int is_ac = power_supply_is_system_supplied();
   1457	int rx = atomic_xchg(&wil->isr_count_rx, 0);
   1458	int tx = atomic_xchg(&wil->isr_count_tx, 0);
   1459	static ulong rxf_old, txf_old;
   1460	ulong rxf = ndev->stats.rx_packets;
   1461	ulong txf = ndev->stats.tx_packets;
   1462	unsigned int i;
   1463
   1464	/* >0 : AC; 0 : battery; <0 : error */
   1465	seq_printf(s, "AC powered : %d\n", is_ac);
   1466	seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
   1467	seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
   1468	rxf_old = rxf;
   1469	txf_old = txf;
   1470
   1471#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
   1472	" " __stringify(x) : ""
   1473
   1474	for (i = 0; i < ndev->num_tx_queues; i++) {
   1475		struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
   1476		unsigned long state = txq->state;
   1477
   1478		seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
   1479			   CHECK_QSTATE(DRV_XOFF),
   1480			   CHECK_QSTATE(STACK_XOFF),
   1481			   CHECK_QSTATE(FROZEN)
   1482			  );
   1483	}
   1484#undef CHECK_QSTATE
   1485	return 0;
   1486}
   1487DEFINE_SHOW_ATTRIBUTE(info);
   1488
   1489/*---------recovery------------*/
   1490/* mode = [manual|auto]
   1491 * state = [idle|pending|running]
   1492 */
   1493static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
   1494				      size_t count, loff_t *ppos)
   1495{
   1496	struct wil6210_priv *wil = file->private_data;
   1497	char buf[80];
   1498	int n;
   1499	static const char * const sstate[] = {"idle", "pending", "running"};
   1500
   1501	n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
   1502		     no_fw_recovery ? "manual" : "auto",
   1503		     sstate[wil->recovery_state]);
   1504
   1505	n = min_t(int, n, sizeof(buf));
   1506
   1507	return simple_read_from_buffer(user_buf, count, ppos,
   1508				       buf, n);
   1509}
   1510
   1511static ssize_t wil_write_file_recovery(struct file *file,
   1512				       const char __user *buf_,
   1513				       size_t count, loff_t *ppos)
   1514{
   1515	struct wil6210_priv *wil = file->private_data;
   1516	static const char run_command[] = "run";
   1517	char buf[sizeof(run_command) + 1]; /* to detect "runx" */
   1518	ssize_t rc;
   1519
   1520	if (wil->recovery_state != fw_recovery_pending) {
   1521		wil_err(wil, "No recovery pending\n");
   1522		return -EINVAL;
   1523	}
   1524
   1525	if (*ppos != 0) {
   1526		wil_err(wil, "Offset [%d]\n", (int)*ppos);
   1527		return -EINVAL;
   1528	}
   1529
   1530	if (count > sizeof(buf)) {
   1531		wil_err(wil, "Input too long, len = %d\n", (int)count);
   1532		return -EINVAL;
   1533	}
   1534
   1535	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
   1536	if (rc < 0)
   1537		return rc;
   1538
   1539	buf[rc] = '\0';
   1540	if (0 == strcmp(buf, run_command))
   1541		wil_set_recovery_state(wil, fw_recovery_running);
   1542	else
   1543		wil_err(wil, "Bad recovery command \"%s\"\n", buf);
   1544
   1545	return rc;
   1546}
   1547
   1548static const struct file_operations fops_recovery = {
   1549	.read = wil_read_file_recovery,
   1550	.write = wil_write_file_recovery,
   1551	.open  = simple_open,
   1552};
   1553
   1554/*---------Station matrix------------*/
   1555static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
   1556{
   1557	int i;
   1558	u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
   1559	unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old;
   1560	unsigned long long drop_dup_mcast = r->drop_dup_mcast;
   1561
   1562	seq_printf(s, "([%2d]) 0x%03x [", r->buf_size, r->head_seq_num);
   1563	for (i = 0; i < r->buf_size; i++) {
   1564		if (i == index)
   1565			seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
   1566		else
   1567			seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
   1568	}
   1569	seq_printf(s,
   1570		   "] total %llu drop %llu (dup %llu + old %llu + dup mcast %llu) last 0x%03x\n",
   1571		   r->total, drop_dup + drop_old + drop_dup_mcast, drop_dup,
   1572		   drop_old, drop_dup_mcast, r->ssn_last_drop);
   1573}
   1574
   1575static void wil_print_rxtid_crypto(struct seq_file *s, int tid,
   1576				   struct wil_tid_crypto_rx *c)
   1577{
   1578	int i;
   1579
   1580	for (i = 0; i < 4; i++) {
   1581		struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
   1582
   1583		if (cc->key_set)
   1584			goto has_keys;
   1585	}
   1586	return;
   1587
   1588has_keys:
   1589	if (tid < WIL_STA_TID_NUM)
   1590		seq_printf(s, "  [%2d] PN", tid);
   1591	else
   1592		seq_puts(s, "  [GR] PN");
   1593
   1594	for (i = 0; i < 4; i++) {
   1595		struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
   1596
   1597		seq_printf(s, " [%i%s]%6phN", i, cc->key_set ? "+" : "-",
   1598			   cc->pn);
   1599	}
   1600	seq_puts(s, "\n");
   1601}
   1602
   1603static int sta_show(struct seq_file *s, void *data)
   1604__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
   1605{
   1606	struct wil6210_priv *wil = s->private;
   1607	int i, tid, mcs;
   1608
   1609	for (i = 0; i < wil->max_assoc_sta; i++) {
   1610		struct wil_sta_info *p = &wil->sta[i];
   1611		char *status = "unknown";
   1612		u8 aid = 0;
   1613		u8 mid;
   1614		bool sta_connected = false;
   1615
   1616		switch (p->status) {
   1617		case wil_sta_unused:
   1618			status = "unused   ";
   1619			break;
   1620		case wil_sta_conn_pending:
   1621			status = "pending  ";
   1622			break;
   1623		case wil_sta_connected:
   1624			status = "connected";
   1625			aid = p->aid;
   1626			break;
   1627		}
   1628		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
   1629		if (mid < GET_MAX_VIFS(wil)) {
   1630			struct wil6210_vif *vif = wil->vifs[mid];
   1631
   1632			if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
   1633			    p->status == wil_sta_connected)
   1634				sta_connected = true;
   1635		}
   1636		/* print roam counter only for connected stations */
   1637		if (sta_connected)
   1638			seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n",
   1639				   i, p->addr, p->stats.ft_roams, mid, aid);
   1640		else
   1641			seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i,
   1642				   p->addr, status, mid, aid);
   1643
   1644		if (p->status == wil_sta_connected) {
   1645			spin_lock_bh(&p->tid_rx_lock);
   1646			for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
   1647				struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
   1648				struct wil_tid_crypto_rx *c =
   1649						&p->tid_crypto_rx[tid];
   1650
   1651				if (r) {
   1652					seq_printf(s, "  [%2d] ", tid);
   1653					wil_print_rxtid(s, r);
   1654				}
   1655
   1656				wil_print_rxtid_crypto(s, tid, c);
   1657			}
   1658			wil_print_rxtid_crypto(s, WIL_STA_TID_NUM,
   1659					       &p->group_crypto_rx);
   1660			spin_unlock_bh(&p->tid_rx_lock);
   1661			seq_printf(s,
   1662				   "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n",
   1663				   p->stats.rx_non_data_frame,
   1664				   p->stats.rx_short_frame,
   1665				   p->stats.rx_large_frame,
   1666				   p->stats.rx_replay);
   1667			seq_printf(s,
   1668				   "mic error %lu, key error %lu, amsdu error %lu, csum error %lu\n",
   1669				   p->stats.rx_mic_error,
   1670				   p->stats.rx_key_error,
   1671				   p->stats.rx_amsdu_error,
   1672				   p->stats.rx_csum_err);
   1673
   1674			seq_puts(s, "Rx/MCS:");
   1675			for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
   1676			     mcs++)
   1677				seq_printf(s, " %lld",
   1678					   p->stats.rx_per_mcs[mcs]);
   1679			seq_puts(s, "\n");
   1680		}
   1681	}
   1682
   1683	return 0;
   1684}
   1685DEFINE_SHOW_ATTRIBUTE(sta);
   1686
   1687static int mids_show(struct seq_file *s, void *data)
   1688{
   1689	struct wil6210_priv *wil = s->private;
   1690	struct wil6210_vif *vif;
   1691	struct net_device *ndev;
   1692	int i;
   1693
   1694	mutex_lock(&wil->vif_mutex);
   1695	for (i = 0; i < GET_MAX_VIFS(wil); i++) {
   1696		vif = wil->vifs[i];
   1697
   1698		if (vif) {
   1699			ndev = vif_to_ndev(vif);
   1700			seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr,
   1701				   ndev->name);
   1702		} else {
   1703			seq_printf(s, "[%d] unused\n", i);
   1704		}
   1705	}
   1706	mutex_unlock(&wil->vif_mutex);
   1707
   1708	return 0;
   1709}
   1710DEFINE_SHOW_ATTRIBUTE(mids);
   1711
   1712static int wil_tx_latency_debugfs_show(struct seq_file *s, void *data)
   1713__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
   1714{
   1715	struct wil6210_priv *wil = s->private;
   1716	int i, bin;
   1717
   1718	for (i = 0; i < wil->max_assoc_sta; i++) {
   1719		struct wil_sta_info *p = &wil->sta[i];
   1720		char *status = "unknown";
   1721		u8 aid = 0;
   1722		u8 mid;
   1723
   1724		if (!p->tx_latency_bins)
   1725			continue;
   1726
   1727		switch (p->status) {
   1728		case wil_sta_unused:
   1729			status = "unused   ";
   1730			break;
   1731		case wil_sta_conn_pending:
   1732			status = "pending  ";
   1733			break;
   1734		case wil_sta_connected:
   1735			status = "connected";
   1736			aid = p->aid;
   1737			break;
   1738		}
   1739		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
   1740		seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
   1741			   mid, aid);
   1742
   1743		if (p->status == wil_sta_connected) {
   1744			u64 num_packets = 0;
   1745			u64 tx_latency_avg = p->stats.tx_latency_total_us;
   1746
   1747			seq_puts(s, "Tx/Latency bin:");
   1748			for (bin = 0; bin < WIL_NUM_LATENCY_BINS; bin++) {
   1749				seq_printf(s, " %lld",
   1750					   p->tx_latency_bins[bin]);
   1751				num_packets += p->tx_latency_bins[bin];
   1752			}
   1753			seq_puts(s, "\n");
   1754			if (!num_packets)
   1755				continue;
   1756			do_div(tx_latency_avg, num_packets);
   1757			seq_printf(s, "Tx/Latency min/avg/max (us): %d/%lld/%d",
   1758				   p->stats.tx_latency_min_us,
   1759				   tx_latency_avg,
   1760				   p->stats.tx_latency_max_us);
   1761
   1762			seq_puts(s, "\n");
   1763		}
   1764	}
   1765
   1766	return 0;
   1767}
   1768
   1769static int wil_tx_latency_seq_open(struct inode *inode, struct file *file)
   1770{
   1771	return single_open(file, wil_tx_latency_debugfs_show,
   1772			   inode->i_private);
   1773}
   1774
   1775static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf,
   1776				    size_t len, loff_t *ppos)
   1777{
   1778	struct seq_file *s = file->private_data;
   1779	struct wil6210_priv *wil = s->private;
   1780	int val, rc, i;
   1781	bool enable;
   1782
   1783	rc = kstrtoint_from_user(buf, len, 0, &val);
   1784	if (rc) {
   1785		wil_err(wil, "Invalid argument\n");
   1786		return rc;
   1787	}
   1788	if (val == 1)
   1789		/* default resolution */
   1790		val = 500;
   1791	if (val && (val < 50 || val > 1000)) {
   1792		wil_err(wil, "Invalid resolution %d\n", val);
   1793		return -EINVAL;
   1794	}
   1795
   1796	enable = !!val;
   1797	if (wil->tx_latency == enable)
   1798		return len;
   1799
   1800	wil_info(wil, "%s TX latency measurements (resolution %dusec)\n",
   1801		 enable ? "Enabling" : "Disabling", val);
   1802
   1803	if (enable) {
   1804		size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS;
   1805
   1806		wil->tx_latency_res = val;
   1807		for (i = 0; i < wil->max_assoc_sta; i++) {
   1808			struct wil_sta_info *sta = &wil->sta[i];
   1809
   1810			kfree(sta->tx_latency_bins);
   1811			sta->tx_latency_bins = kzalloc(sz, GFP_KERNEL);
   1812			if (!sta->tx_latency_bins)
   1813				return -ENOMEM;
   1814			sta->stats.tx_latency_min_us = U32_MAX;
   1815			sta->stats.tx_latency_max_us = 0;
   1816			sta->stats.tx_latency_total_us = 0;
   1817		}
   1818	}
   1819	wil->tx_latency = enable;
   1820
   1821	return len;
   1822}
   1823
   1824static const struct file_operations fops_tx_latency = {
   1825	.open		= wil_tx_latency_seq_open,
   1826	.release	= single_release,
   1827	.read		= seq_read,
   1828	.write		= wil_tx_latency_write,
   1829	.llseek		= seq_lseek,
   1830};
   1831
   1832static void wil_link_stats_print_basic(struct wil6210_vif *vif,
   1833				       struct seq_file *s,
   1834				       struct wmi_link_stats_basic *basic)
   1835{
   1836	char per[5] = "?";
   1837
   1838	if (basic->per_average != 0xff)
   1839		snprintf(per, sizeof(per), "%d%%", basic->per_average);
   1840
   1841	seq_printf(s, "CID %d {\n"
   1842		   "\tTxMCS %s TxTpt %d\n"
   1843		   "\tGoodput(rx:tx) %d:%d\n"
   1844		   "\tRxBcastFrames %d\n"
   1845		   "\tRSSI %d SQI %d SNR %d PER %s\n"
   1846		   "\tRx RFC %d Ant num %d\n"
   1847		   "\tSectors(rx:tx) my %d:%d peer %d:%d\n"
   1848		   "}\n",
   1849		   basic->cid,
   1850		   WIL_EXTENDED_MCS_CHECK(basic->bf_mcs),
   1851		   le32_to_cpu(basic->tx_tpt),
   1852		   le32_to_cpu(basic->rx_goodput),
   1853		   le32_to_cpu(basic->tx_goodput),
   1854		   le32_to_cpu(basic->rx_bcast_frames),
   1855		   basic->rssi, basic->sqi, basic->snr, per,
   1856		   basic->selected_rfc, basic->rx_effective_ant_num,
   1857		   basic->my_rx_sector, basic->my_tx_sector,
   1858		   basic->other_rx_sector, basic->other_tx_sector);
   1859}
   1860
   1861static void wil_link_stats_print_global(struct wil6210_priv *wil,
   1862					struct seq_file *s,
   1863					struct wmi_link_stats_global *global)
   1864{
   1865	seq_printf(s, "Frames(rx:tx) %d:%d\n"
   1866		   "BA Frames(rx:tx) %d:%d\n"
   1867		   "Beacons %d\n"
   1868		   "Rx Errors (MIC:CRC) %d:%d\n"
   1869		   "Tx Errors (no ack) %d\n",
   1870		   le32_to_cpu(global->rx_frames),
   1871		   le32_to_cpu(global->tx_frames),
   1872		   le32_to_cpu(global->rx_ba_frames),
   1873		   le32_to_cpu(global->tx_ba_frames),
   1874		   le32_to_cpu(global->tx_beacons),
   1875		   le32_to_cpu(global->rx_mic_errors),
   1876		   le32_to_cpu(global->rx_crc_errors),
   1877		   le32_to_cpu(global->tx_fail_no_ack));
   1878}
   1879
   1880static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif,
   1881					    struct seq_file *s)
   1882{
   1883	struct wil6210_priv *wil = vif_to_wil(vif);
   1884	struct wmi_link_stats_basic *stats;
   1885	int i;
   1886
   1887	if (!vif->fw_stats_ready) {
   1888		seq_puts(s, "no statistics\n");
   1889		return;
   1890	}
   1891
   1892	seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf);
   1893	for (i = 0; i < wil->max_assoc_sta; i++) {
   1894		if (wil->sta[i].status == wil_sta_unused)
   1895			continue;
   1896		if (wil->sta[i].mid != vif->mid)
   1897			continue;
   1898
   1899		stats = &wil->sta[i].fw_stats_basic;
   1900		wil_link_stats_print_basic(vif, s, stats);
   1901	}
   1902}
   1903
   1904static int wil_link_stats_debugfs_show(struct seq_file *s, void *data)
   1905{
   1906	struct wil6210_priv *wil = s->private;
   1907	struct wil6210_vif *vif;
   1908	int i, rc;
   1909
   1910	rc = mutex_lock_interruptible(&wil->vif_mutex);
   1911	if (rc)
   1912		return rc;
   1913
   1914	/* iterate over all MIDs and show per-cid statistics. Then show the
   1915	 * global statistics
   1916	 */
   1917	for (i = 0; i < GET_MAX_VIFS(wil); i++) {
   1918		vif = wil->vifs[i];
   1919
   1920		seq_printf(s, "MID %d ", i);
   1921		if (!vif) {
   1922			seq_puts(s, "unused\n");
   1923			continue;
   1924		}
   1925
   1926		wil_link_stats_debugfs_show_vif(vif, s);
   1927	}
   1928
   1929	mutex_unlock(&wil->vif_mutex);
   1930
   1931	return 0;
   1932}
   1933
   1934static int wil_link_stats_seq_open(struct inode *inode, struct file *file)
   1935{
   1936	return single_open(file, wil_link_stats_debugfs_show, inode->i_private);
   1937}
   1938
   1939static ssize_t wil_link_stats_write(struct file *file, const char __user *buf,
   1940				    size_t len, loff_t *ppos)
   1941{
   1942	struct seq_file *s = file->private_data;
   1943	struct wil6210_priv *wil = s->private;
   1944	int cid, interval, rc, i;
   1945	struct wil6210_vif *vif;
   1946	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
   1947
   1948	if (!kbuf)
   1949		return -ENOMEM;
   1950
   1951	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
   1952	if (rc != len) {
   1953		kfree(kbuf);
   1954		return rc >= 0 ? -EIO : rc;
   1955	}
   1956
   1957	kbuf[len] = '\0';
   1958	/* specify cid (use -1 for all cids) and snapshot interval in ms */
   1959	rc = sscanf(kbuf, "%d %d", &cid, &interval);
   1960	kfree(kbuf);
   1961	if (rc < 0)
   1962		return rc;
   1963	if (rc < 2 || interval < 0)
   1964		return -EINVAL;
   1965
   1966	wil_info(wil, "request link statistics, cid %d interval %d\n",
   1967		 cid, interval);
   1968
   1969	rc = mutex_lock_interruptible(&wil->vif_mutex);
   1970	if (rc)
   1971		return rc;
   1972
   1973	for (i = 0; i < GET_MAX_VIFS(wil); i++) {
   1974		vif = wil->vifs[i];
   1975		if (!vif)
   1976			continue;
   1977
   1978		rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_BASIC,
   1979					(cid == -1 ? 0xff : cid), interval);
   1980		if (rc)
   1981			wil_err(wil, "link statistics failed for mid %d\n", i);
   1982	}
   1983	mutex_unlock(&wil->vif_mutex);
   1984
   1985	return len;
   1986}
   1987
   1988static const struct file_operations fops_link_stats = {
   1989	.open		= wil_link_stats_seq_open,
   1990	.release	= single_release,
   1991	.read		= seq_read,
   1992	.write		= wil_link_stats_write,
   1993	.llseek		= seq_lseek,
   1994};
   1995
   1996static int
   1997wil_link_stats_global_debugfs_show(struct seq_file *s, void *data)
   1998{
   1999	struct wil6210_priv *wil = s->private;
   2000
   2001	if (!wil->fw_stats_global.ready)
   2002		return 0;
   2003
   2004	seq_printf(s, "TSF %lld\n", wil->fw_stats_global.tsf);
   2005	wil_link_stats_print_global(wil, s, &wil->fw_stats_global.stats);
   2006
   2007	return 0;
   2008}
   2009
   2010static int
   2011wil_link_stats_global_seq_open(struct inode *inode, struct file *file)
   2012{
   2013	return single_open(file, wil_link_stats_global_debugfs_show,
   2014			   inode->i_private);
   2015}
   2016
   2017static ssize_t
   2018wil_link_stats_global_write(struct file *file, const char __user *buf,
   2019			    size_t len, loff_t *ppos)
   2020{
   2021	struct seq_file *s = file->private_data;
   2022	struct wil6210_priv *wil = s->private;
   2023	int interval, rc;
   2024	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
   2025
   2026	/* specify snapshot interval in ms */
   2027	rc = kstrtoint_from_user(buf, len, 0, &interval);
   2028	if (rc || interval < 0) {
   2029		wil_err(wil, "Invalid argument\n");
   2030		return -EINVAL;
   2031	}
   2032
   2033	wil_info(wil, "request global link stats, interval %d\n", interval);
   2034
   2035	rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_GLOBAL, 0, interval);
   2036	if (rc)
   2037		wil_err(wil, "global link stats failed %d\n", rc);
   2038
   2039	return rc ? rc : len;
   2040}
   2041
   2042static const struct file_operations fops_link_stats_global = {
   2043	.open		= wil_link_stats_global_seq_open,
   2044	.release	= single_release,
   2045	.read		= seq_read,
   2046	.write		= wil_link_stats_global_write,
   2047	.llseek		= seq_lseek,
   2048};
   2049
   2050static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
   2051				     size_t count, loff_t *ppos)
   2052{
   2053	char buf[80];
   2054	int n;
   2055
   2056	n = snprintf(buf, sizeof(buf),
   2057		     "led_id is set to %d, echo 1 to enable, 0 to disable\n",
   2058		     led_id);
   2059
   2060	n = min_t(int, n, sizeof(buf));
   2061
   2062	return simple_read_from_buffer(user_buf, count, ppos,
   2063				       buf, n);
   2064}
   2065
   2066static ssize_t wil_write_file_led_cfg(struct file *file,
   2067				      const char __user *buf_,
   2068				      size_t count, loff_t *ppos)
   2069{
   2070	struct wil6210_priv *wil = file->private_data;
   2071	int val;
   2072	int rc;
   2073
   2074	rc = kstrtoint_from_user(buf_, count, 0, &val);
   2075	if (rc) {
   2076		wil_err(wil, "Invalid argument\n");
   2077		return rc;
   2078	}
   2079
   2080	wil_info(wil, "%s led %d\n", val ? "Enabling" : "Disabling", led_id);
   2081	rc = wmi_led_cfg(wil, val);
   2082	if (rc) {
   2083		wil_info(wil, "%s led %d failed\n",
   2084			 val ? "Enabling" : "Disabling", led_id);
   2085		return rc;
   2086	}
   2087
   2088	return count;
   2089}
   2090
   2091static const struct file_operations fops_led_cfg = {
   2092	.read = wil_read_file_led_cfg,
   2093	.write = wil_write_file_led_cfg,
   2094	.open  = simple_open,
   2095};
   2096
   2097/* led_blink_time, write:
   2098 * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
   2099 */
   2100static ssize_t wil_write_led_blink_time(struct file *file,
   2101					const char __user *buf,
   2102					size_t len, loff_t *ppos)
   2103{
   2104	int rc;
   2105	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
   2106
   2107	if (!kbuf)
   2108		return -ENOMEM;
   2109
   2110	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
   2111	if (rc != len) {
   2112		kfree(kbuf);
   2113		return rc >= 0 ? -EIO : rc;
   2114	}
   2115
   2116	kbuf[len] = '\0';
   2117	rc = sscanf(kbuf, "%d %d %d %d %d %d",
   2118		    &led_blink_time[WIL_LED_TIME_SLOW].on_ms,
   2119		    &led_blink_time[WIL_LED_TIME_SLOW].off_ms,
   2120		    &led_blink_time[WIL_LED_TIME_MED].on_ms,
   2121		    &led_blink_time[WIL_LED_TIME_MED].off_ms,
   2122		    &led_blink_time[WIL_LED_TIME_FAST].on_ms,
   2123		    &led_blink_time[WIL_LED_TIME_FAST].off_ms);
   2124	kfree(kbuf);
   2125
   2126	if (rc < 0)
   2127		return rc;
   2128	if (rc < 6)
   2129		return -EINVAL;
   2130
   2131	return len;
   2132}
   2133
   2134static ssize_t wil_read_led_blink_time(struct file *file, char __user *user_buf,
   2135				       size_t count, loff_t *ppos)
   2136{
   2137	static char text[400];
   2138
   2139	snprintf(text, sizeof(text),
   2140		 "To set led blink on/off time variables write:\n"
   2141		 "<blink_on_slow> <blink_off_slow> <blink_on_med> "
   2142		 "<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
   2143		 "The current values are:\n"
   2144		 "%d %d %d %d %d %d\n",
   2145		 led_blink_time[WIL_LED_TIME_SLOW].on_ms,
   2146		 led_blink_time[WIL_LED_TIME_SLOW].off_ms,
   2147		 led_blink_time[WIL_LED_TIME_MED].on_ms,
   2148		 led_blink_time[WIL_LED_TIME_MED].off_ms,
   2149		 led_blink_time[WIL_LED_TIME_FAST].on_ms,
   2150		 led_blink_time[WIL_LED_TIME_FAST].off_ms);
   2151
   2152	return simple_read_from_buffer(user_buf, count, ppos, text,
   2153				       sizeof(text));
   2154}
   2155
   2156static const struct file_operations fops_led_blink_time = {
   2157	.read = wil_read_led_blink_time,
   2158	.write = wil_write_led_blink_time,
   2159	.open  = simple_open,
   2160};
   2161
   2162/*---------FW capabilities------------*/
   2163static int wil_fw_capabilities_debugfs_show(struct seq_file *s, void *data)
   2164{
   2165	struct wil6210_priv *wil = s->private;
   2166
   2167	seq_printf(s, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX,
   2168		   wil->fw_capabilities);
   2169
   2170	return 0;
   2171}
   2172
   2173static int wil_fw_capabilities_seq_open(struct inode *inode, struct file *file)
   2174{
   2175	return single_open(file, wil_fw_capabilities_debugfs_show,
   2176			   inode->i_private);
   2177}
   2178
   2179static const struct file_operations fops_fw_capabilities = {
   2180	.open		= wil_fw_capabilities_seq_open,
   2181	.release	= single_release,
   2182	.read		= seq_read,
   2183	.llseek		= seq_lseek,
   2184};
   2185
   2186/*---------FW version------------*/
   2187static int wil_fw_version_debugfs_show(struct seq_file *s, void *data)
   2188{
   2189	struct wil6210_priv *wil = s->private;
   2190
   2191	if (wil->fw_version[0])
   2192		seq_printf(s, "%s\n", wil->fw_version);
   2193	else
   2194		seq_puts(s, "N/A\n");
   2195
   2196	return 0;
   2197}
   2198
   2199static int wil_fw_version_seq_open(struct inode *inode, struct file *file)
   2200{
   2201	return single_open(file, wil_fw_version_debugfs_show,
   2202			   inode->i_private);
   2203}
   2204
   2205static const struct file_operations fops_fw_version = {
   2206	.open		= wil_fw_version_seq_open,
   2207	.release	= single_release,
   2208	.read		= seq_read,
   2209	.llseek		= seq_lseek,
   2210};
   2211
   2212/*---------suspend_stats---------*/
   2213static ssize_t wil_write_suspend_stats(struct file *file,
   2214				       const char __user *buf,
   2215				       size_t len, loff_t *ppos)
   2216{
   2217	struct wil6210_priv *wil = file->private_data;
   2218
   2219	memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
   2220
   2221	return len;
   2222}
   2223
   2224static ssize_t wil_read_suspend_stats(struct file *file,
   2225				      char __user *user_buf,
   2226				      size_t count, loff_t *ppos)
   2227{
   2228	struct wil6210_priv *wil = file->private_data;
   2229	char *text;
   2230	int n, ret, text_size = 500;
   2231
   2232	text = kmalloc(text_size, GFP_KERNEL);
   2233	if (!text)
   2234		return -ENOMEM;
   2235
   2236	n = snprintf(text, text_size,
   2237		     "Radio on suspend statistics:\n"
   2238		     "successful suspends:%ld failed suspends:%ld\n"
   2239		     "successful resumes:%ld failed resumes:%ld\n"
   2240		     "rejected by device:%ld\n"
   2241		     "Radio off suspend statistics:\n"
   2242		     "successful suspends:%ld failed suspends:%ld\n"
   2243		     "successful resumes:%ld failed resumes:%ld\n"
   2244		     "General statistics:\n"
   2245		     "rejected by host:%ld\n",
   2246		     wil->suspend_stats.r_on.successful_suspends,
   2247		     wil->suspend_stats.r_on.failed_suspends,
   2248		     wil->suspend_stats.r_on.successful_resumes,
   2249		     wil->suspend_stats.r_on.failed_resumes,
   2250		     wil->suspend_stats.rejected_by_device,
   2251		     wil->suspend_stats.r_off.successful_suspends,
   2252		     wil->suspend_stats.r_off.failed_suspends,
   2253		     wil->suspend_stats.r_off.successful_resumes,
   2254		     wil->suspend_stats.r_off.failed_resumes,
   2255		     wil->suspend_stats.rejected_by_host);
   2256
   2257	n = min_t(int, n, text_size);
   2258
   2259	ret = simple_read_from_buffer(user_buf, count, ppos, text, n);
   2260
   2261	kfree(text);
   2262
   2263	return ret;
   2264}
   2265
   2266static const struct file_operations fops_suspend_stats = {
   2267	.read = wil_read_suspend_stats,
   2268	.write = wil_write_suspend_stats,
   2269	.open  = simple_open,
   2270};
   2271
   2272/*---------compressed_rx_status---------*/
   2273static ssize_t wil_compressed_rx_status_write(struct file *file,
   2274					      const char __user *buf,
   2275					      size_t len, loff_t *ppos)
   2276{
   2277	struct seq_file *s = file->private_data;
   2278	struct wil6210_priv *wil = s->private;
   2279	int compressed_rx_status;
   2280	int rc;
   2281
   2282	rc = kstrtoint_from_user(buf, len, 0, &compressed_rx_status);
   2283	if (rc) {
   2284		wil_err(wil, "Invalid argument\n");
   2285		return rc;
   2286	}
   2287
   2288	if (wil_has_active_ifaces(wil, true, false)) {
   2289		wil_err(wil, "cannot change edma config after iface is up\n");
   2290		return -EPERM;
   2291	}
   2292
   2293	wil_info(wil, "%sable compressed_rx_status\n",
   2294		 compressed_rx_status ? "En" : "Dis");
   2295
   2296	wil->use_compressed_rx_status = compressed_rx_status;
   2297
   2298	return len;
   2299}
   2300
   2301static int
   2302wil_compressed_rx_status_show(struct seq_file *s, void *data)
   2303{
   2304	struct wil6210_priv *wil = s->private;
   2305
   2306	seq_printf(s, "%d\n", wil->use_compressed_rx_status);
   2307
   2308	return 0;
   2309}
   2310
   2311static int
   2312wil_compressed_rx_status_seq_open(struct inode *inode, struct file *file)
   2313{
   2314	return single_open(file, wil_compressed_rx_status_show,
   2315			   inode->i_private);
   2316}
   2317
   2318static const struct file_operations fops_compressed_rx_status = {
   2319	.open  = wil_compressed_rx_status_seq_open,
   2320	.release = single_release,
   2321	.read = seq_read,
   2322	.write = wil_compressed_rx_status_write,
   2323	.llseek	= seq_lseek,
   2324};
   2325
   2326/*----------------*/
   2327static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
   2328				       struct dentry *dbg)
   2329{
   2330	int i;
   2331	char name[32];
   2332
   2333	for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
   2334		struct wil_blob_wrapper *wil_blob = &wil->blobs[i];
   2335		struct debugfs_blob_wrapper *blob = &wil_blob->blob;
   2336		const struct fw_map *map = &fw_mapping[i];
   2337
   2338		if (!map->name)
   2339			continue;
   2340
   2341		wil_blob->wil = wil;
   2342		blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
   2343		blob->size = map->to - map->from;
   2344		snprintf(name, sizeof(name), "blob_%s", map->name);
   2345		wil_debugfs_create_ioblob(name, 0444, dbg, wil_blob);
   2346	}
   2347}
   2348
   2349/* misc files */
   2350static const struct {
   2351	const char *name;
   2352	umode_t mode;
   2353	const struct file_operations *fops;
   2354} dbg_files[] = {
   2355	{"mbox",	0444,		&mbox_fops},
   2356	{"rings",	0444,		&ring_fops},
   2357	{"stations", 0444,		&sta_fops},
   2358	{"mids",	0444,		&mids_fops},
   2359	{"desc",	0444,		&txdesc_fops},
   2360	{"bf",		0444,		&bf_fops},
   2361	{"mem_val",	0644,		&memread_fops},
   2362	{"rxon",	0244,		&fops_rxon},
   2363	{"tx_mgmt",	0244,		&fops_txmgmt},
   2364	{"wmi_send", 0244,		&fops_wmi},
   2365	{"back",	0644,		&fops_back},
   2366	{"pmccfg",	0644,		&fops_pmccfg},
   2367	{"pmcdata",	0444,		&fops_pmcdata},
   2368	{"pmcring",	0444,		&fops_pmcring},
   2369	{"temp",	0444,		&temp_fops},
   2370	{"link",	0444,		&link_fops},
   2371	{"info",	0444,		&info_fops},
   2372	{"recovery", 0644,		&fops_recovery},
   2373	{"led_cfg",	0644,		&fops_led_cfg},
   2374	{"led_blink_time",	0644,	&fops_led_blink_time},
   2375	{"fw_capabilities",	0444,	&fops_fw_capabilities},
   2376	{"fw_version",	0444,		&fops_fw_version},
   2377	{"suspend_stats",	0644,	&fops_suspend_stats},
   2378	{"compressed_rx_status", 0644,	&fops_compressed_rx_status},
   2379	{"srings",	0444,		&srings_fops},
   2380	{"status_msg",	0444,		&status_msg_fops},
   2381	{"rx_buff_mgmt",	0444,	&rx_buff_mgmt_fops},
   2382	{"tx_latency",	0644,		&fops_tx_latency},
   2383	{"link_stats",	0644,		&fops_link_stats},
   2384	{"link_stats_global",	0644,	&fops_link_stats_global},
   2385	{"rbufcap",	0244,		&fops_rbufcap},
   2386};
   2387
   2388static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
   2389				       struct dentry *dbg)
   2390{
   2391	int i;
   2392
   2393	for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
   2394		debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
   2395				    wil, dbg_files[i].fops);
   2396}
   2397
   2398/* interrupt control blocks */
   2399static const struct {
   2400	const char *name;
   2401	u32 icr_off;
   2402} dbg_icr[] = {
   2403	{"USER_ICR",		HOSTADDR(RGF_USER_USER_ICR)},
   2404	{"DMA_EP_TX_ICR",	HOSTADDR(RGF_DMA_EP_TX_ICR)},
   2405	{"DMA_EP_RX_ICR",	HOSTADDR(RGF_DMA_EP_RX_ICR)},
   2406	{"DMA_EP_MISC_ICR",	HOSTADDR(RGF_DMA_EP_MISC_ICR)},
   2407};
   2408
   2409static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
   2410				     struct dentry *dbg)
   2411{
   2412	int i;
   2413
   2414	for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
   2415		wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
   2416					   dbg_icr[i].icr_off);
   2417}
   2418
   2419#define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
   2420	offsetof(struct wil6210_priv, name), type}
   2421
   2422/* fields in struct wil6210_priv */
   2423static const struct dbg_off dbg_wil_off[] = {
   2424	WIL_FIELD(status[0],	0644,	doff_ulong),
   2425	WIL_FIELD(hw_version,	0444,	doff_x32),
   2426	WIL_FIELD(recovery_count, 0444,	doff_u32),
   2427	WIL_FIELD(discovery_mode, 0644,	doff_u8),
   2428	WIL_FIELD(chip_revision, 0444,	doff_u8),
   2429	WIL_FIELD(abft_len, 0644,		doff_u8),
   2430	WIL_FIELD(wakeup_trigger, 0644,		doff_u8),
   2431	WIL_FIELD(ring_idle_trsh, 0644,	doff_u32),
   2432	WIL_FIELD(num_rx_status_rings, 0644,	doff_u8),
   2433	WIL_FIELD(rx_status_ring_order, 0644,	doff_u32),
   2434	WIL_FIELD(tx_status_ring_order, 0644,	doff_u32),
   2435	WIL_FIELD(rx_buff_id_count, 0644,	doff_u32),
   2436	WIL_FIELD(amsdu_en, 0644,	doff_u8),
   2437	{},
   2438};
   2439
   2440static const struct dbg_off dbg_wil_regs[] = {
   2441	{"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
   2442		doff_io32},
   2443	{"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
   2444	{"RGF_USER_USAGE_2", 0444, HOSTADDR(RGF_USER_USAGE_2), doff_io32},
   2445	{},
   2446};
   2447
   2448/* static parameters */
   2449static const struct dbg_off dbg_statics[] = {
   2450	{"desc_index",	0644, (ulong)&dbg_txdesc_index, doff_u32},
   2451	{"ring_index",	0644, (ulong)&dbg_ring_index, doff_u32},
   2452	{"mem_addr",	0644, (ulong)&mem_addr, doff_u32},
   2453	{"led_polarity", 0644, (ulong)&led_polarity, doff_u8},
   2454	{"status_index", 0644, (ulong)&dbg_status_msg_index, doff_u32},
   2455	{"sring_index",	0644, (ulong)&dbg_sring_index, doff_u32},
   2456	{"drop_if_ring_full", 0644, (ulong)&drop_if_ring_full, doff_u8},
   2457	{},
   2458};
   2459
   2460static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) +
   2461				ARRAY_SIZE(dbg_wil_regs) - 1 +
   2462				ARRAY_SIZE(pseudo_isr_off) - 1 +
   2463				ARRAY_SIZE(lgc_itr_cnt_off) - 1 +
   2464				ARRAY_SIZE(tx_itr_cnt_off) - 1 +
   2465				ARRAY_SIZE(rx_itr_cnt_off) - 1;
   2466
   2467int wil6210_debugfs_init(struct wil6210_priv *wil)
   2468{
   2469	struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
   2470			wil_to_wiphy(wil)->debugfsdir);
   2471	if (IS_ERR_OR_NULL(dbg))
   2472		return -ENODEV;
   2473
   2474	wil->dbg_data.data_arr = kcalloc(dbg_off_count,
   2475					 sizeof(struct wil_debugfs_iomem_data),
   2476					 GFP_KERNEL);
   2477	if (!wil->dbg_data.data_arr) {
   2478		debugfs_remove_recursive(dbg);
   2479		wil->debug = NULL;
   2480		return -ENOMEM;
   2481	}
   2482
   2483	wil->dbg_data.iomem_data_count = 0;
   2484
   2485	wil_pmc_init(wil);
   2486
   2487	wil6210_debugfs_init_files(wil, dbg);
   2488	wil6210_debugfs_init_isr(wil, dbg);
   2489	wil6210_debugfs_init_blobs(wil, dbg);
   2490	wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
   2491	wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
   2492				    dbg_wil_regs);
   2493	wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
   2494
   2495	wil6210_debugfs_create_pseudo_ISR(wil, dbg);
   2496
   2497	wil6210_debugfs_create_ITR_CNT(wil, dbg);
   2498
   2499	return 0;
   2500}
   2501
   2502void wil6210_debugfs_remove(struct wil6210_priv *wil)
   2503{
   2504	int i;
   2505
   2506	debugfs_remove_recursive(wil->debug);
   2507	wil->debug = NULL;
   2508
   2509	kfree(wil->dbg_data.data_arr);
   2510	for (i = 0; i < wil->max_assoc_sta; i++)
   2511		kfree(wil->sta[i].tx_latency_bins);
   2512
   2513	/* free pmc memory without sending command to fw, as it will
   2514	 * be reset on the way down anyway
   2515	 */
   2516	wil_pmc_free(wil, false);
   2517}