xref: /openbmc/linux/drivers/net/wireless/intel/iwlegacy/debug.c (revision 7ac9a364c1721a863ecc6cc9aba66e10114908db)
1*7ac9a364SKalle Valo /******************************************************************************
2*7ac9a364SKalle Valo  *
3*7ac9a364SKalle Valo  * GPL LICENSE SUMMARY
4*7ac9a364SKalle Valo  *
5*7ac9a364SKalle Valo  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
6*7ac9a364SKalle Valo  *
7*7ac9a364SKalle Valo  * This program is free software; you can redistribute it and/or modify
8*7ac9a364SKalle Valo  * it under the terms of version 2 of the GNU General Public License as
9*7ac9a364SKalle Valo  * published by the Free Software Foundation.
10*7ac9a364SKalle Valo  *
11*7ac9a364SKalle Valo  * This program is distributed in the hope that it will be useful, but
12*7ac9a364SKalle Valo  * WITHOUT ANY WARRANTY; without even the implied warranty of
13*7ac9a364SKalle Valo  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*7ac9a364SKalle Valo  * General Public License for more details.
15*7ac9a364SKalle Valo  *
16*7ac9a364SKalle Valo  * You should have received a copy of the GNU General Public License
17*7ac9a364SKalle Valo  * along with this program; if not, write to the Free Software
18*7ac9a364SKalle Valo  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
19*7ac9a364SKalle Valo  * USA
20*7ac9a364SKalle Valo  *
21*7ac9a364SKalle Valo  * The full GNU General Public License is included in this distribution
22*7ac9a364SKalle Valo  * in the file called LICENSE.GPL.
23*7ac9a364SKalle Valo  *
24*7ac9a364SKalle Valo  * Contact Information:
25*7ac9a364SKalle Valo  *  Intel Linux Wireless <ilw@linux.intel.com>
26*7ac9a364SKalle Valo  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27*7ac9a364SKalle Valo  *****************************************************************************/
28*7ac9a364SKalle Valo #include <linux/ieee80211.h>
29*7ac9a364SKalle Valo #include <linux/export.h>
30*7ac9a364SKalle Valo #include <net/mac80211.h>
31*7ac9a364SKalle Valo 
32*7ac9a364SKalle Valo #include "common.h"
33*7ac9a364SKalle Valo 
34*7ac9a364SKalle Valo static void
35*7ac9a364SKalle Valo il_clear_traffic_stats(struct il_priv *il)
36*7ac9a364SKalle Valo {
37*7ac9a364SKalle Valo 	memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
38*7ac9a364SKalle Valo 	memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
39*7ac9a364SKalle Valo }
40*7ac9a364SKalle Valo 
41*7ac9a364SKalle Valo /*
42*7ac9a364SKalle Valo  * il_update_stats function record all the MGMT, CTRL and DATA pkt for
43*7ac9a364SKalle Valo  * both TX and Rx . Use debugfs to display the rx/rx_stats
44*7ac9a364SKalle Valo  */
45*7ac9a364SKalle Valo void
46*7ac9a364SKalle Valo il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
47*7ac9a364SKalle Valo {
48*7ac9a364SKalle Valo 	struct traffic_stats *stats;
49*7ac9a364SKalle Valo 
50*7ac9a364SKalle Valo 	if (is_tx)
51*7ac9a364SKalle Valo 		stats = &il->tx_stats;
52*7ac9a364SKalle Valo 	else
53*7ac9a364SKalle Valo 		stats = &il->rx_stats;
54*7ac9a364SKalle Valo 
55*7ac9a364SKalle Valo 	if (ieee80211_is_mgmt(fc)) {
56*7ac9a364SKalle Valo 		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
57*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
58*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
59*7ac9a364SKalle Valo 			break;
60*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
61*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
62*7ac9a364SKalle Valo 			break;
63*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
64*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
65*7ac9a364SKalle Valo 			break;
66*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
67*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
68*7ac9a364SKalle Valo 			break;
69*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
70*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_PROBE_REQ]++;
71*7ac9a364SKalle Valo 			break;
72*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
73*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_PROBE_RESP]++;
74*7ac9a364SKalle Valo 			break;
75*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_BEACON):
76*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_BEACON]++;
77*7ac9a364SKalle Valo 			break;
78*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ATIM):
79*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_ATIM]++;
80*7ac9a364SKalle Valo 			break;
81*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
82*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_DISASSOC]++;
83*7ac9a364SKalle Valo 			break;
84*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_AUTH):
85*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_AUTH]++;
86*7ac9a364SKalle Valo 			break;
87*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
88*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_DEAUTH]++;
89*7ac9a364SKalle Valo 			break;
90*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ACTION):
91*7ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_ACTION]++;
92*7ac9a364SKalle Valo 			break;
93*7ac9a364SKalle Valo 		}
94*7ac9a364SKalle Valo 	} else if (ieee80211_is_ctl(fc)) {
95*7ac9a364SKalle Valo 		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
96*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
97*7ac9a364SKalle Valo 			stats->ctrl[CONTROL_BACK_REQ]++;
98*7ac9a364SKalle Valo 			break;
99*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_BACK):
100*7ac9a364SKalle Valo 			stats->ctrl[CONTROL_BACK]++;
101*7ac9a364SKalle Valo 			break;
102*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
103*7ac9a364SKalle Valo 			stats->ctrl[CONTROL_PSPOLL]++;
104*7ac9a364SKalle Valo 			break;
105*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_RTS):
106*7ac9a364SKalle Valo 			stats->ctrl[CONTROL_RTS]++;
107*7ac9a364SKalle Valo 			break;
108*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_CTS):
109*7ac9a364SKalle Valo 			stats->ctrl[CONTROL_CTS]++;
110*7ac9a364SKalle Valo 			break;
111*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ACK):
112*7ac9a364SKalle Valo 			stats->ctrl[CONTROL_ACK]++;
113*7ac9a364SKalle Valo 			break;
114*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_CFEND):
115*7ac9a364SKalle Valo 			stats->ctrl[CONTROL_CFEND]++;
116*7ac9a364SKalle Valo 			break;
117*7ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
118*7ac9a364SKalle Valo 			stats->ctrl[CONTROL_CFENDACK]++;
119*7ac9a364SKalle Valo 			break;
120*7ac9a364SKalle Valo 		}
121*7ac9a364SKalle Valo 	} else {
122*7ac9a364SKalle Valo 		/* data */
123*7ac9a364SKalle Valo 		stats->data_cnt++;
124*7ac9a364SKalle Valo 		stats->data_bytes += len;
125*7ac9a364SKalle Valo 	}
126*7ac9a364SKalle Valo }
127*7ac9a364SKalle Valo EXPORT_SYMBOL(il_update_stats);
128*7ac9a364SKalle Valo 
129*7ac9a364SKalle Valo /* create and remove of files */
130*7ac9a364SKalle Valo #define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
131*7ac9a364SKalle Valo 	if (!debugfs_create_file(#name, mode, parent, il,		\
132*7ac9a364SKalle Valo 			 &il_dbgfs_##name##_ops))		\
133*7ac9a364SKalle Valo 		goto err;						\
134*7ac9a364SKalle Valo } while (0)
135*7ac9a364SKalle Valo 
136*7ac9a364SKalle Valo #define DEBUGFS_ADD_BOOL(name, parent, ptr) do {			\
137*7ac9a364SKalle Valo 	struct dentry *__tmp;						\
138*7ac9a364SKalle Valo 	__tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,		\
139*7ac9a364SKalle Valo 				    parent, ptr);			\
140*7ac9a364SKalle Valo 	if (IS_ERR(__tmp) || !__tmp)					\
141*7ac9a364SKalle Valo 		goto err;						\
142*7ac9a364SKalle Valo } while (0)
143*7ac9a364SKalle Valo 
144*7ac9a364SKalle Valo #define DEBUGFS_ADD_X32(name, parent, ptr) do {				\
145*7ac9a364SKalle Valo 	struct dentry *__tmp;						\
146*7ac9a364SKalle Valo 	__tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,		\
147*7ac9a364SKalle Valo 				   parent, ptr);			\
148*7ac9a364SKalle Valo 	if (IS_ERR(__tmp) || !__tmp)					\
149*7ac9a364SKalle Valo 		goto err;						\
150*7ac9a364SKalle Valo } while (0)
151*7ac9a364SKalle Valo 
152*7ac9a364SKalle Valo /* file operation */
153*7ac9a364SKalle Valo #define DEBUGFS_READ_FUNC(name)                                         \
154*7ac9a364SKalle Valo static ssize_t il_dbgfs_##name##_read(struct file *file,               \
155*7ac9a364SKalle Valo 					char __user *user_buf,          \
156*7ac9a364SKalle Valo 					size_t count, loff_t *ppos);
157*7ac9a364SKalle Valo 
158*7ac9a364SKalle Valo #define DEBUGFS_WRITE_FUNC(name)                                        \
159*7ac9a364SKalle Valo static ssize_t il_dbgfs_##name##_write(struct file *file,              \
160*7ac9a364SKalle Valo 					const char __user *user_buf,    \
161*7ac9a364SKalle Valo 					size_t count, loff_t *ppos);
162*7ac9a364SKalle Valo 
163*7ac9a364SKalle Valo 
164*7ac9a364SKalle Valo #define DEBUGFS_READ_FILE_OPS(name)				\
165*7ac9a364SKalle Valo 	DEBUGFS_READ_FUNC(name);				\
166*7ac9a364SKalle Valo static const struct file_operations il_dbgfs_##name##_ops = {	\
167*7ac9a364SKalle Valo 	.read = il_dbgfs_##name##_read,				\
168*7ac9a364SKalle Valo 	.open = simple_open,					\
169*7ac9a364SKalle Valo 	.llseek = generic_file_llseek,				\
170*7ac9a364SKalle Valo };
171*7ac9a364SKalle Valo 
172*7ac9a364SKalle Valo #define DEBUGFS_WRITE_FILE_OPS(name)				\
173*7ac9a364SKalle Valo 	DEBUGFS_WRITE_FUNC(name);				\
174*7ac9a364SKalle Valo static const struct file_operations il_dbgfs_##name##_ops = {	\
175*7ac9a364SKalle Valo 	.write = il_dbgfs_##name##_write,			\
176*7ac9a364SKalle Valo 	.open = simple_open,					\
177*7ac9a364SKalle Valo 	.llseek = generic_file_llseek,				\
178*7ac9a364SKalle Valo };
179*7ac9a364SKalle Valo 
180*7ac9a364SKalle Valo #define DEBUGFS_READ_WRITE_FILE_OPS(name)			\
181*7ac9a364SKalle Valo 	DEBUGFS_READ_FUNC(name);				\
182*7ac9a364SKalle Valo 	DEBUGFS_WRITE_FUNC(name);				\
183*7ac9a364SKalle Valo static const struct file_operations il_dbgfs_##name##_ops = {	\
184*7ac9a364SKalle Valo 	.write = il_dbgfs_##name##_write,			\
185*7ac9a364SKalle Valo 	.read = il_dbgfs_##name##_read,				\
186*7ac9a364SKalle Valo 	.open = simple_open,					\
187*7ac9a364SKalle Valo 	.llseek = generic_file_llseek,				\
188*7ac9a364SKalle Valo };
189*7ac9a364SKalle Valo 
190*7ac9a364SKalle Valo static const char *
191*7ac9a364SKalle Valo il_get_mgmt_string(int cmd)
192*7ac9a364SKalle Valo {
193*7ac9a364SKalle Valo 	switch (cmd) {
194*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_ASSOC_REQ);
195*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_ASSOC_RESP);
196*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_REASSOC_REQ);
197*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_REASSOC_RESP);
198*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_PROBE_REQ);
199*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_PROBE_RESP);
200*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_BEACON);
201*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_ATIM);
202*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_DISASSOC);
203*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_AUTH);
204*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_DEAUTH);
205*7ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_ACTION);
206*7ac9a364SKalle Valo 	default:
207*7ac9a364SKalle Valo 		return "UNKNOWN";
208*7ac9a364SKalle Valo 
209*7ac9a364SKalle Valo 	}
210*7ac9a364SKalle Valo }
211*7ac9a364SKalle Valo 
212*7ac9a364SKalle Valo static const char *
213*7ac9a364SKalle Valo il_get_ctrl_string(int cmd)
214*7ac9a364SKalle Valo {
215*7ac9a364SKalle Valo 	switch (cmd) {
216*7ac9a364SKalle Valo 	IL_CMD(CONTROL_BACK_REQ);
217*7ac9a364SKalle Valo 	IL_CMD(CONTROL_BACK);
218*7ac9a364SKalle Valo 	IL_CMD(CONTROL_PSPOLL);
219*7ac9a364SKalle Valo 	IL_CMD(CONTROL_RTS);
220*7ac9a364SKalle Valo 	IL_CMD(CONTROL_CTS);
221*7ac9a364SKalle Valo 	IL_CMD(CONTROL_ACK);
222*7ac9a364SKalle Valo 	IL_CMD(CONTROL_CFEND);
223*7ac9a364SKalle Valo 	IL_CMD(CONTROL_CFENDACK);
224*7ac9a364SKalle Valo 	default:
225*7ac9a364SKalle Valo 		return "UNKNOWN";
226*7ac9a364SKalle Valo 
227*7ac9a364SKalle Valo 	}
228*7ac9a364SKalle Valo }
229*7ac9a364SKalle Valo 
230*7ac9a364SKalle Valo static ssize_t
231*7ac9a364SKalle Valo il_dbgfs_tx_stats_read(struct file *file, char __user *user_buf, size_t count,
232*7ac9a364SKalle Valo 		       loff_t *ppos)
233*7ac9a364SKalle Valo {
234*7ac9a364SKalle Valo 
235*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
236*7ac9a364SKalle Valo 	char *buf;
237*7ac9a364SKalle Valo 	int pos = 0;
238*7ac9a364SKalle Valo 
239*7ac9a364SKalle Valo 	int cnt;
240*7ac9a364SKalle Valo 	ssize_t ret;
241*7ac9a364SKalle Valo 	const size_t bufsz =
242*7ac9a364SKalle Valo 	    100 + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
243*7ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
244*7ac9a364SKalle Valo 	if (!buf)
245*7ac9a364SKalle Valo 		return -ENOMEM;
246*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
247*7ac9a364SKalle Valo 	for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
248*7ac9a364SKalle Valo 		pos +=
249*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
250*7ac9a364SKalle Valo 			      il_get_mgmt_string(cnt), il->tx_stats.mgmt[cnt]);
251*7ac9a364SKalle Valo 	}
252*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
253*7ac9a364SKalle Valo 	for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
254*7ac9a364SKalle Valo 		pos +=
255*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
256*7ac9a364SKalle Valo 			      il_get_ctrl_string(cnt), il->tx_stats.ctrl[cnt]);
257*7ac9a364SKalle Valo 	}
258*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
259*7ac9a364SKalle Valo 	pos +=
260*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
261*7ac9a364SKalle Valo 		      il->tx_stats.data_cnt);
262*7ac9a364SKalle Valo 	pos +=
263*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
264*7ac9a364SKalle Valo 		      il->tx_stats.data_bytes);
265*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
266*7ac9a364SKalle Valo 	kfree(buf);
267*7ac9a364SKalle Valo 	return ret;
268*7ac9a364SKalle Valo }
269*7ac9a364SKalle Valo 
270*7ac9a364SKalle Valo static ssize_t
271*7ac9a364SKalle Valo il_dbgfs_clear_traffic_stats_write(struct file *file,
272*7ac9a364SKalle Valo 				   const char __user *user_buf, size_t count,
273*7ac9a364SKalle Valo 				   loff_t *ppos)
274*7ac9a364SKalle Valo {
275*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
276*7ac9a364SKalle Valo 	u32 clear_flag;
277*7ac9a364SKalle Valo 	char buf[8];
278*7ac9a364SKalle Valo 	int buf_size;
279*7ac9a364SKalle Valo 
280*7ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
281*7ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
282*7ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
283*7ac9a364SKalle Valo 		return -EFAULT;
284*7ac9a364SKalle Valo 	if (sscanf(buf, "%x", &clear_flag) != 1)
285*7ac9a364SKalle Valo 		return -EFAULT;
286*7ac9a364SKalle Valo 	il_clear_traffic_stats(il);
287*7ac9a364SKalle Valo 
288*7ac9a364SKalle Valo 	return count;
289*7ac9a364SKalle Valo }
290*7ac9a364SKalle Valo 
291*7ac9a364SKalle Valo static ssize_t
292*7ac9a364SKalle Valo il_dbgfs_rx_stats_read(struct file *file, char __user *user_buf, size_t count,
293*7ac9a364SKalle Valo 		       loff_t *ppos)
294*7ac9a364SKalle Valo {
295*7ac9a364SKalle Valo 
296*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
297*7ac9a364SKalle Valo 	char *buf;
298*7ac9a364SKalle Valo 	int pos = 0;
299*7ac9a364SKalle Valo 	int cnt;
300*7ac9a364SKalle Valo 	ssize_t ret;
301*7ac9a364SKalle Valo 	const size_t bufsz =
302*7ac9a364SKalle Valo 	    100 + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
303*7ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
304*7ac9a364SKalle Valo 	if (!buf)
305*7ac9a364SKalle Valo 		return -ENOMEM;
306*7ac9a364SKalle Valo 
307*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
308*7ac9a364SKalle Valo 	for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
309*7ac9a364SKalle Valo 		pos +=
310*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
311*7ac9a364SKalle Valo 			      il_get_mgmt_string(cnt), il->rx_stats.mgmt[cnt]);
312*7ac9a364SKalle Valo 	}
313*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
314*7ac9a364SKalle Valo 	for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
315*7ac9a364SKalle Valo 		pos +=
316*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
317*7ac9a364SKalle Valo 			      il_get_ctrl_string(cnt), il->rx_stats.ctrl[cnt]);
318*7ac9a364SKalle Valo 	}
319*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
320*7ac9a364SKalle Valo 	pos +=
321*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
322*7ac9a364SKalle Valo 		      il->rx_stats.data_cnt);
323*7ac9a364SKalle Valo 	pos +=
324*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
325*7ac9a364SKalle Valo 		      il->rx_stats.data_bytes);
326*7ac9a364SKalle Valo 
327*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
328*7ac9a364SKalle Valo 	kfree(buf);
329*7ac9a364SKalle Valo 	return ret;
330*7ac9a364SKalle Valo }
331*7ac9a364SKalle Valo 
332*7ac9a364SKalle Valo #define BYTE1_MASK 0x000000ff;
333*7ac9a364SKalle Valo #define BYTE2_MASK 0x0000ffff;
334*7ac9a364SKalle Valo #define BYTE3_MASK 0x00ffffff;
335*7ac9a364SKalle Valo static ssize_t
336*7ac9a364SKalle Valo il_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count,
337*7ac9a364SKalle Valo 		   loff_t *ppos)
338*7ac9a364SKalle Valo {
339*7ac9a364SKalle Valo 	u32 val;
340*7ac9a364SKalle Valo 	char *buf;
341*7ac9a364SKalle Valo 	ssize_t ret;
342*7ac9a364SKalle Valo 	int i;
343*7ac9a364SKalle Valo 	int pos = 0;
344*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
345*7ac9a364SKalle Valo 	size_t bufsz;
346*7ac9a364SKalle Valo 
347*7ac9a364SKalle Valo 	/* default is to dump the entire data segment */
348*7ac9a364SKalle Valo 	if (!il->dbgfs_sram_offset && !il->dbgfs_sram_len) {
349*7ac9a364SKalle Valo 		il->dbgfs_sram_offset = 0x800000;
350*7ac9a364SKalle Valo 		if (il->ucode_type == UCODE_INIT)
351*7ac9a364SKalle Valo 			il->dbgfs_sram_len = il->ucode_init_data.len;
352*7ac9a364SKalle Valo 		else
353*7ac9a364SKalle Valo 			il->dbgfs_sram_len = il->ucode_data.len;
354*7ac9a364SKalle Valo 	}
355*7ac9a364SKalle Valo 	bufsz = 30 + il->dbgfs_sram_len * sizeof(char) * 10;
356*7ac9a364SKalle Valo 	buf = kmalloc(bufsz, GFP_KERNEL);
357*7ac9a364SKalle Valo 	if (!buf)
358*7ac9a364SKalle Valo 		return -ENOMEM;
359*7ac9a364SKalle Valo 	pos +=
360*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
361*7ac9a364SKalle Valo 		      il->dbgfs_sram_len);
362*7ac9a364SKalle Valo 	pos +=
363*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
364*7ac9a364SKalle Valo 		      il->dbgfs_sram_offset);
365*7ac9a364SKalle Valo 	for (i = il->dbgfs_sram_len; i > 0; i -= 4) {
366*7ac9a364SKalle Valo 		val =
367*7ac9a364SKalle Valo 		    il_read_targ_mem(il,
368*7ac9a364SKalle Valo 				     il->dbgfs_sram_offset +
369*7ac9a364SKalle Valo 				     il->dbgfs_sram_len - i);
370*7ac9a364SKalle Valo 		if (i < 4) {
371*7ac9a364SKalle Valo 			switch (i) {
372*7ac9a364SKalle Valo 			case 1:
373*7ac9a364SKalle Valo 				val &= BYTE1_MASK;
374*7ac9a364SKalle Valo 				break;
375*7ac9a364SKalle Valo 			case 2:
376*7ac9a364SKalle Valo 				val &= BYTE2_MASK;
377*7ac9a364SKalle Valo 				break;
378*7ac9a364SKalle Valo 			case 3:
379*7ac9a364SKalle Valo 				val &= BYTE3_MASK;
380*7ac9a364SKalle Valo 				break;
381*7ac9a364SKalle Valo 			}
382*7ac9a364SKalle Valo 		}
383*7ac9a364SKalle Valo 		if (!(i % 16))
384*7ac9a364SKalle Valo 			pos += scnprintf(buf + pos, bufsz - pos, "\n");
385*7ac9a364SKalle Valo 		pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
386*7ac9a364SKalle Valo 	}
387*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
388*7ac9a364SKalle Valo 
389*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
390*7ac9a364SKalle Valo 	kfree(buf);
391*7ac9a364SKalle Valo 	return ret;
392*7ac9a364SKalle Valo }
393*7ac9a364SKalle Valo 
394*7ac9a364SKalle Valo static ssize_t
395*7ac9a364SKalle Valo il_dbgfs_sram_write(struct file *file, const char __user *user_buf,
396*7ac9a364SKalle Valo 		    size_t count, loff_t *ppos)
397*7ac9a364SKalle Valo {
398*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
399*7ac9a364SKalle Valo 	char buf[64];
400*7ac9a364SKalle Valo 	int buf_size;
401*7ac9a364SKalle Valo 	u32 offset, len;
402*7ac9a364SKalle Valo 
403*7ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
404*7ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
405*7ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
406*7ac9a364SKalle Valo 		return -EFAULT;
407*7ac9a364SKalle Valo 
408*7ac9a364SKalle Valo 	if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
409*7ac9a364SKalle Valo 		il->dbgfs_sram_offset = offset;
410*7ac9a364SKalle Valo 		il->dbgfs_sram_len = len;
411*7ac9a364SKalle Valo 	} else {
412*7ac9a364SKalle Valo 		il->dbgfs_sram_offset = 0;
413*7ac9a364SKalle Valo 		il->dbgfs_sram_len = 0;
414*7ac9a364SKalle Valo 	}
415*7ac9a364SKalle Valo 
416*7ac9a364SKalle Valo 	return count;
417*7ac9a364SKalle Valo }
418*7ac9a364SKalle Valo 
419*7ac9a364SKalle Valo static ssize_t
420*7ac9a364SKalle Valo il_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count,
421*7ac9a364SKalle Valo 		       loff_t *ppos)
422*7ac9a364SKalle Valo {
423*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
424*7ac9a364SKalle Valo 	struct il_station_entry *station;
425*7ac9a364SKalle Valo 	int max_sta = il->hw_params.max_stations;
426*7ac9a364SKalle Valo 	char *buf;
427*7ac9a364SKalle Valo 	int i, j, pos = 0;
428*7ac9a364SKalle Valo 	ssize_t ret;
429*7ac9a364SKalle Valo 	/* Add 30 for initial string */
430*7ac9a364SKalle Valo 	const size_t bufsz = 30 + sizeof(char) * 500 * (il->num_stations);
431*7ac9a364SKalle Valo 
432*7ac9a364SKalle Valo 	buf = kmalloc(bufsz, GFP_KERNEL);
433*7ac9a364SKalle Valo 	if (!buf)
434*7ac9a364SKalle Valo 		return -ENOMEM;
435*7ac9a364SKalle Valo 
436*7ac9a364SKalle Valo 	pos +=
437*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
438*7ac9a364SKalle Valo 		      il->num_stations);
439*7ac9a364SKalle Valo 
440*7ac9a364SKalle Valo 	for (i = 0; i < max_sta; i++) {
441*7ac9a364SKalle Valo 		station = &il->stations[i];
442*7ac9a364SKalle Valo 		if (!station->used)
443*7ac9a364SKalle Valo 			continue;
444*7ac9a364SKalle Valo 		pos +=
445*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
446*7ac9a364SKalle Valo 			      "station %d - addr: %pM, flags: %#x\n", i,
447*7ac9a364SKalle Valo 			      station->sta.sta.addr,
448*7ac9a364SKalle Valo 			      station->sta.station_flags_msk);
449*7ac9a364SKalle Valo 		pos +=
450*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
451*7ac9a364SKalle Valo 			      "TID\tseq_num\ttxq_id\tframes\ttfds\t");
452*7ac9a364SKalle Valo 		pos +=
453*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
454*7ac9a364SKalle Valo 			      "start_idx\tbitmap\t\t\trate_n_flags\n");
455*7ac9a364SKalle Valo 
456*7ac9a364SKalle Valo 		for (j = 0; j < MAX_TID_COUNT; j++) {
457*7ac9a364SKalle Valo 			pos +=
458*7ac9a364SKalle Valo 			    scnprintf(buf + pos, bufsz - pos,
459*7ac9a364SKalle Valo 				      "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
460*7ac9a364SKalle Valo 				      j, station->tid[j].seq_number,
461*7ac9a364SKalle Valo 				      station->tid[j].agg.txq_id,
462*7ac9a364SKalle Valo 				      station->tid[j].agg.frame_count,
463*7ac9a364SKalle Valo 				      station->tid[j].tfds_in_queue,
464*7ac9a364SKalle Valo 				      station->tid[j].agg.start_idx,
465*7ac9a364SKalle Valo 				      station->tid[j].agg.bitmap,
466*7ac9a364SKalle Valo 				      station->tid[j].agg.rate_n_flags);
467*7ac9a364SKalle Valo 
468*7ac9a364SKalle Valo 			if (station->tid[j].agg.wait_for_ba)
469*7ac9a364SKalle Valo 				pos +=
470*7ac9a364SKalle Valo 				    scnprintf(buf + pos, bufsz - pos,
471*7ac9a364SKalle Valo 					      " - waitforba");
472*7ac9a364SKalle Valo 			pos += scnprintf(buf + pos, bufsz - pos, "\n");
473*7ac9a364SKalle Valo 		}
474*7ac9a364SKalle Valo 
475*7ac9a364SKalle Valo 		pos += scnprintf(buf + pos, bufsz - pos, "\n");
476*7ac9a364SKalle Valo 	}
477*7ac9a364SKalle Valo 
478*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
479*7ac9a364SKalle Valo 	kfree(buf);
480*7ac9a364SKalle Valo 	return ret;
481*7ac9a364SKalle Valo }
482*7ac9a364SKalle Valo 
483*7ac9a364SKalle Valo static ssize_t
484*7ac9a364SKalle Valo il_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count,
485*7ac9a364SKalle Valo 		  loff_t *ppos)
486*7ac9a364SKalle Valo {
487*7ac9a364SKalle Valo 	ssize_t ret;
488*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
489*7ac9a364SKalle Valo 	int pos = 0, ofs = 0, buf_size = 0;
490*7ac9a364SKalle Valo 	const u8 *ptr;
491*7ac9a364SKalle Valo 	char *buf;
492*7ac9a364SKalle Valo 	u16 eeprom_ver;
493*7ac9a364SKalle Valo 	size_t eeprom_len = il->cfg->eeprom_size;
494*7ac9a364SKalle Valo 	buf_size = 4 * eeprom_len + 256;
495*7ac9a364SKalle Valo 
496*7ac9a364SKalle Valo 	if (eeprom_len % 16) {
497*7ac9a364SKalle Valo 		IL_ERR("NVM size is not multiple of 16.\n");
498*7ac9a364SKalle Valo 		return -ENODATA;
499*7ac9a364SKalle Valo 	}
500*7ac9a364SKalle Valo 
501*7ac9a364SKalle Valo 	ptr = il->eeprom;
502*7ac9a364SKalle Valo 	if (!ptr) {
503*7ac9a364SKalle Valo 		IL_ERR("Invalid EEPROM memory\n");
504*7ac9a364SKalle Valo 		return -ENOMEM;
505*7ac9a364SKalle Valo 	}
506*7ac9a364SKalle Valo 
507*7ac9a364SKalle Valo 	/* 4 characters for byte 0xYY */
508*7ac9a364SKalle Valo 	buf = kzalloc(buf_size, GFP_KERNEL);
509*7ac9a364SKalle Valo 	if (!buf) {
510*7ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
511*7ac9a364SKalle Valo 		return -ENOMEM;
512*7ac9a364SKalle Valo 	}
513*7ac9a364SKalle Valo 	eeprom_ver = il_eeprom_query16(il, EEPROM_VERSION);
514*7ac9a364SKalle Valo 	pos +=
515*7ac9a364SKalle Valo 	    scnprintf(buf + pos, buf_size - pos, "EEPROM " "version: 0x%x\n",
516*7ac9a364SKalle Valo 		      eeprom_ver);
517*7ac9a364SKalle Valo 	for (ofs = 0; ofs < eeprom_len; ofs += 16) {
518*7ac9a364SKalle Valo 		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x %16ph\n",
519*7ac9a364SKalle Valo 				 ofs, ptr + ofs);
520*7ac9a364SKalle Valo 	}
521*7ac9a364SKalle Valo 
522*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
523*7ac9a364SKalle Valo 	kfree(buf);
524*7ac9a364SKalle Valo 	return ret;
525*7ac9a364SKalle Valo }
526*7ac9a364SKalle Valo 
527*7ac9a364SKalle Valo static ssize_t
528*7ac9a364SKalle Valo il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
529*7ac9a364SKalle Valo 		       loff_t *ppos)
530*7ac9a364SKalle Valo {
531*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
532*7ac9a364SKalle Valo 	struct ieee80211_channel *channels = NULL;
533*7ac9a364SKalle Valo 	const struct ieee80211_supported_band *supp_band = NULL;
534*7ac9a364SKalle Valo 	int pos = 0, i, bufsz = PAGE_SIZE;
535*7ac9a364SKalle Valo 	char *buf;
536*7ac9a364SKalle Valo 	ssize_t ret;
537*7ac9a364SKalle Valo 
538*7ac9a364SKalle Valo 	if (!test_bit(S_GEO_CONFIGURED, &il->status))
539*7ac9a364SKalle Valo 		return -EAGAIN;
540*7ac9a364SKalle Valo 
541*7ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
542*7ac9a364SKalle Valo 	if (!buf) {
543*7ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
544*7ac9a364SKalle Valo 		return -ENOMEM;
545*7ac9a364SKalle Valo 	}
546*7ac9a364SKalle Valo 
547*7ac9a364SKalle Valo 	supp_band = il_get_hw_mode(il, IEEE80211_BAND_2GHZ);
548*7ac9a364SKalle Valo 	if (supp_band) {
549*7ac9a364SKalle Valo 		channels = supp_band->channels;
550*7ac9a364SKalle Valo 
551*7ac9a364SKalle Valo 		pos +=
552*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
553*7ac9a364SKalle Valo 			      "Displaying %d channels in 2.4GHz band 802.11bg):\n",
554*7ac9a364SKalle Valo 			      supp_band->n_channels);
555*7ac9a364SKalle Valo 
556*7ac9a364SKalle Valo 		for (i = 0; i < supp_band->n_channels; i++)
557*7ac9a364SKalle Valo 			pos +=
558*7ac9a364SKalle Valo 			    scnprintf(buf + pos, bufsz - pos,
559*7ac9a364SKalle Valo 				      "%d: %ddBm: BSS%s%s, %s.\n",
560*7ac9a364SKalle Valo 				      channels[i].hw_value,
561*7ac9a364SKalle Valo 				      channels[i].max_power,
562*7ac9a364SKalle Valo 				      channels[i].
563*7ac9a364SKalle Valo 				      flags & IEEE80211_CHAN_RADAR ?
564*7ac9a364SKalle Valo 				      " (IEEE 802.11h required)" : "",
565*7ac9a364SKalle Valo 				      ((channels[i].
566*7ac9a364SKalle Valo 					flags & IEEE80211_CHAN_NO_IR) ||
567*7ac9a364SKalle Valo 				       (channels[i].
568*7ac9a364SKalle Valo 					flags & IEEE80211_CHAN_RADAR)) ? "" :
569*7ac9a364SKalle Valo 				      ", IBSS",
570*7ac9a364SKalle Valo 				      channels[i].
571*7ac9a364SKalle Valo 				      flags & IEEE80211_CHAN_NO_IR ?
572*7ac9a364SKalle Valo 				      "passive only" : "active/passive");
573*7ac9a364SKalle Valo 	}
574*7ac9a364SKalle Valo 	supp_band = il_get_hw_mode(il, IEEE80211_BAND_5GHZ);
575*7ac9a364SKalle Valo 	if (supp_band) {
576*7ac9a364SKalle Valo 		channels = supp_band->channels;
577*7ac9a364SKalle Valo 
578*7ac9a364SKalle Valo 		pos +=
579*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
580*7ac9a364SKalle Valo 			      "Displaying %d channels in 5.2GHz band (802.11a)\n",
581*7ac9a364SKalle Valo 			      supp_band->n_channels);
582*7ac9a364SKalle Valo 
583*7ac9a364SKalle Valo 		for (i = 0; i < supp_band->n_channels; i++)
584*7ac9a364SKalle Valo 			pos +=
585*7ac9a364SKalle Valo 			    scnprintf(buf + pos, bufsz - pos,
586*7ac9a364SKalle Valo 				      "%d: %ddBm: BSS%s%s, %s.\n",
587*7ac9a364SKalle Valo 				      channels[i].hw_value,
588*7ac9a364SKalle Valo 				      channels[i].max_power,
589*7ac9a364SKalle Valo 				      channels[i].
590*7ac9a364SKalle Valo 				      flags & IEEE80211_CHAN_RADAR ?
591*7ac9a364SKalle Valo 				      " (IEEE 802.11h required)" : "",
592*7ac9a364SKalle Valo 				      ((channels[i].
593*7ac9a364SKalle Valo 					flags & IEEE80211_CHAN_NO_IR) ||
594*7ac9a364SKalle Valo 				       (channels[i].
595*7ac9a364SKalle Valo 					flags & IEEE80211_CHAN_RADAR)) ? "" :
596*7ac9a364SKalle Valo 				      ", IBSS",
597*7ac9a364SKalle Valo 				      channels[i].
598*7ac9a364SKalle Valo 				      flags & IEEE80211_CHAN_NO_IR ?
599*7ac9a364SKalle Valo 				      "passive only" : "active/passive");
600*7ac9a364SKalle Valo 	}
601*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
602*7ac9a364SKalle Valo 	kfree(buf);
603*7ac9a364SKalle Valo 	return ret;
604*7ac9a364SKalle Valo }
605*7ac9a364SKalle Valo 
606*7ac9a364SKalle Valo static ssize_t
607*7ac9a364SKalle Valo il_dbgfs_status_read(struct file *file, char __user *user_buf, size_t count,
608*7ac9a364SKalle Valo 		     loff_t *ppos)
609*7ac9a364SKalle Valo {
610*7ac9a364SKalle Valo 
611*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
612*7ac9a364SKalle Valo 	char buf[512];
613*7ac9a364SKalle Valo 	int pos = 0;
614*7ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
615*7ac9a364SKalle Valo 
616*7ac9a364SKalle Valo 	pos +=
617*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_HCMD_ACTIVE:\t %d\n",
618*7ac9a364SKalle Valo 		      test_bit(S_HCMD_ACTIVE, &il->status));
619*7ac9a364SKalle Valo 	pos +=
620*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_INT_ENABLED:\t %d\n",
621*7ac9a364SKalle Valo 		      test_bit(S_INT_ENABLED, &il->status));
622*7ac9a364SKalle Valo 	pos +=
623*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_RFKILL:\t %d\n",
624*7ac9a364SKalle Valo 		      test_bit(S_RFKILL, &il->status));
625*7ac9a364SKalle Valo 	pos +=
626*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_CT_KILL:\t\t %d\n",
627*7ac9a364SKalle Valo 		      test_bit(S_CT_KILL, &il->status));
628*7ac9a364SKalle Valo 	pos +=
629*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_INIT:\t\t %d\n",
630*7ac9a364SKalle Valo 		      test_bit(S_INIT, &il->status));
631*7ac9a364SKalle Valo 	pos +=
632*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_ALIVE:\t\t %d\n",
633*7ac9a364SKalle Valo 		      test_bit(S_ALIVE, &il->status));
634*7ac9a364SKalle Valo 	pos +=
635*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_READY:\t\t %d\n",
636*7ac9a364SKalle Valo 		      test_bit(S_READY, &il->status));
637*7ac9a364SKalle Valo 	pos +=
638*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_TEMPERATURE:\t %d\n",
639*7ac9a364SKalle Valo 		      test_bit(S_TEMPERATURE, &il->status));
640*7ac9a364SKalle Valo 	pos +=
641*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_GEO_CONFIGURED:\t %d\n",
642*7ac9a364SKalle Valo 		      test_bit(S_GEO_CONFIGURED, &il->status));
643*7ac9a364SKalle Valo 	pos +=
644*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_EXIT_PENDING:\t %d\n",
645*7ac9a364SKalle Valo 		      test_bit(S_EXIT_PENDING, &il->status));
646*7ac9a364SKalle Valo 	pos +=
647*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_STATS:\t %d\n",
648*7ac9a364SKalle Valo 		      test_bit(S_STATS, &il->status));
649*7ac9a364SKalle Valo 	pos +=
650*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_SCANNING:\t %d\n",
651*7ac9a364SKalle Valo 		      test_bit(S_SCANNING, &il->status));
652*7ac9a364SKalle Valo 	pos +=
653*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_SCAN_ABORTING:\t %d\n",
654*7ac9a364SKalle Valo 		      test_bit(S_SCAN_ABORTING, &il->status));
655*7ac9a364SKalle Valo 	pos +=
656*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_SCAN_HW:\t\t %d\n",
657*7ac9a364SKalle Valo 		      test_bit(S_SCAN_HW, &il->status));
658*7ac9a364SKalle Valo 	pos +=
659*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_POWER_PMI:\t %d\n",
660*7ac9a364SKalle Valo 		      test_bit(S_POWER_PMI, &il->status));
661*7ac9a364SKalle Valo 	pos +=
662*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_FW_ERROR:\t %d\n",
663*7ac9a364SKalle Valo 		      test_bit(S_FW_ERROR, &il->status));
664*7ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
665*7ac9a364SKalle Valo }
666*7ac9a364SKalle Valo 
667*7ac9a364SKalle Valo static ssize_t
668*7ac9a364SKalle Valo il_dbgfs_interrupt_read(struct file *file, char __user *user_buf, size_t count,
669*7ac9a364SKalle Valo 			loff_t *ppos)
670*7ac9a364SKalle Valo {
671*7ac9a364SKalle Valo 
672*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
673*7ac9a364SKalle Valo 	int pos = 0;
674*7ac9a364SKalle Valo 	int cnt = 0;
675*7ac9a364SKalle Valo 	char *buf;
676*7ac9a364SKalle Valo 	int bufsz = 24 * 64;	/* 24 items * 64 char per item */
677*7ac9a364SKalle Valo 	ssize_t ret;
678*7ac9a364SKalle Valo 
679*7ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
680*7ac9a364SKalle Valo 	if (!buf) {
681*7ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
682*7ac9a364SKalle Valo 		return -ENOMEM;
683*7ac9a364SKalle Valo 	}
684*7ac9a364SKalle Valo 
685*7ac9a364SKalle Valo 	pos +=
686*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Interrupt Statistics Report:\n");
687*7ac9a364SKalle Valo 
688*7ac9a364SKalle Valo 	pos +=
689*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
690*7ac9a364SKalle Valo 		      il->isr_stats.hw);
691*7ac9a364SKalle Valo 	pos +=
692*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
693*7ac9a364SKalle Valo 		      il->isr_stats.sw);
694*7ac9a364SKalle Valo 	if (il->isr_stats.sw || il->isr_stats.hw) {
695*7ac9a364SKalle Valo 		pos +=
696*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
697*7ac9a364SKalle Valo 			      "\tLast Restarting Code:  0x%X\n",
698*7ac9a364SKalle Valo 			      il->isr_stats.err_code);
699*7ac9a364SKalle Valo 	}
700*7ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG
701*7ac9a364SKalle Valo 	pos +=
702*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
703*7ac9a364SKalle Valo 		      il->isr_stats.sch);
704*7ac9a364SKalle Valo 	pos +=
705*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
706*7ac9a364SKalle Valo 		      il->isr_stats.alive);
707*7ac9a364SKalle Valo #endif
708*7ac9a364SKalle Valo 	pos +=
709*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
710*7ac9a364SKalle Valo 		      "HW RF KILL switch toggled:\t %u\n",
711*7ac9a364SKalle Valo 		      il->isr_stats.rfkill);
712*7ac9a364SKalle Valo 
713*7ac9a364SKalle Valo 	pos +=
714*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
715*7ac9a364SKalle Valo 		      il->isr_stats.ctkill);
716*7ac9a364SKalle Valo 
717*7ac9a364SKalle Valo 	pos +=
718*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
719*7ac9a364SKalle Valo 		      il->isr_stats.wakeup);
720*7ac9a364SKalle Valo 
721*7ac9a364SKalle Valo 	pos +=
722*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Rx command responses:\t\t %u\n",
723*7ac9a364SKalle Valo 		      il->isr_stats.rx);
724*7ac9a364SKalle Valo 	for (cnt = 0; cnt < IL_CN_MAX; cnt++) {
725*7ac9a364SKalle Valo 		if (il->isr_stats.handlers[cnt] > 0)
726*7ac9a364SKalle Valo 			pos +=
727*7ac9a364SKalle Valo 			    scnprintf(buf + pos, bufsz - pos,
728*7ac9a364SKalle Valo 				      "\tRx handler[%36s]:\t\t %u\n",
729*7ac9a364SKalle Valo 				      il_get_cmd_string(cnt),
730*7ac9a364SKalle Valo 				      il->isr_stats.handlers[cnt]);
731*7ac9a364SKalle Valo 	}
732*7ac9a364SKalle Valo 
733*7ac9a364SKalle Valo 	pos +=
734*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
735*7ac9a364SKalle Valo 		      il->isr_stats.tx);
736*7ac9a364SKalle Valo 
737*7ac9a364SKalle Valo 	pos +=
738*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
739*7ac9a364SKalle Valo 		      il->isr_stats.unhandled);
740*7ac9a364SKalle Valo 
741*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
742*7ac9a364SKalle Valo 	kfree(buf);
743*7ac9a364SKalle Valo 	return ret;
744*7ac9a364SKalle Valo }
745*7ac9a364SKalle Valo 
746*7ac9a364SKalle Valo static ssize_t
747*7ac9a364SKalle Valo il_dbgfs_interrupt_write(struct file *file, const char __user *user_buf,
748*7ac9a364SKalle Valo 			 size_t count, loff_t *ppos)
749*7ac9a364SKalle Valo {
750*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
751*7ac9a364SKalle Valo 	char buf[8];
752*7ac9a364SKalle Valo 	int buf_size;
753*7ac9a364SKalle Valo 	u32 reset_flag;
754*7ac9a364SKalle Valo 
755*7ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
756*7ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
757*7ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
758*7ac9a364SKalle Valo 		return -EFAULT;
759*7ac9a364SKalle Valo 	if (sscanf(buf, "%x", &reset_flag) != 1)
760*7ac9a364SKalle Valo 		return -EFAULT;
761*7ac9a364SKalle Valo 	if (reset_flag == 0)
762*7ac9a364SKalle Valo 		il_clear_isr_stats(il);
763*7ac9a364SKalle Valo 
764*7ac9a364SKalle Valo 	return count;
765*7ac9a364SKalle Valo }
766*7ac9a364SKalle Valo 
767*7ac9a364SKalle Valo static ssize_t
768*7ac9a364SKalle Valo il_dbgfs_qos_read(struct file *file, char __user *user_buf, size_t count,
769*7ac9a364SKalle Valo 		  loff_t *ppos)
770*7ac9a364SKalle Valo {
771*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
772*7ac9a364SKalle Valo 	int pos = 0, i;
773*7ac9a364SKalle Valo 	char buf[256];
774*7ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
775*7ac9a364SKalle Valo 
776*7ac9a364SKalle Valo 	for (i = 0; i < AC_NUM; i++) {
777*7ac9a364SKalle Valo 		pos +=
778*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
779*7ac9a364SKalle Valo 			      "\tcw_min\tcw_max\taifsn\ttxop\n");
780*7ac9a364SKalle Valo 		pos +=
781*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
782*7ac9a364SKalle Valo 			      "AC[%d]\t%u\t%u\t%u\t%u\n", i,
783*7ac9a364SKalle Valo 			      il->qos_data.def_qos_parm.ac[i].cw_min,
784*7ac9a364SKalle Valo 			      il->qos_data.def_qos_parm.ac[i].cw_max,
785*7ac9a364SKalle Valo 			      il->qos_data.def_qos_parm.ac[i].aifsn,
786*7ac9a364SKalle Valo 			      il->qos_data.def_qos_parm.ac[i].edca_txop);
787*7ac9a364SKalle Valo 	}
788*7ac9a364SKalle Valo 
789*7ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
790*7ac9a364SKalle Valo }
791*7ac9a364SKalle Valo 
792*7ac9a364SKalle Valo static ssize_t
793*7ac9a364SKalle Valo il_dbgfs_disable_ht40_write(struct file *file, const char __user *user_buf,
794*7ac9a364SKalle Valo 			    size_t count, loff_t *ppos)
795*7ac9a364SKalle Valo {
796*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
797*7ac9a364SKalle Valo 	char buf[8];
798*7ac9a364SKalle Valo 	int buf_size;
799*7ac9a364SKalle Valo 	int ht40;
800*7ac9a364SKalle Valo 
801*7ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
802*7ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
803*7ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
804*7ac9a364SKalle Valo 		return -EFAULT;
805*7ac9a364SKalle Valo 	if (sscanf(buf, "%d", &ht40) != 1)
806*7ac9a364SKalle Valo 		return -EFAULT;
807*7ac9a364SKalle Valo 	if (!il_is_any_associated(il))
808*7ac9a364SKalle Valo 		il->disable_ht40 = ht40 ? true : false;
809*7ac9a364SKalle Valo 	else {
810*7ac9a364SKalle Valo 		IL_ERR("Sta associated with AP - "
811*7ac9a364SKalle Valo 		       "Change to 40MHz channel support is not allowed\n");
812*7ac9a364SKalle Valo 		return -EINVAL;
813*7ac9a364SKalle Valo 	}
814*7ac9a364SKalle Valo 
815*7ac9a364SKalle Valo 	return count;
816*7ac9a364SKalle Valo }
817*7ac9a364SKalle Valo 
818*7ac9a364SKalle Valo static ssize_t
819*7ac9a364SKalle Valo il_dbgfs_disable_ht40_read(struct file *file, char __user *user_buf,
820*7ac9a364SKalle Valo 			   size_t count, loff_t *ppos)
821*7ac9a364SKalle Valo {
822*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
823*7ac9a364SKalle Valo 	char buf[100];
824*7ac9a364SKalle Valo 	int pos = 0;
825*7ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
826*7ac9a364SKalle Valo 
827*7ac9a364SKalle Valo 	pos +=
828*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "11n 40MHz Mode: %s\n",
829*7ac9a364SKalle Valo 		      il->disable_ht40 ? "Disabled" : "Enabled");
830*7ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
831*7ac9a364SKalle Valo }
832*7ac9a364SKalle Valo 
833*7ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(sram);
834*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(nvm);
835*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(stations);
836*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(channels);
837*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(status);
838*7ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
839*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(qos);
840*7ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
841*7ac9a364SKalle Valo 
842*7ac9a364SKalle Valo static ssize_t
843*7ac9a364SKalle Valo il_dbgfs_tx_queue_read(struct file *file, char __user *user_buf, size_t count,
844*7ac9a364SKalle Valo 		       loff_t *ppos)
845*7ac9a364SKalle Valo {
846*7ac9a364SKalle Valo 
847*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
848*7ac9a364SKalle Valo 	struct il_tx_queue *txq;
849*7ac9a364SKalle Valo 	struct il_queue *q;
850*7ac9a364SKalle Valo 	char *buf;
851*7ac9a364SKalle Valo 	int pos = 0;
852*7ac9a364SKalle Valo 	int cnt;
853*7ac9a364SKalle Valo 	int ret;
854*7ac9a364SKalle Valo 	const size_t bufsz =
855*7ac9a364SKalle Valo 	    sizeof(char) * 64 * il->cfg->num_of_queues;
856*7ac9a364SKalle Valo 
857*7ac9a364SKalle Valo 	if (!il->txq) {
858*7ac9a364SKalle Valo 		IL_ERR("txq not ready\n");
859*7ac9a364SKalle Valo 		return -EAGAIN;
860*7ac9a364SKalle Valo 	}
861*7ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
862*7ac9a364SKalle Valo 	if (!buf)
863*7ac9a364SKalle Valo 		return -ENOMEM;
864*7ac9a364SKalle Valo 
865*7ac9a364SKalle Valo 	for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) {
866*7ac9a364SKalle Valo 		txq = &il->txq[cnt];
867*7ac9a364SKalle Valo 		q = &txq->q;
868*7ac9a364SKalle Valo 		pos +=
869*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
870*7ac9a364SKalle Valo 			      "hwq %.2d: read=%u write=%u stop=%d"
871*7ac9a364SKalle Valo 			      " swq_id=%#.2x (ac %d/hwq %d)\n", cnt,
872*7ac9a364SKalle Valo 			      q->read_ptr, q->write_ptr,
873*7ac9a364SKalle Valo 			      !!test_bit(cnt, il->queue_stopped),
874*7ac9a364SKalle Valo 			      txq->swq_id, txq->swq_id & 3,
875*7ac9a364SKalle Valo 			      (txq->swq_id >> 2) & 0x1f);
876*7ac9a364SKalle Valo 		if (cnt >= 4)
877*7ac9a364SKalle Valo 			continue;
878*7ac9a364SKalle Valo 		/* for the ACs, display the stop count too */
879*7ac9a364SKalle Valo 		pos +=
880*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
881*7ac9a364SKalle Valo 			      "        stop-count: %d\n",
882*7ac9a364SKalle Valo 			      atomic_read(&il->queue_stop_count[cnt]));
883*7ac9a364SKalle Valo 	}
884*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
885*7ac9a364SKalle Valo 	kfree(buf);
886*7ac9a364SKalle Valo 	return ret;
887*7ac9a364SKalle Valo }
888*7ac9a364SKalle Valo 
889*7ac9a364SKalle Valo static ssize_t
890*7ac9a364SKalle Valo il_dbgfs_rx_queue_read(struct file *file, char __user *user_buf, size_t count,
891*7ac9a364SKalle Valo 		       loff_t *ppos)
892*7ac9a364SKalle Valo {
893*7ac9a364SKalle Valo 
894*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
895*7ac9a364SKalle Valo 	struct il_rx_queue *rxq = &il->rxq;
896*7ac9a364SKalle Valo 	char buf[256];
897*7ac9a364SKalle Valo 	int pos = 0;
898*7ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
899*7ac9a364SKalle Valo 
900*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", rxq->read);
901*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", rxq->write);
902*7ac9a364SKalle Valo 	pos +=
903*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
904*7ac9a364SKalle Valo 		      rxq->free_count);
905*7ac9a364SKalle Valo 	if (rxq->rb_stts) {
906*7ac9a364SKalle Valo 		pos +=
907*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
908*7ac9a364SKalle Valo 			      le16_to_cpu(rxq->rb_stts->
909*7ac9a364SKalle Valo 					  closed_rb_num) & 0x0FFF);
910*7ac9a364SKalle Valo 	} else {
911*7ac9a364SKalle Valo 		pos +=
912*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
913*7ac9a364SKalle Valo 			      "closed_rb_num: Not Allocated\n");
914*7ac9a364SKalle Valo 	}
915*7ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
916*7ac9a364SKalle Valo }
917*7ac9a364SKalle Valo 
918*7ac9a364SKalle Valo static ssize_t
919*7ac9a364SKalle Valo il_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf,
920*7ac9a364SKalle Valo 			     size_t count, loff_t *ppos)
921*7ac9a364SKalle Valo {
922*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
923*7ac9a364SKalle Valo 
924*7ac9a364SKalle Valo 	return il->debugfs_ops->rx_stats_read(file, user_buf, count, ppos);
925*7ac9a364SKalle Valo }
926*7ac9a364SKalle Valo 
927*7ac9a364SKalle Valo static ssize_t
928*7ac9a364SKalle Valo il_dbgfs_ucode_tx_stats_read(struct file *file, char __user *user_buf,
929*7ac9a364SKalle Valo 			     size_t count, loff_t *ppos)
930*7ac9a364SKalle Valo {
931*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
932*7ac9a364SKalle Valo 
933*7ac9a364SKalle Valo 	return il->debugfs_ops->tx_stats_read(file, user_buf, count, ppos);
934*7ac9a364SKalle Valo }
935*7ac9a364SKalle Valo 
936*7ac9a364SKalle Valo static ssize_t
937*7ac9a364SKalle Valo il_dbgfs_ucode_general_stats_read(struct file *file, char __user *user_buf,
938*7ac9a364SKalle Valo 				  size_t count, loff_t *ppos)
939*7ac9a364SKalle Valo {
940*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
941*7ac9a364SKalle Valo 
942*7ac9a364SKalle Valo 	return il->debugfs_ops->general_stats_read(file, user_buf, count, ppos);
943*7ac9a364SKalle Valo }
944*7ac9a364SKalle Valo 
945*7ac9a364SKalle Valo static ssize_t
946*7ac9a364SKalle Valo il_dbgfs_sensitivity_read(struct file *file, char __user *user_buf,
947*7ac9a364SKalle Valo 			  size_t count, loff_t *ppos)
948*7ac9a364SKalle Valo {
949*7ac9a364SKalle Valo 
950*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
951*7ac9a364SKalle Valo 	int pos = 0;
952*7ac9a364SKalle Valo 	int cnt = 0;
953*7ac9a364SKalle Valo 	char *buf;
954*7ac9a364SKalle Valo 	int bufsz = sizeof(struct il_sensitivity_data) * 4 + 100;
955*7ac9a364SKalle Valo 	ssize_t ret;
956*7ac9a364SKalle Valo 	struct il_sensitivity_data *data;
957*7ac9a364SKalle Valo 
958*7ac9a364SKalle Valo 	data = &il->sensitivity_data;
959*7ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
960*7ac9a364SKalle Valo 	if (!buf) {
961*7ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
962*7ac9a364SKalle Valo 		return -ENOMEM;
963*7ac9a364SKalle Valo 	}
964*7ac9a364SKalle Valo 
965*7ac9a364SKalle Valo 	pos +=
966*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
967*7ac9a364SKalle Valo 		      data->auto_corr_ofdm);
968*7ac9a364SKalle Valo 	pos +=
969*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_mrc:\t\t %u\n",
970*7ac9a364SKalle Valo 		      data->auto_corr_ofdm_mrc);
971*7ac9a364SKalle Valo 	pos +=
972*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
973*7ac9a364SKalle Valo 		      data->auto_corr_ofdm_x1);
974*7ac9a364SKalle Valo 	pos +=
975*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_mrc_x1:\t\t %u\n",
976*7ac9a364SKalle Valo 		      data->auto_corr_ofdm_mrc_x1);
977*7ac9a364SKalle Valo 	pos +=
978*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
979*7ac9a364SKalle Valo 		      data->auto_corr_cck);
980*7ac9a364SKalle Valo 	pos +=
981*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
982*7ac9a364SKalle Valo 		      data->auto_corr_cck_mrc);
983*7ac9a364SKalle Valo 	pos +=
984*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
985*7ac9a364SKalle Valo 		      "last_bad_plcp_cnt_ofdm:\t\t %u\n",
986*7ac9a364SKalle Valo 		      data->last_bad_plcp_cnt_ofdm);
987*7ac9a364SKalle Valo 	pos +=
988*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
989*7ac9a364SKalle Valo 		      data->last_fa_cnt_ofdm);
990*7ac9a364SKalle Valo 	pos +=
991*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "last_bad_plcp_cnt_cck:\t\t %u\n",
992*7ac9a364SKalle Valo 		      data->last_bad_plcp_cnt_cck);
993*7ac9a364SKalle Valo 	pos +=
994*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
995*7ac9a364SKalle Valo 		      data->last_fa_cnt_cck);
996*7ac9a364SKalle Valo 	pos +=
997*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
998*7ac9a364SKalle Valo 		      data->nrg_curr_state);
999*7ac9a364SKalle Valo 	pos +=
1000*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
1001*7ac9a364SKalle Valo 		      data->nrg_prev_state);
1002*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
1003*7ac9a364SKalle Valo 	for (cnt = 0; cnt < 10; cnt++) {
1004*7ac9a364SKalle Valo 		pos +=
1005*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, " %u",
1006*7ac9a364SKalle Valo 			      data->nrg_value[cnt]);
1007*7ac9a364SKalle Valo 	}
1008*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
1009*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
1010*7ac9a364SKalle Valo 	for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
1011*7ac9a364SKalle Valo 		pos +=
1012*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, " %u",
1013*7ac9a364SKalle Valo 			      data->nrg_silence_rssi[cnt]);
1014*7ac9a364SKalle Valo 	}
1015*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
1016*7ac9a364SKalle Valo 	pos +=
1017*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
1018*7ac9a364SKalle Valo 		      data->nrg_silence_ref);
1019*7ac9a364SKalle Valo 	pos +=
1020*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
1021*7ac9a364SKalle Valo 		      data->nrg_energy_idx);
1022*7ac9a364SKalle Valo 	pos +=
1023*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
1024*7ac9a364SKalle Valo 		      data->nrg_silence_idx);
1025*7ac9a364SKalle Valo 	pos +=
1026*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
1027*7ac9a364SKalle Valo 		      data->nrg_th_cck);
1028*7ac9a364SKalle Valo 	pos +=
1029*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
1030*7ac9a364SKalle Valo 		      "nrg_auto_corr_silence_diff:\t %u\n",
1031*7ac9a364SKalle Valo 		      data->nrg_auto_corr_silence_diff);
1032*7ac9a364SKalle Valo 	pos +=
1033*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
1034*7ac9a364SKalle Valo 		      data->num_in_cck_no_fa);
1035*7ac9a364SKalle Valo 	pos +=
1036*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
1037*7ac9a364SKalle Valo 		      data->nrg_th_ofdm);
1038*7ac9a364SKalle Valo 
1039*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1040*7ac9a364SKalle Valo 	kfree(buf);
1041*7ac9a364SKalle Valo 	return ret;
1042*7ac9a364SKalle Valo }
1043*7ac9a364SKalle Valo 
1044*7ac9a364SKalle Valo static ssize_t
1045*7ac9a364SKalle Valo il_dbgfs_chain_noise_read(struct file *file, char __user *user_buf,
1046*7ac9a364SKalle Valo 			  size_t count, loff_t *ppos)
1047*7ac9a364SKalle Valo {
1048*7ac9a364SKalle Valo 
1049*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1050*7ac9a364SKalle Valo 	int pos = 0;
1051*7ac9a364SKalle Valo 	int cnt = 0;
1052*7ac9a364SKalle Valo 	char *buf;
1053*7ac9a364SKalle Valo 	int bufsz = sizeof(struct il_chain_noise_data) * 4 + 100;
1054*7ac9a364SKalle Valo 	ssize_t ret;
1055*7ac9a364SKalle Valo 	struct il_chain_noise_data *data;
1056*7ac9a364SKalle Valo 
1057*7ac9a364SKalle Valo 	data = &il->chain_noise_data;
1058*7ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
1059*7ac9a364SKalle Valo 	if (!buf) {
1060*7ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
1061*7ac9a364SKalle Valo 		return -ENOMEM;
1062*7ac9a364SKalle Valo 	}
1063*7ac9a364SKalle Valo 
1064*7ac9a364SKalle Valo 	pos +=
1065*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
1066*7ac9a364SKalle Valo 		      data->active_chains);
1067*7ac9a364SKalle Valo 	pos +=
1068*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
1069*7ac9a364SKalle Valo 		      data->chain_noise_a);
1070*7ac9a364SKalle Valo 	pos +=
1071*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
1072*7ac9a364SKalle Valo 		      data->chain_noise_b);
1073*7ac9a364SKalle Valo 	pos +=
1074*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
1075*7ac9a364SKalle Valo 		      data->chain_noise_c);
1076*7ac9a364SKalle Valo 	pos +=
1077*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
1078*7ac9a364SKalle Valo 		      data->chain_signal_a);
1079*7ac9a364SKalle Valo 	pos +=
1080*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
1081*7ac9a364SKalle Valo 		      data->chain_signal_b);
1082*7ac9a364SKalle Valo 	pos +=
1083*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
1084*7ac9a364SKalle Valo 		      data->chain_signal_c);
1085*7ac9a364SKalle Valo 	pos +=
1086*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
1087*7ac9a364SKalle Valo 		      data->beacon_count);
1088*7ac9a364SKalle Valo 
1089*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
1090*7ac9a364SKalle Valo 	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
1091*7ac9a364SKalle Valo 		pos +=
1092*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, " %u",
1093*7ac9a364SKalle Valo 			      data->disconn_array[cnt]);
1094*7ac9a364SKalle Valo 	}
1095*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
1096*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
1097*7ac9a364SKalle Valo 	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
1098*7ac9a364SKalle Valo 		pos +=
1099*7ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, " %u",
1100*7ac9a364SKalle Valo 			      data->delta_gain_code[cnt]);
1101*7ac9a364SKalle Valo 	}
1102*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
1103*7ac9a364SKalle Valo 	pos +=
1104*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
1105*7ac9a364SKalle Valo 		      data->radio_write);
1106*7ac9a364SKalle Valo 	pos +=
1107*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
1108*7ac9a364SKalle Valo 		      data->state);
1109*7ac9a364SKalle Valo 
1110*7ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1111*7ac9a364SKalle Valo 	kfree(buf);
1112*7ac9a364SKalle Valo 	return ret;
1113*7ac9a364SKalle Valo }
1114*7ac9a364SKalle Valo 
1115*7ac9a364SKalle Valo static ssize_t
1116*7ac9a364SKalle Valo il_dbgfs_power_save_status_read(struct file *file, char __user *user_buf,
1117*7ac9a364SKalle Valo 				size_t count, loff_t *ppos)
1118*7ac9a364SKalle Valo {
1119*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1120*7ac9a364SKalle Valo 	char buf[60];
1121*7ac9a364SKalle Valo 	int pos = 0;
1122*7ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
1123*7ac9a364SKalle Valo 	u32 pwrsave_status;
1124*7ac9a364SKalle Valo 
1125*7ac9a364SKalle Valo 	pwrsave_status =
1126*7ac9a364SKalle Valo 	    _il_rd(il, CSR_GP_CNTRL) & CSR_GP_REG_POWER_SAVE_STATUS_MSK;
1127*7ac9a364SKalle Valo 
1128*7ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
1129*7ac9a364SKalle Valo 	pos +=
1130*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "%s\n",
1131*7ac9a364SKalle Valo 		      (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
1132*7ac9a364SKalle Valo 		      (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
1133*7ac9a364SKalle Valo 		      (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
1134*7ac9a364SKalle Valo 		      "error");
1135*7ac9a364SKalle Valo 
1136*7ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1137*7ac9a364SKalle Valo }
1138*7ac9a364SKalle Valo 
1139*7ac9a364SKalle Valo static ssize_t
1140*7ac9a364SKalle Valo il_dbgfs_clear_ucode_stats_write(struct file *file,
1141*7ac9a364SKalle Valo 				 const char __user *user_buf, size_t count,
1142*7ac9a364SKalle Valo 				 loff_t *ppos)
1143*7ac9a364SKalle Valo {
1144*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1145*7ac9a364SKalle Valo 	char buf[8];
1146*7ac9a364SKalle Valo 	int buf_size;
1147*7ac9a364SKalle Valo 	int clear;
1148*7ac9a364SKalle Valo 
1149*7ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
1150*7ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
1151*7ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
1152*7ac9a364SKalle Valo 		return -EFAULT;
1153*7ac9a364SKalle Valo 	if (sscanf(buf, "%d", &clear) != 1)
1154*7ac9a364SKalle Valo 		return -EFAULT;
1155*7ac9a364SKalle Valo 
1156*7ac9a364SKalle Valo 	/* make request to uCode to retrieve stats information */
1157*7ac9a364SKalle Valo 	mutex_lock(&il->mutex);
1158*7ac9a364SKalle Valo 	il_send_stats_request(il, CMD_SYNC, true);
1159*7ac9a364SKalle Valo 	mutex_unlock(&il->mutex);
1160*7ac9a364SKalle Valo 
1161*7ac9a364SKalle Valo 	return count;
1162*7ac9a364SKalle Valo }
1163*7ac9a364SKalle Valo 
1164*7ac9a364SKalle Valo static ssize_t
1165*7ac9a364SKalle Valo il_dbgfs_rxon_flags_read(struct file *file, char __user *user_buf,
1166*7ac9a364SKalle Valo 			 size_t count, loff_t *ppos)
1167*7ac9a364SKalle Valo {
1168*7ac9a364SKalle Valo 
1169*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1170*7ac9a364SKalle Valo 	int len = 0;
1171*7ac9a364SKalle Valo 	char buf[20];
1172*7ac9a364SKalle Valo 
1173*7ac9a364SKalle Valo 	len = sprintf(buf, "0x%04X\n", le32_to_cpu(il->active.flags));
1174*7ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1175*7ac9a364SKalle Valo }
1176*7ac9a364SKalle Valo 
1177*7ac9a364SKalle Valo static ssize_t
1178*7ac9a364SKalle Valo il_dbgfs_rxon_filter_flags_read(struct file *file, char __user *user_buf,
1179*7ac9a364SKalle Valo 				size_t count, loff_t *ppos)
1180*7ac9a364SKalle Valo {
1181*7ac9a364SKalle Valo 
1182*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1183*7ac9a364SKalle Valo 	int len = 0;
1184*7ac9a364SKalle Valo 	char buf[20];
1185*7ac9a364SKalle Valo 
1186*7ac9a364SKalle Valo 	len =
1187*7ac9a364SKalle Valo 	    sprintf(buf, "0x%04X\n", le32_to_cpu(il->active.filter_flags));
1188*7ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1189*7ac9a364SKalle Valo }
1190*7ac9a364SKalle Valo 
1191*7ac9a364SKalle Valo static ssize_t
1192*7ac9a364SKalle Valo il_dbgfs_fh_reg_read(struct file *file, char __user *user_buf, size_t count,
1193*7ac9a364SKalle Valo 		     loff_t *ppos)
1194*7ac9a364SKalle Valo {
1195*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1196*7ac9a364SKalle Valo 	char *buf;
1197*7ac9a364SKalle Valo 	int pos = 0;
1198*7ac9a364SKalle Valo 	ssize_t ret = -EFAULT;
1199*7ac9a364SKalle Valo 
1200*7ac9a364SKalle Valo 	if (il->ops->dump_fh) {
1201*7ac9a364SKalle Valo 		ret = pos = il->ops->dump_fh(il, &buf, true);
1202*7ac9a364SKalle Valo 		if (buf) {
1203*7ac9a364SKalle Valo 			ret =
1204*7ac9a364SKalle Valo 			    simple_read_from_buffer(user_buf, count, ppos, buf,
1205*7ac9a364SKalle Valo 						    pos);
1206*7ac9a364SKalle Valo 			kfree(buf);
1207*7ac9a364SKalle Valo 		}
1208*7ac9a364SKalle Valo 	}
1209*7ac9a364SKalle Valo 
1210*7ac9a364SKalle Valo 	return ret;
1211*7ac9a364SKalle Valo }
1212*7ac9a364SKalle Valo 
1213*7ac9a364SKalle Valo static ssize_t
1214*7ac9a364SKalle Valo il_dbgfs_missed_beacon_read(struct file *file, char __user *user_buf,
1215*7ac9a364SKalle Valo 			    size_t count, loff_t *ppos)
1216*7ac9a364SKalle Valo {
1217*7ac9a364SKalle Valo 
1218*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1219*7ac9a364SKalle Valo 	int pos = 0;
1220*7ac9a364SKalle Valo 	char buf[12];
1221*7ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
1222*7ac9a364SKalle Valo 
1223*7ac9a364SKalle Valo 	pos +=
1224*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "%d\n",
1225*7ac9a364SKalle Valo 		      il->missed_beacon_threshold);
1226*7ac9a364SKalle Valo 
1227*7ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1228*7ac9a364SKalle Valo }
1229*7ac9a364SKalle Valo 
1230*7ac9a364SKalle Valo static ssize_t
1231*7ac9a364SKalle Valo il_dbgfs_missed_beacon_write(struct file *file, const char __user *user_buf,
1232*7ac9a364SKalle Valo 			     size_t count, loff_t *ppos)
1233*7ac9a364SKalle Valo {
1234*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1235*7ac9a364SKalle Valo 	char buf[8];
1236*7ac9a364SKalle Valo 	int buf_size;
1237*7ac9a364SKalle Valo 	int missed;
1238*7ac9a364SKalle Valo 
1239*7ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
1240*7ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
1241*7ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
1242*7ac9a364SKalle Valo 		return -EFAULT;
1243*7ac9a364SKalle Valo 	if (sscanf(buf, "%d", &missed) != 1)
1244*7ac9a364SKalle Valo 		return -EINVAL;
1245*7ac9a364SKalle Valo 
1246*7ac9a364SKalle Valo 	if (missed < IL_MISSED_BEACON_THRESHOLD_MIN ||
1247*7ac9a364SKalle Valo 	    missed > IL_MISSED_BEACON_THRESHOLD_MAX)
1248*7ac9a364SKalle Valo 		il->missed_beacon_threshold = IL_MISSED_BEACON_THRESHOLD_DEF;
1249*7ac9a364SKalle Valo 	else
1250*7ac9a364SKalle Valo 		il->missed_beacon_threshold = missed;
1251*7ac9a364SKalle Valo 
1252*7ac9a364SKalle Valo 	return count;
1253*7ac9a364SKalle Valo }
1254*7ac9a364SKalle Valo 
1255*7ac9a364SKalle Valo static ssize_t
1256*7ac9a364SKalle Valo il_dbgfs_force_reset_read(struct file *file, char __user *user_buf,
1257*7ac9a364SKalle Valo 			  size_t count, loff_t *ppos)
1258*7ac9a364SKalle Valo {
1259*7ac9a364SKalle Valo 
1260*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1261*7ac9a364SKalle Valo 	int pos = 0;
1262*7ac9a364SKalle Valo 	char buf[300];
1263*7ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
1264*7ac9a364SKalle Valo 	struct il_force_reset *force_reset;
1265*7ac9a364SKalle Valo 
1266*7ac9a364SKalle Valo 	force_reset = &il->force_reset;
1267*7ac9a364SKalle Valo 
1268*7ac9a364SKalle Valo 	pos +=
1269*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tnumber of reset request: %d\n",
1270*7ac9a364SKalle Valo 		      force_reset->reset_request_count);
1271*7ac9a364SKalle Valo 	pos +=
1272*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
1273*7ac9a364SKalle Valo 		      "\tnumber of reset request success: %d\n",
1274*7ac9a364SKalle Valo 		      force_reset->reset_success_count);
1275*7ac9a364SKalle Valo 	pos +=
1276*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
1277*7ac9a364SKalle Valo 		      "\tnumber of reset request reject: %d\n",
1278*7ac9a364SKalle Valo 		      force_reset->reset_reject_count);
1279*7ac9a364SKalle Valo 	pos +=
1280*7ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\treset duration: %lu\n",
1281*7ac9a364SKalle Valo 		      force_reset->reset_duration);
1282*7ac9a364SKalle Valo 
1283*7ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1284*7ac9a364SKalle Valo }
1285*7ac9a364SKalle Valo 
1286*7ac9a364SKalle Valo static ssize_t
1287*7ac9a364SKalle Valo il_dbgfs_force_reset_write(struct file *file, const char __user *user_buf,
1288*7ac9a364SKalle Valo 			   size_t count, loff_t *ppos)
1289*7ac9a364SKalle Valo {
1290*7ac9a364SKalle Valo 
1291*7ac9a364SKalle Valo 	int ret;
1292*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1293*7ac9a364SKalle Valo 
1294*7ac9a364SKalle Valo 	ret = il_force_reset(il, true);
1295*7ac9a364SKalle Valo 
1296*7ac9a364SKalle Valo 	return ret ? ret : count;
1297*7ac9a364SKalle Valo }
1298*7ac9a364SKalle Valo 
1299*7ac9a364SKalle Valo static ssize_t
1300*7ac9a364SKalle Valo il_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf,
1301*7ac9a364SKalle Valo 			  size_t count, loff_t *ppos)
1302*7ac9a364SKalle Valo {
1303*7ac9a364SKalle Valo 
1304*7ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
1305*7ac9a364SKalle Valo 	char buf[8];
1306*7ac9a364SKalle Valo 	int buf_size;
1307*7ac9a364SKalle Valo 	int timeout;
1308*7ac9a364SKalle Valo 
1309*7ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
1310*7ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
1311*7ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
1312*7ac9a364SKalle Valo 		return -EFAULT;
1313*7ac9a364SKalle Valo 	if (sscanf(buf, "%d", &timeout) != 1)
1314*7ac9a364SKalle Valo 		return -EINVAL;
1315*7ac9a364SKalle Valo 	if (timeout < 0 || timeout > IL_MAX_WD_TIMEOUT)
1316*7ac9a364SKalle Valo 		timeout = IL_DEF_WD_TIMEOUT;
1317*7ac9a364SKalle Valo 
1318*7ac9a364SKalle Valo 	il->cfg->wd_timeout = timeout;
1319*7ac9a364SKalle Valo 	il_setup_watchdog(il);
1320*7ac9a364SKalle Valo 	return count;
1321*7ac9a364SKalle Valo }
1322*7ac9a364SKalle Valo 
1323*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(rx_stats);
1324*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(tx_stats);
1325*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(rx_queue);
1326*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(tx_queue);
1327*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
1328*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
1329*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(ucode_general_stats);
1330*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(sensitivity);
1331*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(chain_noise);
1332*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(power_save_status);
1333*7ac9a364SKalle Valo DEBUGFS_WRITE_FILE_OPS(clear_ucode_stats);
1334*7ac9a364SKalle Valo DEBUGFS_WRITE_FILE_OPS(clear_traffic_stats);
1335*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(fh_reg);
1336*7ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
1337*7ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
1338*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(rxon_flags);
1339*7ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
1340*7ac9a364SKalle Valo DEBUGFS_WRITE_FILE_OPS(wd_timeout);
1341*7ac9a364SKalle Valo 
1342*7ac9a364SKalle Valo /*
1343*7ac9a364SKalle Valo  * Create the debugfs files and directories
1344*7ac9a364SKalle Valo  *
1345*7ac9a364SKalle Valo  */
1346*7ac9a364SKalle Valo int
1347*7ac9a364SKalle Valo il_dbgfs_register(struct il_priv *il, const char *name)
1348*7ac9a364SKalle Valo {
1349*7ac9a364SKalle Valo 	struct dentry *phyd = il->hw->wiphy->debugfsdir;
1350*7ac9a364SKalle Valo 	struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
1351*7ac9a364SKalle Valo 
1352*7ac9a364SKalle Valo 	dir_drv = debugfs_create_dir(name, phyd);
1353*7ac9a364SKalle Valo 	if (!dir_drv)
1354*7ac9a364SKalle Valo 		return -ENOMEM;
1355*7ac9a364SKalle Valo 
1356*7ac9a364SKalle Valo 	il->debugfs_dir = dir_drv;
1357*7ac9a364SKalle Valo 
1358*7ac9a364SKalle Valo 	dir_data = debugfs_create_dir("data", dir_drv);
1359*7ac9a364SKalle Valo 	if (!dir_data)
1360*7ac9a364SKalle Valo 		goto err;
1361*7ac9a364SKalle Valo 	dir_rf = debugfs_create_dir("rf", dir_drv);
1362*7ac9a364SKalle Valo 	if (!dir_rf)
1363*7ac9a364SKalle Valo 		goto err;
1364*7ac9a364SKalle Valo 	dir_debug = debugfs_create_dir("debug", dir_drv);
1365*7ac9a364SKalle Valo 	if (!dir_debug)
1366*7ac9a364SKalle Valo 		goto err;
1367*7ac9a364SKalle Valo 
1368*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
1369*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
1370*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
1371*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
1372*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
1373*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
1374*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
1375*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
1376*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(rx_stats, dir_debug, S_IRUSR);
1377*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(tx_stats, dir_debug, S_IRUSR);
1378*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
1379*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
1380*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
1381*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(clear_ucode_stats, dir_debug, S_IWUSR);
1382*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(clear_traffic_stats, dir_debug, S_IWUSR);
1383*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
1384*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
1385*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
1386*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
1387*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
1388*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
1389*7ac9a364SKalle Valo 
1390*7ac9a364SKalle Valo 	if (il->cfg->sensitivity_calib_by_driver)
1391*7ac9a364SKalle Valo 		DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
1392*7ac9a364SKalle Valo 	if (il->cfg->chain_noise_calib_by_driver)
1393*7ac9a364SKalle Valo 		DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
1394*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
1395*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
1396*7ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
1397*7ac9a364SKalle Valo 	if (il->cfg->sensitivity_calib_by_driver)
1398*7ac9a364SKalle Valo 		DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
1399*7ac9a364SKalle Valo 				 &il->disable_sens_cal);
1400*7ac9a364SKalle Valo 	if (il->cfg->chain_noise_calib_by_driver)
1401*7ac9a364SKalle Valo 		DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
1402*7ac9a364SKalle Valo 				 &il->disable_chain_noise_cal);
1403*7ac9a364SKalle Valo 	DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, &il->disable_tx_power_cal);
1404*7ac9a364SKalle Valo 	return 0;
1405*7ac9a364SKalle Valo 
1406*7ac9a364SKalle Valo err:
1407*7ac9a364SKalle Valo 	IL_ERR("Can't create the debugfs directory\n");
1408*7ac9a364SKalle Valo 	il_dbgfs_unregister(il);
1409*7ac9a364SKalle Valo 	return -ENOMEM;
1410*7ac9a364SKalle Valo }
1411*7ac9a364SKalle Valo EXPORT_SYMBOL(il_dbgfs_register);
1412*7ac9a364SKalle Valo 
1413*7ac9a364SKalle Valo /**
1414*7ac9a364SKalle Valo  * Remove the debugfs files and directories
1415*7ac9a364SKalle Valo  *
1416*7ac9a364SKalle Valo  */
1417*7ac9a364SKalle Valo void
1418*7ac9a364SKalle Valo il_dbgfs_unregister(struct il_priv *il)
1419*7ac9a364SKalle Valo {
1420*7ac9a364SKalle Valo 	if (!il->debugfs_dir)
1421*7ac9a364SKalle Valo 		return;
1422*7ac9a364SKalle Valo 
1423*7ac9a364SKalle Valo 	debugfs_remove_recursive(il->debugfs_dir);
1424*7ac9a364SKalle Valo 	il->debugfs_dir = NULL;
1425*7ac9a364SKalle Valo }
1426*7ac9a364SKalle Valo EXPORT_SYMBOL(il_dbgfs_unregister);
1427