xref: /linux/drivers/net/wireless/nxp/nxpwifi/debugfs.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1*73b01e57SJeff Chen // SPDX-License-Identifier: GPL-2.0-only
2*73b01e57SJeff Chen /*
3*73b01e57SJeff Chen  * nxpwifi: debugfs
4*73b01e57SJeff Chen  *
5*73b01e57SJeff Chen  * Copyright 2011-2024 NXP
6*73b01e57SJeff Chen  */
7*73b01e57SJeff Chen 
8*73b01e57SJeff Chen #include <linux/debugfs.h>
9*73b01e57SJeff Chen 
10*73b01e57SJeff Chen #include "main.h"
11*73b01e57SJeff Chen #include "cmdevt.h"
12*73b01e57SJeff Chen #include "11n.h"
13*73b01e57SJeff Chen 
14*73b01e57SJeff Chen static struct dentry *nxpwifi_dfs_dir;
15*73b01e57SJeff Chen 
16*73b01e57SJeff Chen static char *bss_modes[] = {
17*73b01e57SJeff Chen 	"UNSPECIFIED",
18*73b01e57SJeff Chen 	"ADHOC",
19*73b01e57SJeff Chen 	"STATION",
20*73b01e57SJeff Chen 	"AP",
21*73b01e57SJeff Chen 	"AP_VLAN",
22*73b01e57SJeff Chen 	"WDS",
23*73b01e57SJeff Chen 	"MONITOR",
24*73b01e57SJeff Chen 	"MESH_POINT",
25*73b01e57SJeff Chen 	"P2P_CLIENT",
26*73b01e57SJeff Chen 	"P2P_GO",
27*73b01e57SJeff Chen 	"P2P_DEVICE",
28*73b01e57SJeff Chen };
29*73b01e57SJeff Chen 
30*73b01e57SJeff Chen /*
31*73b01e57SJeff Chen  * debugfs "info" read handler: dump driver name/version, interface, BSS mode,
32*73b01e57SJeff Chen  * link state, MAC, counters; STA adds SSID/BSSID/channel/country/region and
33*73b01e57SJeff Chen  * multicast list.
34*73b01e57SJeff Chen  */
35*73b01e57SJeff Chen static ssize_t
nxpwifi_info_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)36*73b01e57SJeff Chen nxpwifi_info_read(struct file *file, char __user *ubuf,
37*73b01e57SJeff Chen 		  size_t count, loff_t *ppos)
38*73b01e57SJeff Chen {
39*73b01e57SJeff Chen 	struct nxpwifi_private *priv =
40*73b01e57SJeff Chen 		(struct nxpwifi_private *)file->private_data;
41*73b01e57SJeff Chen 	struct net_device *netdev = priv->netdev;
42*73b01e57SJeff Chen 	struct netdev_hw_addr *ha;
43*73b01e57SJeff Chen 	struct netdev_queue *txq;
44*73b01e57SJeff Chen 	unsigned long page = get_zeroed_page(GFP_KERNEL);
45*73b01e57SJeff Chen 	char *p = (char *)page, fmt[64];
46*73b01e57SJeff Chen 	struct nxpwifi_bss_info info;
47*73b01e57SJeff Chen 	ssize_t ret;
48*73b01e57SJeff Chen 	int i = 0;
49*73b01e57SJeff Chen 
50*73b01e57SJeff Chen 	if (!p)
51*73b01e57SJeff Chen 		return -ENOMEM;
52*73b01e57SJeff Chen 
53*73b01e57SJeff Chen 	memset(&info, 0, sizeof(info));
54*73b01e57SJeff Chen 	ret = nxpwifi_get_bss_info(priv, &info);
55*73b01e57SJeff Chen 	if (ret)
56*73b01e57SJeff Chen 		goto free_and_exit;
57*73b01e57SJeff Chen 
58*73b01e57SJeff Chen 	nxpwifi_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
59*73b01e57SJeff Chen 
60*73b01e57SJeff Chen 	nxpwifi_get_ver_ext(priv, 0);
61*73b01e57SJeff Chen 
62*73b01e57SJeff Chen 	p += sprintf(p, "driver_name = ");
63*73b01e57SJeff Chen 	p += sprintf(p, "\"nxpwifi\"\n");
64*73b01e57SJeff Chen 	p += sprintf(p, "driver_version = %s", fmt);
65*73b01e57SJeff Chen 	p += sprintf(p, "\nverext = %s", priv->version_str);
66*73b01e57SJeff Chen 	p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
67*73b01e57SJeff Chen 
68*73b01e57SJeff Chen 	if (info.bss_mode >= ARRAY_SIZE(bss_modes))
69*73b01e57SJeff Chen 		p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
70*73b01e57SJeff Chen 	else
71*73b01e57SJeff Chen 		p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
72*73b01e57SJeff Chen 
73*73b01e57SJeff Chen 	p += sprintf(p, "media_state=\"%s\"\n",
74*73b01e57SJeff Chen 		     (!priv->media_connected ? "Disconnected" : "Connected"));
75*73b01e57SJeff Chen 	p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
76*73b01e57SJeff Chen 
77*73b01e57SJeff Chen 	if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA) {
78*73b01e57SJeff Chen 		p += sprintf(p, "multicast_count=\"%d\"\n",
79*73b01e57SJeff Chen 			     netdev_mc_count(netdev));
80*73b01e57SJeff Chen 		p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len,
81*73b01e57SJeff Chen 			     info.ssid.ssid);
82*73b01e57SJeff Chen 		p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
83*73b01e57SJeff Chen 		p += sprintf(p, "channel=\"%d\"\n", (int)info.bss_chan);
84*73b01e57SJeff Chen 		p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
85*73b01e57SJeff Chen 		p += sprintf(p, "region_code=\"0x%x\"\n",
86*73b01e57SJeff Chen 			     priv->adapter->region_code);
87*73b01e57SJeff Chen 
88*73b01e57SJeff Chen 		netdev_for_each_mc_addr(ha, netdev)
89*73b01e57SJeff Chen 			p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",
90*73b01e57SJeff Chen 					i++, ha->addr);
91*73b01e57SJeff Chen 	}
92*73b01e57SJeff Chen 
93*73b01e57SJeff Chen 	p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
94*73b01e57SJeff Chen 	p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
95*73b01e57SJeff Chen 	p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
96*73b01e57SJeff Chen 	p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
97*73b01e57SJeff Chen 	p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
98*73b01e57SJeff Chen 	p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
99*73b01e57SJeff Chen 	p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
100*73b01e57SJeff Chen 	p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
101*73b01e57SJeff Chen 	p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
102*73b01e57SJeff Chen 					 ? "on" : "off"));
103*73b01e57SJeff Chen 	p += sprintf(p, "tx queue");
104*73b01e57SJeff Chen 	for (i = 0; i < netdev->num_tx_queues; i++) {
105*73b01e57SJeff Chen 		txq = netdev_get_tx_queue(netdev, i);
106*73b01e57SJeff Chen 		p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ?
107*73b01e57SJeff Chen 			     "stopped" : "started");
108*73b01e57SJeff Chen 	}
109*73b01e57SJeff Chen 	p += sprintf(p, "\n");
110*73b01e57SJeff Chen 
111*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
112*73b01e57SJeff Chen 				      (unsigned long)p - page);
113*73b01e57SJeff Chen 
114*73b01e57SJeff Chen free_and_exit:
115*73b01e57SJeff Chen 	free_page(page);
116*73b01e57SJeff Chen 	return ret;
117*73b01e57SJeff Chen }
118*73b01e57SJeff Chen 
119*73b01e57SJeff Chen /*
120*73b01e57SJeff Chen  * debugfs "getlog" read handler: dump firmware/802.11 counters (retry, RTS/ACK, dup,
121*73b01e57SJeff Chen  * frag, mcast, FCS, beacon stats).
122*73b01e57SJeff Chen  */
123*73b01e57SJeff Chen static ssize_t
nxpwifi_getlog_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)124*73b01e57SJeff Chen nxpwifi_getlog_read(struct file *file, char __user *ubuf,
125*73b01e57SJeff Chen 		    size_t count, loff_t *ppos)
126*73b01e57SJeff Chen {
127*73b01e57SJeff Chen 	struct nxpwifi_private *priv =
128*73b01e57SJeff Chen 		(struct nxpwifi_private *)file->private_data;
129*73b01e57SJeff Chen 	unsigned long page = get_zeroed_page(GFP_KERNEL);
130*73b01e57SJeff Chen 	char *p = (char *)page;
131*73b01e57SJeff Chen 	ssize_t ret;
132*73b01e57SJeff Chen 	struct nxpwifi_ds_get_stats stats;
133*73b01e57SJeff Chen 
134*73b01e57SJeff Chen 	if (!p)
135*73b01e57SJeff Chen 		return -ENOMEM;
136*73b01e57SJeff Chen 
137*73b01e57SJeff Chen 	memset(&stats, 0, sizeof(stats));
138*73b01e57SJeff Chen 	ret = nxpwifi_get_stats_info(priv, &stats);
139*73b01e57SJeff Chen 	if (ret)
140*73b01e57SJeff Chen 		goto free_and_exit;
141*73b01e57SJeff Chen 
142*73b01e57SJeff Chen 	p += sprintf(p, "\n"
143*73b01e57SJeff Chen 		     "mcasttxframe     %u\n"
144*73b01e57SJeff Chen 		     "failed           %u\n"
145*73b01e57SJeff Chen 		     "retry            %u\n"
146*73b01e57SJeff Chen 		     "multiretry       %u\n"
147*73b01e57SJeff Chen 		     "framedup         %u\n"
148*73b01e57SJeff Chen 		     "rtssuccess       %u\n"
149*73b01e57SJeff Chen 		     "rtsfailure       %u\n"
150*73b01e57SJeff Chen 		     "ackfailure       %u\n"
151*73b01e57SJeff Chen 		     "rxfrag           %u\n"
152*73b01e57SJeff Chen 		     "mcastrxframe     %u\n"
153*73b01e57SJeff Chen 		     "fcserror         %u\n"
154*73b01e57SJeff Chen 		     "txframe          %u\n"
155*73b01e57SJeff Chen 		     "wepicverrcnt-1   %u\n"
156*73b01e57SJeff Chen 		     "wepicverrcnt-2   %u\n"
157*73b01e57SJeff Chen 		     "wepicverrcnt-3   %u\n"
158*73b01e57SJeff Chen 		     "wepicverrcnt-4   %u\n"
159*73b01e57SJeff Chen 		     "bcn_rcv_cnt   %u\n"
160*73b01e57SJeff Chen 		     "bcn_miss_cnt   %u\n",
161*73b01e57SJeff Chen 		     stats.mcast_tx_frame,
162*73b01e57SJeff Chen 		     stats.failed,
163*73b01e57SJeff Chen 		     stats.retry,
164*73b01e57SJeff Chen 		     stats.multi_retry,
165*73b01e57SJeff Chen 		     stats.frame_dup,
166*73b01e57SJeff Chen 		     stats.rts_success,
167*73b01e57SJeff Chen 		     stats.rts_failure,
168*73b01e57SJeff Chen 		     stats.ack_failure,
169*73b01e57SJeff Chen 		     stats.rx_frag,
170*73b01e57SJeff Chen 		     stats.mcast_rx_frame,
171*73b01e57SJeff Chen 		     stats.fcs_error,
172*73b01e57SJeff Chen 		     stats.tx_frame,
173*73b01e57SJeff Chen 		     stats.wep_icv_error[0],
174*73b01e57SJeff Chen 		     stats.wep_icv_error[1],
175*73b01e57SJeff Chen 		     stats.wep_icv_error[2],
176*73b01e57SJeff Chen 		     stats.wep_icv_error[3],
177*73b01e57SJeff Chen 		     stats.bcn_rcv_cnt,
178*73b01e57SJeff Chen 		     stats.bcn_miss_cnt);
179*73b01e57SJeff Chen 
180*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
181*73b01e57SJeff Chen 				      (unsigned long)p - page);
182*73b01e57SJeff Chen 
183*73b01e57SJeff Chen free_and_exit:
184*73b01e57SJeff Chen 	free_page(page);
185*73b01e57SJeff Chen 	return ret;
186*73b01e57SJeff Chen }
187*73b01e57SJeff Chen 
188*73b01e57SJeff Chen /*
189*73b01e57SJeff Chen  * debugfs "histogram" read handler: report sample count and per-rate/SNR/noise
190*73b01e57SJeff Chen  * floor/signal strength histograms.
191*73b01e57SJeff Chen  */
192*73b01e57SJeff Chen static ssize_t
nxpwifi_histogram_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)193*73b01e57SJeff Chen nxpwifi_histogram_read(struct file *file, char __user *ubuf,
194*73b01e57SJeff Chen 		       size_t count, loff_t *ppos)
195*73b01e57SJeff Chen {
196*73b01e57SJeff Chen 	struct nxpwifi_private *priv =
197*73b01e57SJeff Chen 		(struct nxpwifi_private *)file->private_data;
198*73b01e57SJeff Chen 	ssize_t ret;
199*73b01e57SJeff Chen 	struct nxpwifi_histogram_data *phist_data;
200*73b01e57SJeff Chen 	int i, value;
201*73b01e57SJeff Chen 	unsigned long page = get_zeroed_page(GFP_KERNEL);
202*73b01e57SJeff Chen 	char *p = (char *)page;
203*73b01e57SJeff Chen 
204*73b01e57SJeff Chen 	if (!p)
205*73b01e57SJeff Chen 		return -ENOMEM;
206*73b01e57SJeff Chen 
207*73b01e57SJeff Chen 	if (!priv || !priv->hist_data) {
208*73b01e57SJeff Chen 		ret = -EFAULT;
209*73b01e57SJeff Chen 		goto free_and_exit;
210*73b01e57SJeff Chen 	}
211*73b01e57SJeff Chen 
212*73b01e57SJeff Chen 	phist_data = priv->hist_data;
213*73b01e57SJeff Chen 
214*73b01e57SJeff Chen 	p += sprintf(p, "\n"
215*73b01e57SJeff Chen 		     "total samples = %d\n",
216*73b01e57SJeff Chen 		     atomic_read(&phist_data->num_samples));
217*73b01e57SJeff Chen 
218*73b01e57SJeff Chen 	p += sprintf(p,
219*73b01e57SJeff Chen 		     "rx rates (in Mbps): 0=1M   1=2M 2=5.5M  3=11M   4=6M   5=9M  6=12M\n"
220*73b01e57SJeff Chen 		     "7=18M  8=24M  9=36M  10=48M  11=54M 12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n");
221*73b01e57SJeff Chen 
222*73b01e57SJeff Chen 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
223*73b01e57SJeff Chen 		p += sprintf(p,
224*73b01e57SJeff Chen 			     "44-53=MCS0-9(VHT:BW20) 54-63=MCS0-9(VHT:BW40) 64-73=MCS0-9(VHT:BW80)\n\n");
225*73b01e57SJeff Chen 	} else {
226*73b01e57SJeff Chen 		p += sprintf(p, "\n");
227*73b01e57SJeff Chen 	}
228*73b01e57SJeff Chen 
229*73b01e57SJeff Chen 	for (i = 0; i < NXPWIFI_MAX_RX_RATES; i++) {
230*73b01e57SJeff Chen 		value = atomic_read(&phist_data->rx_rate[i]);
231*73b01e57SJeff Chen 		if (value)
232*73b01e57SJeff Chen 			p += sprintf(p, "rx_rate[%02d] = %d\n", i, value);
233*73b01e57SJeff Chen 	}
234*73b01e57SJeff Chen 
235*73b01e57SJeff Chen 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
236*73b01e57SJeff Chen 		for (i = NXPWIFI_MAX_RX_RATES; i < NXPWIFI_MAX_AC_RX_RATES;
237*73b01e57SJeff Chen 		     i++) {
238*73b01e57SJeff Chen 			value = atomic_read(&phist_data->rx_rate[i]);
239*73b01e57SJeff Chen 			if (value)
240*73b01e57SJeff Chen 				p += sprintf(p, "rx_rate[%02d] = %d\n",
241*73b01e57SJeff Chen 					   i, value);
242*73b01e57SJeff Chen 		}
243*73b01e57SJeff Chen 	}
244*73b01e57SJeff Chen 
245*73b01e57SJeff Chen 	for (i = 0; i < NXPWIFI_MAX_SNR; i++) {
246*73b01e57SJeff Chen 		value =  atomic_read(&phist_data->snr[i]);
247*73b01e57SJeff Chen 		if (value)
248*73b01e57SJeff Chen 			p += sprintf(p, "snr[%02ddB] = %d\n", i, value);
249*73b01e57SJeff Chen 	}
250*73b01e57SJeff Chen 	for (i = 0; i < NXPWIFI_MAX_NOISE_FLR; i++) {
251*73b01e57SJeff Chen 		value = atomic_read(&phist_data->noise_flr[i]);
252*73b01e57SJeff Chen 		if (value)
253*73b01e57SJeff Chen 			p += sprintf(p, "noise_flr[%02ddBm] = %d\n",
254*73b01e57SJeff Chen 				     (int)(i - 128), value);
255*73b01e57SJeff Chen 	}
256*73b01e57SJeff Chen 	for (i = 0; i < NXPWIFI_MAX_SIG_STRENGTH; i++) {
257*73b01e57SJeff Chen 		value = atomic_read(&phist_data->sig_str[i]);
258*73b01e57SJeff Chen 		if (value)
259*73b01e57SJeff Chen 			p += sprintf(p, "sig_strength[-%02ddBm] = %d\n",
260*73b01e57SJeff Chen 				i, value);
261*73b01e57SJeff Chen 	}
262*73b01e57SJeff Chen 
263*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
264*73b01e57SJeff Chen 				      (unsigned long)p - page);
265*73b01e57SJeff Chen 
266*73b01e57SJeff Chen free_and_exit:
267*73b01e57SJeff Chen 	free_page(page);
268*73b01e57SJeff Chen 	return ret;
269*73b01e57SJeff Chen }
270*73b01e57SJeff Chen 
271*73b01e57SJeff Chen static ssize_t
nxpwifi_histogram_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)272*73b01e57SJeff Chen nxpwifi_histogram_write(struct file *file, const char __user *ubuf,
273*73b01e57SJeff Chen 			size_t count, loff_t *ppos)
274*73b01e57SJeff Chen {
275*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
276*73b01e57SJeff Chen 
277*73b01e57SJeff Chen 	if (priv && priv->hist_data)
278*73b01e57SJeff Chen 		nxpwifi_hist_data_reset(priv);
279*73b01e57SJeff Chen 	return 0;
280*73b01e57SJeff Chen }
281*73b01e57SJeff Chen 
282*73b01e57SJeff Chen static struct nxpwifi_debug_info info;
283*73b01e57SJeff Chen 
284*73b01e57SJeff Chen /* debugfs "debug" read handler: dump adapter debug info and BA/reorder tables. */
285*73b01e57SJeff Chen static ssize_t
nxpwifi_debug_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)286*73b01e57SJeff Chen nxpwifi_debug_read(struct file *file, char __user *ubuf,
287*73b01e57SJeff Chen 		   size_t count, loff_t *ppos)
288*73b01e57SJeff Chen {
289*73b01e57SJeff Chen 	struct nxpwifi_private *priv =
290*73b01e57SJeff Chen 		(struct nxpwifi_private *)file->private_data;
291*73b01e57SJeff Chen 	unsigned long page = get_zeroed_page(GFP_KERNEL);
292*73b01e57SJeff Chen 	char *p = (char *)page;
293*73b01e57SJeff Chen 	ssize_t ret;
294*73b01e57SJeff Chen 
295*73b01e57SJeff Chen 	if (!p)
296*73b01e57SJeff Chen 		return -ENOMEM;
297*73b01e57SJeff Chen 
298*73b01e57SJeff Chen 	ret = nxpwifi_get_debug_info(priv, &info);
299*73b01e57SJeff Chen 	if (ret)
300*73b01e57SJeff Chen 		goto free_and_exit;
301*73b01e57SJeff Chen 
302*73b01e57SJeff Chen 	p += nxpwifi_debug_info_to_buffer(priv, p, &info);
303*73b01e57SJeff Chen 
304*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
305*73b01e57SJeff Chen 				      (unsigned long)p - page);
306*73b01e57SJeff Chen 
307*73b01e57SJeff Chen free_and_exit:
308*73b01e57SJeff Chen 	free_page(page);
309*73b01e57SJeff Chen 	return ret;
310*73b01e57SJeff Chen }
311*73b01e57SJeff Chen 
312*73b01e57SJeff Chen static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
313*73b01e57SJeff Chen 
314*73b01e57SJeff Chen /*
315*73b01e57SJeff Chen  * debugfs "regrdwr" write handler: parse <type offset value> and store for
316*73b01e57SJeff Chen  * readback/IO.
317*73b01e57SJeff Chen  */
318*73b01e57SJeff Chen static ssize_t
nxpwifi_regrdwr_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)319*73b01e57SJeff Chen nxpwifi_regrdwr_write(struct file *file,
320*73b01e57SJeff Chen 		      const char __user *ubuf, size_t count, loff_t *ppos)
321*73b01e57SJeff Chen {
322*73b01e57SJeff Chen 	char *buf;
323*73b01e57SJeff Chen 	int ret;
324*73b01e57SJeff Chen 	u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
325*73b01e57SJeff Chen 	int rv;
326*73b01e57SJeff Chen 
327*73b01e57SJeff Chen 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
328*73b01e57SJeff Chen 	if (IS_ERR(buf))
329*73b01e57SJeff Chen 		return PTR_ERR(buf);
330*73b01e57SJeff Chen 
331*73b01e57SJeff Chen 	rv = sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
332*73b01e57SJeff Chen 
333*73b01e57SJeff Chen 	if (rv != 3) {
334*73b01e57SJeff Chen 		ret = -EINVAL;
335*73b01e57SJeff Chen 		goto done;
336*73b01e57SJeff Chen 	}
337*73b01e57SJeff Chen 
338*73b01e57SJeff Chen 	if (reg_type == 0 || reg_offset == 0) {
339*73b01e57SJeff Chen 		ret = -EINVAL;
340*73b01e57SJeff Chen 		goto done;
341*73b01e57SJeff Chen 	} else {
342*73b01e57SJeff Chen 		saved_reg_type = reg_type;
343*73b01e57SJeff Chen 		saved_reg_offset = reg_offset;
344*73b01e57SJeff Chen 		saved_reg_value = reg_value;
345*73b01e57SJeff Chen 		ret = count;
346*73b01e57SJeff Chen 	}
347*73b01e57SJeff Chen done:
348*73b01e57SJeff Chen 	kfree(buf);
349*73b01e57SJeff Chen 	return ret;
350*73b01e57SJeff Chen }
351*73b01e57SJeff Chen 
352*73b01e57SJeff Chen /*
353*73b01e57SJeff Chen  * debugfs "regrdwr" read handler: perform pending register read/write and return
354*73b01e57SJeff Chen  * <type offset value>.
355*73b01e57SJeff Chen  */
356*73b01e57SJeff Chen static ssize_t
nxpwifi_regrdwr_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)357*73b01e57SJeff Chen nxpwifi_regrdwr_read(struct file *file, char __user *ubuf,
358*73b01e57SJeff Chen 		     size_t count, loff_t *ppos)
359*73b01e57SJeff Chen {
360*73b01e57SJeff Chen 	struct nxpwifi_private *priv =
361*73b01e57SJeff Chen 		(struct nxpwifi_private *)file->private_data;
362*73b01e57SJeff Chen 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
363*73b01e57SJeff Chen 	char *buf = (char *)addr;
364*73b01e57SJeff Chen 	int pos = 0, ret = 0;
365*73b01e57SJeff Chen 	u32 reg_value;
366*73b01e57SJeff Chen 
367*73b01e57SJeff Chen 	if (!buf)
368*73b01e57SJeff Chen 		return -ENOMEM;
369*73b01e57SJeff Chen 
370*73b01e57SJeff Chen 	if (!saved_reg_type) {
371*73b01e57SJeff Chen 		/* No command has been given */
372*73b01e57SJeff Chen 		pos += snprintf(buf, PAGE_SIZE, "0");
373*73b01e57SJeff Chen 		goto done;
374*73b01e57SJeff Chen 	}
375*73b01e57SJeff Chen 	/* Set command has been given */
376*73b01e57SJeff Chen 	if (saved_reg_value != UINT_MAX) {
377*73b01e57SJeff Chen 		ret = nxpwifi_reg_write(priv, saved_reg_type, saved_reg_offset,
378*73b01e57SJeff Chen 					saved_reg_value);
379*73b01e57SJeff Chen 
380*73b01e57SJeff Chen 		pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
381*73b01e57SJeff Chen 				saved_reg_type, saved_reg_offset,
382*73b01e57SJeff Chen 				saved_reg_value);
383*73b01e57SJeff Chen 
384*73b01e57SJeff Chen 		ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
385*73b01e57SJeff Chen 
386*73b01e57SJeff Chen 		goto done;
387*73b01e57SJeff Chen 	}
388*73b01e57SJeff Chen 	/* Get command has been given */
389*73b01e57SJeff Chen 	ret = nxpwifi_reg_read(priv, saved_reg_type,
390*73b01e57SJeff Chen 			       saved_reg_offset, &reg_value);
391*73b01e57SJeff Chen 	if (ret) {
392*73b01e57SJeff Chen 		ret = -EINVAL;
393*73b01e57SJeff Chen 		goto done;
394*73b01e57SJeff Chen 	}
395*73b01e57SJeff Chen 
396*73b01e57SJeff Chen 	pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
397*73b01e57SJeff Chen 			saved_reg_offset, reg_value);
398*73b01e57SJeff Chen 
399*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
400*73b01e57SJeff Chen 
401*73b01e57SJeff Chen done:
402*73b01e57SJeff Chen 	free_page(addr);
403*73b01e57SJeff Chen 	return ret;
404*73b01e57SJeff Chen }
405*73b01e57SJeff Chen 
406*73b01e57SJeff Chen /* debugfs "debug_mask" read handler: show driver debug mask. */
407*73b01e57SJeff Chen 
408*73b01e57SJeff Chen static ssize_t
nxpwifi_debug_mask_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)409*73b01e57SJeff Chen nxpwifi_debug_mask_read(struct file *file, char __user *ubuf,
410*73b01e57SJeff Chen 			size_t count, loff_t *ppos)
411*73b01e57SJeff Chen {
412*73b01e57SJeff Chen 	struct nxpwifi_private *priv =
413*73b01e57SJeff Chen 		(struct nxpwifi_private *)file->private_data;
414*73b01e57SJeff Chen 	unsigned long page = get_zeroed_page(GFP_KERNEL);
415*73b01e57SJeff Chen 	char *buf = (char *)page;
416*73b01e57SJeff Chen 	size_t ret = 0;
417*73b01e57SJeff Chen 	int pos = 0;
418*73b01e57SJeff Chen 
419*73b01e57SJeff Chen 	if (!buf)
420*73b01e57SJeff Chen 		return -ENOMEM;
421*73b01e57SJeff Chen 
422*73b01e57SJeff Chen 	pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n",
423*73b01e57SJeff Chen 			priv->adapter->debug_mask);
424*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
425*73b01e57SJeff Chen 
426*73b01e57SJeff Chen 	free_page(page);
427*73b01e57SJeff Chen 	return ret;
428*73b01e57SJeff Chen }
429*73b01e57SJeff Chen 
430*73b01e57SJeff Chen /* debugfs "debug_mask" write handler: set driver debug mask. */
431*73b01e57SJeff Chen 
432*73b01e57SJeff Chen static ssize_t
nxpwifi_debug_mask_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)433*73b01e57SJeff Chen nxpwifi_debug_mask_write(struct file *file, const char __user *ubuf,
434*73b01e57SJeff Chen 			 size_t count, loff_t *ppos)
435*73b01e57SJeff Chen {
436*73b01e57SJeff Chen 	int ret;
437*73b01e57SJeff Chen 	unsigned long debug_mask;
438*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
439*73b01e57SJeff Chen 	char *buf;
440*73b01e57SJeff Chen 
441*73b01e57SJeff Chen 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
442*73b01e57SJeff Chen 	if (IS_ERR(buf))
443*73b01e57SJeff Chen 		return PTR_ERR(buf);
444*73b01e57SJeff Chen 
445*73b01e57SJeff Chen 	if (kstrtoul(buf, 0, &debug_mask)) {
446*73b01e57SJeff Chen 		ret = -EINVAL;
447*73b01e57SJeff Chen 		goto done;
448*73b01e57SJeff Chen 	}
449*73b01e57SJeff Chen 
450*73b01e57SJeff Chen 	priv->adapter->debug_mask = debug_mask;
451*73b01e57SJeff Chen 	ret = count;
452*73b01e57SJeff Chen done:
453*73b01e57SJeff Chen 	kfree(buf);
454*73b01e57SJeff Chen 	return ret;
455*73b01e57SJeff Chen }
456*73b01e57SJeff Chen 
457*73b01e57SJeff Chen /* debugfs "verext" write handler: select extended version string. */
458*73b01e57SJeff Chen static ssize_t
nxpwifi_verext_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)459*73b01e57SJeff Chen nxpwifi_verext_write(struct file *file, const char __user *ubuf,
460*73b01e57SJeff Chen 		     size_t count, loff_t *ppos)
461*73b01e57SJeff Chen {
462*73b01e57SJeff Chen 	int ret;
463*73b01e57SJeff Chen 	u32 versionstrsel;
464*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
465*73b01e57SJeff Chen 
466*73b01e57SJeff Chen 	ret = kstrtou32_from_user(ubuf, count, 10, &versionstrsel);
467*73b01e57SJeff Chen 	if (ret)
468*73b01e57SJeff Chen 		return ret;
469*73b01e57SJeff Chen 
470*73b01e57SJeff Chen 	priv->versionstrsel = versionstrsel;
471*73b01e57SJeff Chen 
472*73b01e57SJeff Chen 	return count;
473*73b01e57SJeff Chen }
474*73b01e57SJeff Chen 
475*73b01e57SJeff Chen /* debugfs "verext" read handler: show extended version string. */
476*73b01e57SJeff Chen static ssize_t
nxpwifi_verext_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)477*73b01e57SJeff Chen nxpwifi_verext_read(struct file *file, char __user *ubuf,
478*73b01e57SJeff Chen 		    size_t count, loff_t *ppos)
479*73b01e57SJeff Chen {
480*73b01e57SJeff Chen 	struct nxpwifi_private *priv =
481*73b01e57SJeff Chen 		(struct nxpwifi_private *)file->private_data;
482*73b01e57SJeff Chen 	char buf[256];
483*73b01e57SJeff Chen 	int ret;
484*73b01e57SJeff Chen 
485*73b01e57SJeff Chen 	nxpwifi_get_ver_ext(priv, priv->versionstrsel);
486*73b01e57SJeff Chen 	ret = snprintf(buf, sizeof(buf), "version string: %s\n",
487*73b01e57SJeff Chen 		       priv->version_str);
488*73b01e57SJeff Chen 
489*73b01e57SJeff Chen 	return simple_read_from_buffer(ubuf, count, ppos, buf, ret);
490*73b01e57SJeff Chen }
491*73b01e57SJeff Chen 
492*73b01e57SJeff Chen /* debugfs "memrw" write handler: read/write firmware memory (addr, value). */
493*73b01e57SJeff Chen static ssize_t
nxpwifi_memrw_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)494*73b01e57SJeff Chen nxpwifi_memrw_write(struct file *file, const char __user *ubuf, size_t count,
495*73b01e57SJeff Chen 		    loff_t *ppos)
496*73b01e57SJeff Chen {
497*73b01e57SJeff Chen 	int ret;
498*73b01e57SJeff Chen 	char cmd;
499*73b01e57SJeff Chen 	struct nxpwifi_ds_mem_rw mem_rw;
500*73b01e57SJeff Chen 	u16 cmd_action;
501*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
502*73b01e57SJeff Chen 	char *buf;
503*73b01e57SJeff Chen 
504*73b01e57SJeff Chen 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
505*73b01e57SJeff Chen 	if (IS_ERR(buf))
506*73b01e57SJeff Chen 		return PTR_ERR(buf);
507*73b01e57SJeff Chen 
508*73b01e57SJeff Chen 	ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);
509*73b01e57SJeff Chen 	if (ret != 3) {
510*73b01e57SJeff Chen 		ret = -EINVAL;
511*73b01e57SJeff Chen 		goto done;
512*73b01e57SJeff Chen 	}
513*73b01e57SJeff Chen 
514*73b01e57SJeff Chen 	if ((cmd == 'r') || (cmd == 'R')) {
515*73b01e57SJeff Chen 		cmd_action = HOST_ACT_GEN_GET;
516*73b01e57SJeff Chen 		mem_rw.value = 0;
517*73b01e57SJeff Chen 	} else if ((cmd == 'w') || (cmd == 'W')) {
518*73b01e57SJeff Chen 		cmd_action = HOST_ACT_GEN_SET;
519*73b01e57SJeff Chen 	} else {
520*73b01e57SJeff Chen 		ret = -EINVAL;
521*73b01e57SJeff Chen 		goto done;
522*73b01e57SJeff Chen 	}
523*73b01e57SJeff Chen 
524*73b01e57SJeff Chen 	memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw));
525*73b01e57SJeff Chen 	ret = nxpwifi_send_cmd(priv, HOST_CMD_MEM_ACCESS, cmd_action, 0,
526*73b01e57SJeff Chen 			       &mem_rw, true);
527*73b01e57SJeff Chen 	if (!ret)
528*73b01e57SJeff Chen 		ret = count;
529*73b01e57SJeff Chen 
530*73b01e57SJeff Chen done:
531*73b01e57SJeff Chen 	kfree(buf);
532*73b01e57SJeff Chen 	return ret;
533*73b01e57SJeff Chen }
534*73b01e57SJeff Chen 
535*73b01e57SJeff Chen /* debugfs "memrw" read handler: show last memory access result. */
536*73b01e57SJeff Chen static ssize_t
nxpwifi_memrw_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)537*73b01e57SJeff Chen nxpwifi_memrw_read(struct file *file, char __user *ubuf,
538*73b01e57SJeff Chen 		   size_t count, loff_t *ppos)
539*73b01e57SJeff Chen {
540*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
541*73b01e57SJeff Chen 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
542*73b01e57SJeff Chen 	char *buf = (char *)addr;
543*73b01e57SJeff Chen 	int ret, pos = 0;
544*73b01e57SJeff Chen 
545*73b01e57SJeff Chen 	if (!buf)
546*73b01e57SJeff Chen 		return -ENOMEM;
547*73b01e57SJeff Chen 
548*73b01e57SJeff Chen 	pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr,
549*73b01e57SJeff Chen 			priv->mem_rw.value);
550*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
551*73b01e57SJeff Chen 
552*73b01e57SJeff Chen 	free_page(addr);
553*73b01e57SJeff Chen 	return ret;
554*73b01e57SJeff Chen }
555*73b01e57SJeff Chen 
556*73b01e57SJeff Chen static u32 saved_offset = -1, saved_bytes = -1;
557*73b01e57SJeff Chen 
558*73b01e57SJeff Chen /* debugfs "rdeeprom" write handler: set EEPROM offset/length to read. */
559*73b01e57SJeff Chen static ssize_t
nxpwifi_rdeeprom_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)560*73b01e57SJeff Chen nxpwifi_rdeeprom_write(struct file *file,
561*73b01e57SJeff Chen 		       const char __user *ubuf, size_t count, loff_t *ppos)
562*73b01e57SJeff Chen {
563*73b01e57SJeff Chen 	char *buf;
564*73b01e57SJeff Chen 	int ret = 0;
565*73b01e57SJeff Chen 	int offset = -1, bytes = -1;
566*73b01e57SJeff Chen 	int rv;
567*73b01e57SJeff Chen 
568*73b01e57SJeff Chen 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
569*73b01e57SJeff Chen 	if (IS_ERR(buf))
570*73b01e57SJeff Chen 		return PTR_ERR(buf);
571*73b01e57SJeff Chen 
572*73b01e57SJeff Chen 	rv = sscanf(buf, "%d %d", &offset, &bytes);
573*73b01e57SJeff Chen 
574*73b01e57SJeff Chen 	if (rv != 2) {
575*73b01e57SJeff Chen 		ret = -EINVAL;
576*73b01e57SJeff Chen 		goto done;
577*73b01e57SJeff Chen 	}
578*73b01e57SJeff Chen 
579*73b01e57SJeff Chen 	if (offset == -1 || bytes == -1) {
580*73b01e57SJeff Chen 		ret = -EINVAL;
581*73b01e57SJeff Chen 		goto done;
582*73b01e57SJeff Chen 	} else {
583*73b01e57SJeff Chen 		saved_offset = offset;
584*73b01e57SJeff Chen 		saved_bytes = bytes;
585*73b01e57SJeff Chen 		ret = count;
586*73b01e57SJeff Chen 	}
587*73b01e57SJeff Chen done:
588*73b01e57SJeff Chen 	kfree(buf);
589*73b01e57SJeff Chen 	return ret;
590*73b01e57SJeff Chen }
591*73b01e57SJeff Chen 
592*73b01e57SJeff Chen /* debugfs "rdeeprom" read handler: dump EEPROM bytes from saved offset/length. */
593*73b01e57SJeff Chen static ssize_t
nxpwifi_rdeeprom_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)594*73b01e57SJeff Chen nxpwifi_rdeeprom_read(struct file *file, char __user *ubuf,
595*73b01e57SJeff Chen 		      size_t count, loff_t *ppos)
596*73b01e57SJeff Chen {
597*73b01e57SJeff Chen 	struct nxpwifi_private *priv =
598*73b01e57SJeff Chen 		(struct nxpwifi_private *)file->private_data;
599*73b01e57SJeff Chen 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
600*73b01e57SJeff Chen 	char *buf = (char *)addr;
601*73b01e57SJeff Chen 	int pos, ret, i;
602*73b01e57SJeff Chen 	u8 value[MAX_EEPROM_DATA];
603*73b01e57SJeff Chen 
604*73b01e57SJeff Chen 	if (!buf)
605*73b01e57SJeff Chen 		return -ENOMEM;
606*73b01e57SJeff Chen 
607*73b01e57SJeff Chen 	if (saved_offset == -1) {
608*73b01e57SJeff Chen 		/* No command has been given */
609*73b01e57SJeff Chen 		pos = snprintf(buf, PAGE_SIZE, "0");
610*73b01e57SJeff Chen 		goto done;
611*73b01e57SJeff Chen 	}
612*73b01e57SJeff Chen 
613*73b01e57SJeff Chen 	/* Get command has been given */
614*73b01e57SJeff Chen 	ret = nxpwifi_eeprom_read(priv, (u16)saved_offset,
615*73b01e57SJeff Chen 				  (u16)saved_bytes, value);
616*73b01e57SJeff Chen 	if (ret) {
617*73b01e57SJeff Chen 		ret = -EINVAL;
618*73b01e57SJeff Chen 		goto out_free;
619*73b01e57SJeff Chen 	}
620*73b01e57SJeff Chen 
621*73b01e57SJeff Chen 	pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
622*73b01e57SJeff Chen 
623*73b01e57SJeff Chen 	for (i = 0; i < saved_bytes; i++)
624*73b01e57SJeff Chen 		pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]);
625*73b01e57SJeff Chen 
626*73b01e57SJeff Chen done:
627*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
628*73b01e57SJeff Chen out_free:
629*73b01e57SJeff Chen 	free_page(addr);
630*73b01e57SJeff Chen 	return ret;
631*73b01e57SJeff Chen }
632*73b01e57SJeff Chen 
633*73b01e57SJeff Chen /*
634*73b01e57SJeff Chen  * debugfs "hscfg" write handler: configure host-sleep (conditions/gpio/gap) or
635*73b01e57SJeff Chen  * cancel.
636*73b01e57SJeff Chen  */
637*73b01e57SJeff Chen static ssize_t
nxpwifi_hscfg_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)638*73b01e57SJeff Chen nxpwifi_hscfg_write(struct file *file, const char __user *ubuf,
639*73b01e57SJeff Chen 		    size_t count, loff_t *ppos)
640*73b01e57SJeff Chen {
641*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
642*73b01e57SJeff Chen 	char *buf;
643*73b01e57SJeff Chen 	int ret, arg_num;
644*73b01e57SJeff Chen 	struct nxpwifi_ds_hs_cfg hscfg;
645*73b01e57SJeff Chen 	int conditions = HS_CFG_COND_DEF;
646*73b01e57SJeff Chen 	u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF;
647*73b01e57SJeff Chen 
648*73b01e57SJeff Chen 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
649*73b01e57SJeff Chen 	if (IS_ERR(buf))
650*73b01e57SJeff Chen 		return PTR_ERR(buf);
651*73b01e57SJeff Chen 
652*73b01e57SJeff Chen 	arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap);
653*73b01e57SJeff Chen 
654*73b01e57SJeff Chen 	memset(&hscfg, 0, sizeof(struct nxpwifi_ds_hs_cfg));
655*73b01e57SJeff Chen 
656*73b01e57SJeff Chen 	if (arg_num > 3) {
657*73b01e57SJeff Chen 		nxpwifi_dbg(priv->adapter, ERROR,
658*73b01e57SJeff Chen 			    "Too many arguments\n");
659*73b01e57SJeff Chen 		ret = -EINVAL;
660*73b01e57SJeff Chen 		goto done;
661*73b01e57SJeff Chen 	}
662*73b01e57SJeff Chen 
663*73b01e57SJeff Chen 	if (arg_num >= 1 && arg_num < 3)
664*73b01e57SJeff Chen 		nxpwifi_set_hs_params(priv, HOST_ACT_GEN_GET,
665*73b01e57SJeff Chen 				      NXPWIFI_SYNC_CMD, &hscfg);
666*73b01e57SJeff Chen 
667*73b01e57SJeff Chen 	if (arg_num) {
668*73b01e57SJeff Chen 		if (conditions == HS_CFG_CANCEL) {
669*73b01e57SJeff Chen 			nxpwifi_cancel_hs(priv, NXPWIFI_ASYNC_CMD);
670*73b01e57SJeff Chen 			ret = count;
671*73b01e57SJeff Chen 			goto done;
672*73b01e57SJeff Chen 		}
673*73b01e57SJeff Chen 		hscfg.conditions = conditions;
674*73b01e57SJeff Chen 	}
675*73b01e57SJeff Chen 	if (arg_num >= 2)
676*73b01e57SJeff Chen 		hscfg.gpio = gpio;
677*73b01e57SJeff Chen 	if (arg_num == 3)
678*73b01e57SJeff Chen 		hscfg.gap = gap;
679*73b01e57SJeff Chen 
680*73b01e57SJeff Chen 	hscfg.is_invoke_hostcmd = false;
681*73b01e57SJeff Chen 	nxpwifi_set_hs_params(priv, HOST_ACT_GEN_SET,
682*73b01e57SJeff Chen 			      NXPWIFI_SYNC_CMD, &hscfg);
683*73b01e57SJeff Chen 
684*73b01e57SJeff Chen 	nxpwifi_enable_hs(priv->adapter);
685*73b01e57SJeff Chen 	clear_bit(NXPWIFI_IS_HS_ENABLING, &priv->adapter->work_flags);
686*73b01e57SJeff Chen 	ret = count;
687*73b01e57SJeff Chen done:
688*73b01e57SJeff Chen 	kfree(buf);
689*73b01e57SJeff Chen 	return ret;
690*73b01e57SJeff Chen }
691*73b01e57SJeff Chen 
692*73b01e57SJeff Chen /* debugfs "hscfg" read handler: show current host-sleep configuration. */
693*73b01e57SJeff Chen static ssize_t
nxpwifi_hscfg_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)694*73b01e57SJeff Chen nxpwifi_hscfg_read(struct file *file, char __user *ubuf,
695*73b01e57SJeff Chen 		   size_t count, loff_t *ppos)
696*73b01e57SJeff Chen {
697*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
698*73b01e57SJeff Chen 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
699*73b01e57SJeff Chen 	char *buf = (char *)addr;
700*73b01e57SJeff Chen 	int pos, ret;
701*73b01e57SJeff Chen 	struct nxpwifi_ds_hs_cfg hscfg;
702*73b01e57SJeff Chen 
703*73b01e57SJeff Chen 	if (!buf)
704*73b01e57SJeff Chen 		return -ENOMEM;
705*73b01e57SJeff Chen 
706*73b01e57SJeff Chen 	nxpwifi_set_hs_params(priv, HOST_ACT_GEN_GET,
707*73b01e57SJeff Chen 			      NXPWIFI_SYNC_CMD, &hscfg);
708*73b01e57SJeff Chen 
709*73b01e57SJeff Chen 	pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions,
710*73b01e57SJeff Chen 		       hscfg.gpio, hscfg.gap);
711*73b01e57SJeff Chen 
712*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
713*73b01e57SJeff Chen 
714*73b01e57SJeff Chen 	free_page(addr);
715*73b01e57SJeff Chen 	return ret;
716*73b01e57SJeff Chen }
717*73b01e57SJeff Chen 
718*73b01e57SJeff Chen static ssize_t
nxpwifi_timeshare_coex_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)719*73b01e57SJeff Chen nxpwifi_timeshare_coex_read(struct file *file, char __user *ubuf,
720*73b01e57SJeff Chen 			    size_t count, loff_t *ppos)
721*73b01e57SJeff Chen {
722*73b01e57SJeff Chen 	struct nxpwifi_private *priv = file->private_data;
723*73b01e57SJeff Chen 	char buf[3];
724*73b01e57SJeff Chen 	bool timeshare_coex;
725*73b01e57SJeff Chen 	int ret;
726*73b01e57SJeff Chen 	unsigned int len;
727*73b01e57SJeff Chen 
728*73b01e57SJeff Chen 	if (priv->adapter->fw_api_ver != NXPWIFI_FW_V15)
729*73b01e57SJeff Chen 		return -EOPNOTSUPP;
730*73b01e57SJeff Chen 
731*73b01e57SJeff Chen 	ret = nxpwifi_send_cmd(priv, HOST_CMD_ROBUST_COEX,
732*73b01e57SJeff Chen 			       HOST_ACT_GEN_GET, 0, &timeshare_coex, true);
733*73b01e57SJeff Chen 	if (ret)
734*73b01e57SJeff Chen 		return ret;
735*73b01e57SJeff Chen 
736*73b01e57SJeff Chen 	len = sprintf(buf, "%d\n", timeshare_coex);
737*73b01e57SJeff Chen 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
738*73b01e57SJeff Chen }
739*73b01e57SJeff Chen 
740*73b01e57SJeff Chen static ssize_t
nxpwifi_timeshare_coex_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)741*73b01e57SJeff Chen nxpwifi_timeshare_coex_write(struct file *file, const char __user *ubuf,
742*73b01e57SJeff Chen 			     size_t count, loff_t *ppos)
743*73b01e57SJeff Chen {
744*73b01e57SJeff Chen 	bool timeshare_coex;
745*73b01e57SJeff Chen 	struct nxpwifi_private *priv = file->private_data;
746*73b01e57SJeff Chen 	int ret;
747*73b01e57SJeff Chen 
748*73b01e57SJeff Chen 	if (priv->adapter->fw_api_ver != NXPWIFI_FW_V15)
749*73b01e57SJeff Chen 		return -EOPNOTSUPP;
750*73b01e57SJeff Chen 
751*73b01e57SJeff Chen 	ret = kstrtobool_from_user(ubuf, count, &timeshare_coex);
752*73b01e57SJeff Chen 	if (ret)
753*73b01e57SJeff Chen 		return ret;
754*73b01e57SJeff Chen 
755*73b01e57SJeff Chen 	ret = nxpwifi_send_cmd(priv, HOST_CMD_ROBUST_COEX,
756*73b01e57SJeff Chen 			       HOST_ACT_GEN_SET, 0, &timeshare_coex, true);
757*73b01e57SJeff Chen 	if (ret)
758*73b01e57SJeff Chen 		return ret;
759*73b01e57SJeff Chen 	else
760*73b01e57SJeff Chen 		return count;
761*73b01e57SJeff Chen }
762*73b01e57SJeff Chen 
763*73b01e57SJeff Chen static ssize_t
nxpwifi_reset_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)764*73b01e57SJeff Chen nxpwifi_reset_write(struct file *file,
765*73b01e57SJeff Chen 		    const char __user *ubuf, size_t count, loff_t *ppos)
766*73b01e57SJeff Chen {
767*73b01e57SJeff Chen 	struct nxpwifi_private *priv = file->private_data;
768*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
769*73b01e57SJeff Chen 	bool result;
770*73b01e57SJeff Chen 	int rc;
771*73b01e57SJeff Chen 
772*73b01e57SJeff Chen 	rc = kstrtobool_from_user(ubuf, count, &result);
773*73b01e57SJeff Chen 	if (rc)
774*73b01e57SJeff Chen 		return rc;
775*73b01e57SJeff Chen 
776*73b01e57SJeff Chen 	if (!result)
777*73b01e57SJeff Chen 		return -EINVAL;
778*73b01e57SJeff Chen 
779*73b01e57SJeff Chen 	if (adapter->if_ops.card_reset) {
780*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, INFO, "Resetting per request\n");
781*73b01e57SJeff Chen 		adapter->if_ops.card_reset(adapter);
782*73b01e57SJeff Chen 	}
783*73b01e57SJeff Chen 
784*73b01e57SJeff Chen 	return count;
785*73b01e57SJeff Chen }
786*73b01e57SJeff Chen 
787*73b01e57SJeff Chen static ssize_t
nxpwifi_fake_radar_detect_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)788*73b01e57SJeff Chen nxpwifi_fake_radar_detect_write(struct file *file,
789*73b01e57SJeff Chen 				const char __user *ubuf,
790*73b01e57SJeff Chen 				size_t count, loff_t *ppos)
791*73b01e57SJeff Chen {
792*73b01e57SJeff Chen 	struct nxpwifi_private *priv = file->private_data;
793*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
794*73b01e57SJeff Chen 	bool result;
795*73b01e57SJeff Chen 	int rc;
796*73b01e57SJeff Chen 
797*73b01e57SJeff Chen 	rc = kstrtobool_from_user(ubuf, count, &result);
798*73b01e57SJeff Chen 	if (rc)
799*73b01e57SJeff Chen 		return rc;
800*73b01e57SJeff Chen 
801*73b01e57SJeff Chen 	if (!result)
802*73b01e57SJeff Chen 		return -EINVAL;
803*73b01e57SJeff Chen 
804*73b01e57SJeff Chen 	if (priv->wdev.links[0].cac_started) {
805*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, MSG,
806*73b01e57SJeff Chen 			    "Generate fake radar detected during CAC\n");
807*73b01e57SJeff Chen 		if (nxpwifi_stop_radar_detection(priv, &priv->dfs_chandef))
808*73b01e57SJeff Chen 			nxpwifi_dbg(adapter, ERROR,
809*73b01e57SJeff Chen 				    "Failed to stop CAC in FW\n");
810*73b01e57SJeff Chen 		wiphy_delayed_work_cancel(priv->adapter->wiphy, &priv->dfs_cac_work);
811*73b01e57SJeff Chen 		cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
812*73b01e57SJeff Chen 				   NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0);
813*73b01e57SJeff Chen 		cfg80211_radar_event(adapter->wiphy, &priv->dfs_chandef,
814*73b01e57SJeff Chen 				     GFP_KERNEL);
815*73b01e57SJeff Chen 	} else {
816*73b01e57SJeff Chen 		if (priv->bss_chandef.chan->dfs_cac_ms) {
817*73b01e57SJeff Chen 			nxpwifi_dbg(adapter, MSG,
818*73b01e57SJeff Chen 				    "Generate fake radar detected\n");
819*73b01e57SJeff Chen 			cfg80211_radar_event(adapter->wiphy,
820*73b01e57SJeff Chen 					     &priv->dfs_chandef,
821*73b01e57SJeff Chen 					     GFP_KERNEL);
822*73b01e57SJeff Chen 		}
823*73b01e57SJeff Chen 	}
824*73b01e57SJeff Chen 
825*73b01e57SJeff Chen 	return count;
826*73b01e57SJeff Chen }
827*73b01e57SJeff Chen 
828*73b01e57SJeff Chen static ssize_t
nxpwifi_netmon_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)829*73b01e57SJeff Chen nxpwifi_netmon_write(struct file *file, const char __user *ubuf,
830*73b01e57SJeff Chen 		     size_t count, loff_t *ppos)
831*73b01e57SJeff Chen {
832*73b01e57SJeff Chen 	int ret;
833*73b01e57SJeff Chen 	struct nxpwifi_802_11_net_monitor netmon_cfg;
834*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
835*73b01e57SJeff Chen 	char *buf;
836*73b01e57SJeff Chen 
837*73b01e57SJeff Chen 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
838*73b01e57SJeff Chen 	if (IS_ERR(buf))
839*73b01e57SJeff Chen 		return PTR_ERR(buf);
840*73b01e57SJeff Chen 	memset(&netmon_cfg, 0, sizeof(struct nxpwifi_802_11_net_monitor));
841*73b01e57SJeff Chen 	ret = sscanf(buf, "%u %u %u %u %u",
842*73b01e57SJeff Chen 		     &netmon_cfg.enable_net_mon,
843*73b01e57SJeff Chen 		     &netmon_cfg.filter_flag,
844*73b01e57SJeff Chen 		     &netmon_cfg.band,
845*73b01e57SJeff Chen 		     &netmon_cfg.channel,
846*73b01e57SJeff Chen 		     &netmon_cfg.chan_bandwidth);
847*73b01e57SJeff Chen 
848*73b01e57SJeff Chen 	ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_NET_MONITOR,
849*73b01e57SJeff Chen 			       HOST_ACT_GEN_SET, 0, &netmon_cfg, true);
850*73b01e57SJeff Chen 
851*73b01e57SJeff Chen 	if (!ret)
852*73b01e57SJeff Chen 		ret = count;
853*73b01e57SJeff Chen 
854*73b01e57SJeff Chen 	kfree(buf);
855*73b01e57SJeff Chen 	return ret;
856*73b01e57SJeff Chen }
857*73b01e57SJeff Chen 
858*73b01e57SJeff Chen static ssize_t
nxpwifi_twt_setup_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)859*73b01e57SJeff Chen nxpwifi_twt_setup_write(struct file *file, const char __user *ubuf,
860*73b01e57SJeff Chen 			size_t count, loff_t *ppos)
861*73b01e57SJeff Chen {
862*73b01e57SJeff Chen 	int ret;
863*73b01e57SJeff Chen 	struct nxpwifi_twt_cfg twt_cfg;
864*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
865*73b01e57SJeff Chen 	char *buf;
866*73b01e57SJeff Chen 	u16 twt_mantissa, bcn_miss_threshold;
867*73b01e57SJeff Chen 
868*73b01e57SJeff Chen 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
869*73b01e57SJeff Chen 	if (IS_ERR(buf))
870*73b01e57SJeff Chen 		return PTR_ERR(buf);
871*73b01e57SJeff Chen 
872*73b01e57SJeff Chen 	ret = sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hu %hhu %hu",
873*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.implicit,
874*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.announced,
875*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.trigger_enabled,
876*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.twt_info_disabled,
877*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.negotiation_type,
878*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.twt_wakeup_duration,
879*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.flow_identifier,
880*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.hard_constraint,
881*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.twt_exponent,
882*73b01e57SJeff Chen 		     &twt_mantissa,
883*73b01e57SJeff Chen 		     &twt_cfg.param.twt_setup.twt_request,
884*73b01e57SJeff Chen 		     &bcn_miss_threshold);
885*73b01e57SJeff Chen 
886*73b01e57SJeff Chen 	twt_cfg.param.twt_setup.twt_mantissa = cpu_to_le16(twt_mantissa);
887*73b01e57SJeff Chen 	twt_cfg.param.twt_setup.bcn_miss_threshold = cpu_to_le16(bcn_miss_threshold);
888*73b01e57SJeff Chen 	twt_cfg.sub_id = NXPWIFI_11AX_TWT_SETUP_SUBID;
889*73b01e57SJeff Chen 	ret = nxpwifi_send_cmd(priv, HOST_CMD_TWT_CFG, HOST_ACT_GEN_SET, 0,
890*73b01e57SJeff Chen 			       &twt_cfg, true);
891*73b01e57SJeff Chen 	if (!ret)
892*73b01e57SJeff Chen 		ret = count;
893*73b01e57SJeff Chen 
894*73b01e57SJeff Chen 	kfree(buf);
895*73b01e57SJeff Chen 	return ret;
896*73b01e57SJeff Chen }
897*73b01e57SJeff Chen 
898*73b01e57SJeff Chen static ssize_t
nxpwifi_twt_teardown_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)899*73b01e57SJeff Chen nxpwifi_twt_teardown_write(struct file *file, const char __user *ubuf,
900*73b01e57SJeff Chen 			   size_t count, loff_t *ppos)
901*73b01e57SJeff Chen {
902*73b01e57SJeff Chen 	int ret;
903*73b01e57SJeff Chen 	struct nxpwifi_twt_cfg twt_cfg;
904*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
905*73b01e57SJeff Chen 	char *buf;
906*73b01e57SJeff Chen 
907*73b01e57SJeff Chen 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
908*73b01e57SJeff Chen 	if (IS_ERR(buf))
909*73b01e57SJeff Chen 		return PTR_ERR(buf);
910*73b01e57SJeff Chen 
911*73b01e57SJeff Chen 	ret = sscanf(buf, "%hhu %hhu %hhu",
912*73b01e57SJeff Chen 		     &twt_cfg.param.twt_teardown.flow_identifier,
913*73b01e57SJeff Chen 		     &twt_cfg.param.twt_teardown.negotiation_type,
914*73b01e57SJeff Chen 		     &twt_cfg.param.twt_teardown.teardown_all_twt);
915*73b01e57SJeff Chen 
916*73b01e57SJeff Chen 	twt_cfg.sub_id = NXPWIFI_11AX_TWT_TEARDOWN_SUBID;
917*73b01e57SJeff Chen 	ret = nxpwifi_send_cmd(priv, HOST_CMD_TWT_CFG, HOST_ACT_GEN_SET, 0,
918*73b01e57SJeff Chen 			       &twt_cfg, true);
919*73b01e57SJeff Chen 
920*73b01e57SJeff Chen 	if (!ret)
921*73b01e57SJeff Chen 		ret = count;
922*73b01e57SJeff Chen 
923*73b01e57SJeff Chen 	kfree(buf);
924*73b01e57SJeff Chen 	return ret;
925*73b01e57SJeff Chen }
926*73b01e57SJeff Chen 
927*73b01e57SJeff Chen static ssize_t
nxpwifi_twt_report_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)928*73b01e57SJeff Chen nxpwifi_twt_report_read(struct file *file, char __user *ubuf,
929*73b01e57SJeff Chen 			size_t count, loff_t *ppos)
930*73b01e57SJeff Chen {
931*73b01e57SJeff Chen 	struct nxpwifi_private *priv =
932*73b01e57SJeff Chen 		(struct nxpwifi_private *)file->private_data;
933*73b01e57SJeff Chen 	unsigned long page = get_zeroed_page(GFP_KERNEL);
934*73b01e57SJeff Chen 	char *p = (char *)page;
935*73b01e57SJeff Chen 	ssize_t ret;
936*73b01e57SJeff Chen 	struct nxpwifi_twt_cfg twt_cfg;
937*73b01e57SJeff Chen 	u8 num, i, j;
938*73b01e57SJeff Chen 
939*73b01e57SJeff Chen 	if (!p)
940*73b01e57SJeff Chen 		return -ENOMEM;
941*73b01e57SJeff Chen 
942*73b01e57SJeff Chen 	twt_cfg.sub_id = NXPWIFI_11AX_TWT_REPORT_SUBID;
943*73b01e57SJeff Chen 	ret = nxpwifi_send_cmd(priv, HOST_CMD_TWT_CFG, HOST_ACT_GEN_GET, 0,
944*73b01e57SJeff Chen 			       &twt_cfg, true);
945*73b01e57SJeff Chen 	if (ret)
946*73b01e57SJeff Chen 		goto done;
947*73b01e57SJeff Chen 	num = twt_cfg.param.twt_report.length / NXPWIFI_BTWT_REPORT_LEN;
948*73b01e57SJeff Chen 	num = num <= NXPWIFI_BTWT_REPORT_MAX_NUM ? num : NXPWIFI_BTWT_REPORT_MAX_NUM;
949*73b01e57SJeff Chen 	p += sprintf(p, "\ntwt_report len %hhu, num %hhu, twt_report_info:\n",
950*73b01e57SJeff Chen 		twt_cfg.param.twt_report.length, num);
951*73b01e57SJeff Chen 	for (i = 0; i < num; i++) {
952*73b01e57SJeff Chen 		p += sprintf(p, "id[%hu]:\r\n", i);
953*73b01e57SJeff Chen 		for (j = 0; j < NXPWIFI_BTWT_REPORT_LEN; j++) {
954*73b01e57SJeff Chen 			p += sprintf(p,
955*73b01e57SJeff Chen 				" 0x%02x",
956*73b01e57SJeff Chen 				twt_cfg.param.twt_report.data[i * NXPWIFI_BTWT_REPORT_LEN + j]);
957*73b01e57SJeff Chen 		}
958*73b01e57SJeff Chen 		p += sprintf(p, "\r\n");
959*73b01e57SJeff Chen 	}
960*73b01e57SJeff Chen 
961*73b01e57SJeff Chen 	ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
962*73b01e57SJeff Chen 				      (unsigned long)p - page);
963*73b01e57SJeff Chen 
964*73b01e57SJeff Chen done:
965*73b01e57SJeff Chen 	free_page(page);
966*73b01e57SJeff Chen 	return ret;
967*73b01e57SJeff Chen }
968*73b01e57SJeff Chen 
969*73b01e57SJeff Chen static ssize_t
nxpwifi_twt_information_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)970*73b01e57SJeff Chen nxpwifi_twt_information_write(struct file *file, const char __user *ubuf,
971*73b01e57SJeff Chen 			      size_t count, loff_t *ppos)
972*73b01e57SJeff Chen {
973*73b01e57SJeff Chen 	int ret;
974*73b01e57SJeff Chen 	struct nxpwifi_twt_cfg twt_cfg;
975*73b01e57SJeff Chen 	struct nxpwifi_private *priv = (void *)file->private_data;
976*73b01e57SJeff Chen 	char *buf;
977*73b01e57SJeff Chen 	u32 suspend_duration;
978*73b01e57SJeff Chen 
979*73b01e57SJeff Chen 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
980*73b01e57SJeff Chen 	if (IS_ERR(buf))
981*73b01e57SJeff Chen 		return PTR_ERR(buf);
982*73b01e57SJeff Chen 
983*73b01e57SJeff Chen 	ret = sscanf(buf, "%hhu %u",
984*73b01e57SJeff Chen 		     &twt_cfg.param.twt_information.flow_identifier, &suspend_duration);
985*73b01e57SJeff Chen 	twt_cfg.param.twt_information.suspend_duration = cpu_to_le32(suspend_duration);
986*73b01e57SJeff Chen 
987*73b01e57SJeff Chen 	twt_cfg.sub_id = NXPWIFI_11AX_TWT_INFORMATION_SUBID;
988*73b01e57SJeff Chen 	ret = nxpwifi_send_cmd(priv, HOST_CMD_TWT_CFG, HOST_ACT_GEN_SET, 0,
989*73b01e57SJeff Chen 			       &twt_cfg, true);
990*73b01e57SJeff Chen 
991*73b01e57SJeff Chen 	if (!ret)
992*73b01e57SJeff Chen 		ret = count;
993*73b01e57SJeff Chen 
994*73b01e57SJeff Chen 	kfree(buf);
995*73b01e57SJeff Chen 	return ret;
996*73b01e57SJeff Chen }
997*73b01e57SJeff Chen 
998*73b01e57SJeff Chen #define NXPWIFI_DFS_ADD_FILE(name) debugfs_create_file(#name, 0644,     \
999*73b01e57SJeff Chen 				   priv->dfs_dev_dir, priv,             \
1000*73b01e57SJeff Chen 				   &nxpwifi_dfs_##name##_fops)
1001*73b01e57SJeff Chen 
1002*73b01e57SJeff Chen #define NXPWIFI_DFS_FILE_OPS(name)                                      \
1003*73b01e57SJeff Chen static const struct file_operations nxpwifi_dfs_##name##_fops = {       \
1004*73b01e57SJeff Chen 	.read = nxpwifi_##name##_read,                                  \
1005*73b01e57SJeff Chen 	.write = nxpwifi_##name##_write,                                \
1006*73b01e57SJeff Chen 	.open = simple_open,                                            \
1007*73b01e57SJeff Chen }
1008*73b01e57SJeff Chen 
1009*73b01e57SJeff Chen #define NXPWIFI_DFS_FILE_READ_OPS(name)                                 \
1010*73b01e57SJeff Chen static const struct file_operations nxpwifi_dfs_##name##_fops = {       \
1011*73b01e57SJeff Chen 	.read = nxpwifi_##name##_read,                                  \
1012*73b01e57SJeff Chen 	.open = simple_open,                                            \
1013*73b01e57SJeff Chen }
1014*73b01e57SJeff Chen 
1015*73b01e57SJeff Chen #define NXPWIFI_DFS_FILE_WRITE_OPS(name)                                \
1016*73b01e57SJeff Chen static const struct file_operations nxpwifi_dfs_##name##_fops = {       \
1017*73b01e57SJeff Chen 	.write = nxpwifi_##name##_write,                                \
1018*73b01e57SJeff Chen 	.open = simple_open,                                            \
1019*73b01e57SJeff Chen }
1020*73b01e57SJeff Chen 
1021*73b01e57SJeff Chen NXPWIFI_DFS_FILE_READ_OPS(info);
1022*73b01e57SJeff Chen NXPWIFI_DFS_FILE_READ_OPS(debug);
1023*73b01e57SJeff Chen NXPWIFI_DFS_FILE_READ_OPS(getlog);
1024*73b01e57SJeff Chen NXPWIFI_DFS_FILE_OPS(regrdwr);
1025*73b01e57SJeff Chen NXPWIFI_DFS_FILE_OPS(rdeeprom);
1026*73b01e57SJeff Chen NXPWIFI_DFS_FILE_OPS(memrw);
1027*73b01e57SJeff Chen NXPWIFI_DFS_FILE_OPS(hscfg);
1028*73b01e57SJeff Chen NXPWIFI_DFS_FILE_OPS(histogram);
1029*73b01e57SJeff Chen NXPWIFI_DFS_FILE_OPS(debug_mask);
1030*73b01e57SJeff Chen NXPWIFI_DFS_FILE_OPS(timeshare_coex);
1031*73b01e57SJeff Chen NXPWIFI_DFS_FILE_WRITE_OPS(reset);
1032*73b01e57SJeff Chen NXPWIFI_DFS_FILE_WRITE_OPS(fake_radar_detect);
1033*73b01e57SJeff Chen NXPWIFI_DFS_FILE_OPS(verext);
1034*73b01e57SJeff Chen NXPWIFI_DFS_FILE_WRITE_OPS(netmon);
1035*73b01e57SJeff Chen NXPWIFI_DFS_FILE_WRITE_OPS(twt_setup);
1036*73b01e57SJeff Chen NXPWIFI_DFS_FILE_WRITE_OPS(twt_teardown);
1037*73b01e57SJeff Chen NXPWIFI_DFS_FILE_READ_OPS(twt_report);
1038*73b01e57SJeff Chen NXPWIFI_DFS_FILE_WRITE_OPS(twt_information);
1039*73b01e57SJeff Chen 
1040*73b01e57SJeff Chen /* Create per-netdev debugfs directory and files. */
1041*73b01e57SJeff Chen void
nxpwifi_dev_debugfs_init(struct nxpwifi_private * priv)1042*73b01e57SJeff Chen nxpwifi_dev_debugfs_init(struct nxpwifi_private *priv)
1043*73b01e57SJeff Chen {
1044*73b01e57SJeff Chen 	if (!nxpwifi_dfs_dir || !priv)
1045*73b01e57SJeff Chen 		return;
1046*73b01e57SJeff Chen 
1047*73b01e57SJeff Chen 	priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
1048*73b01e57SJeff Chen 					       nxpwifi_dfs_dir);
1049*73b01e57SJeff Chen 
1050*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(info);
1051*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(debug);
1052*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(getlog);
1053*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(regrdwr);
1054*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(rdeeprom);
1055*73b01e57SJeff Chen 
1056*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(memrw);
1057*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(hscfg);
1058*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(histogram);
1059*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(debug_mask);
1060*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(timeshare_coex);
1061*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(reset);
1062*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(fake_radar_detect);
1063*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(verext);
1064*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(netmon);
1065*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(twt_setup);
1066*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(twt_teardown);
1067*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(twt_report);
1068*73b01e57SJeff Chen 	NXPWIFI_DFS_ADD_FILE(twt_information);
1069*73b01e57SJeff Chen }
1070*73b01e57SJeff Chen 
1071*73b01e57SJeff Chen /* Remove per-netdev debugfs directory and files. */
1072*73b01e57SJeff Chen void
nxpwifi_dev_debugfs_remove(struct nxpwifi_private * priv)1073*73b01e57SJeff Chen nxpwifi_dev_debugfs_remove(struct nxpwifi_private *priv)
1074*73b01e57SJeff Chen {
1075*73b01e57SJeff Chen 	if (!priv)
1076*73b01e57SJeff Chen 		return;
1077*73b01e57SJeff Chen 
1078*73b01e57SJeff Chen 	debugfs_remove_recursive(priv->dfs_dev_dir);
1079*73b01e57SJeff Chen }
1080*73b01e57SJeff Chen 
1081*73b01e57SJeff Chen /* Create top-level debugfs directory. */
1082*73b01e57SJeff Chen void
nxpwifi_debugfs_init(void)1083*73b01e57SJeff Chen nxpwifi_debugfs_init(void)
1084*73b01e57SJeff Chen {
1085*73b01e57SJeff Chen 	if (!nxpwifi_dfs_dir)
1086*73b01e57SJeff Chen 		nxpwifi_dfs_dir = debugfs_create_dir("nxpwifi", NULL);
1087*73b01e57SJeff Chen }
1088*73b01e57SJeff Chen 
1089*73b01e57SJeff Chen /* Remove top-level debugfs directory. */
1090*73b01e57SJeff Chen void
nxpwifi_debugfs_remove(void)1091*73b01e57SJeff Chen nxpwifi_debugfs_remove(void)
1092*73b01e57SJeff Chen {
1093*73b01e57SJeff Chen 	debugfs_remove(nxpwifi_dfs_dir);
1094*73b01e57SJeff Chen }
1095