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