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