17ac9a364SKalle Valo /******************************************************************************
27ac9a364SKalle Valo  *
37ac9a364SKalle Valo  * GPL LICENSE SUMMARY
47ac9a364SKalle Valo  *
57ac9a364SKalle Valo  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
67ac9a364SKalle Valo  *
77ac9a364SKalle Valo  * This program is free software; you can redistribute it and/or modify
87ac9a364SKalle Valo  * it under the terms of version 2 of the GNU General Public License as
97ac9a364SKalle Valo  * published by the Free Software Foundation.
107ac9a364SKalle Valo  *
117ac9a364SKalle Valo  * This program is distributed in the hope that it will be useful, but
127ac9a364SKalle Valo  * WITHOUT ANY WARRANTY; without even the implied warranty of
137ac9a364SKalle Valo  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147ac9a364SKalle Valo  * General Public License for more details.
157ac9a364SKalle Valo  *
167ac9a364SKalle Valo  * You should have received a copy of the GNU General Public License
177ac9a364SKalle Valo  * along with this program; if not, write to the Free Software
187ac9a364SKalle Valo  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
197ac9a364SKalle Valo  * USA
207ac9a364SKalle Valo  *
217ac9a364SKalle Valo  * The full GNU General Public License is included in this distribution
227ac9a364SKalle Valo  * in the file called LICENSE.GPL.
237ac9a364SKalle Valo  *
247ac9a364SKalle Valo  * Contact Information:
257ac9a364SKalle Valo  *  Intel Linux Wireless <ilw@linux.intel.com>
267ac9a364SKalle Valo  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
277ac9a364SKalle Valo  *****************************************************************************/
287ac9a364SKalle Valo #include <linux/ieee80211.h>
297ac9a364SKalle Valo #include <linux/export.h>
307ac9a364SKalle Valo #include <net/mac80211.h>
317ac9a364SKalle Valo 
327ac9a364SKalle Valo #include "common.h"
337ac9a364SKalle Valo 
347ac9a364SKalle Valo static void
357ac9a364SKalle Valo il_clear_traffic_stats(struct il_priv *il)
367ac9a364SKalle Valo {
377ac9a364SKalle Valo 	memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
387ac9a364SKalle Valo 	memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
397ac9a364SKalle Valo }
407ac9a364SKalle Valo 
417ac9a364SKalle Valo /*
427ac9a364SKalle Valo  * il_update_stats function record all the MGMT, CTRL and DATA pkt for
437ac9a364SKalle Valo  * both TX and Rx . Use debugfs to display the rx/rx_stats
447ac9a364SKalle Valo  */
457ac9a364SKalle Valo void
467ac9a364SKalle Valo il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
477ac9a364SKalle Valo {
487ac9a364SKalle Valo 	struct traffic_stats *stats;
497ac9a364SKalle Valo 
507ac9a364SKalle Valo 	if (is_tx)
517ac9a364SKalle Valo 		stats = &il->tx_stats;
527ac9a364SKalle Valo 	else
537ac9a364SKalle Valo 		stats = &il->rx_stats;
547ac9a364SKalle Valo 
557ac9a364SKalle Valo 	if (ieee80211_is_mgmt(fc)) {
567ac9a364SKalle Valo 		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
577ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
587ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
597ac9a364SKalle Valo 			break;
607ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
617ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
627ac9a364SKalle Valo 			break;
637ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
647ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
657ac9a364SKalle Valo 			break;
667ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
677ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
687ac9a364SKalle Valo 			break;
697ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
707ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_PROBE_REQ]++;
717ac9a364SKalle Valo 			break;
727ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
737ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_PROBE_RESP]++;
747ac9a364SKalle Valo 			break;
757ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_BEACON):
767ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_BEACON]++;
777ac9a364SKalle Valo 			break;
787ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ATIM):
797ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_ATIM]++;
807ac9a364SKalle Valo 			break;
817ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
827ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_DISASSOC]++;
837ac9a364SKalle Valo 			break;
847ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_AUTH):
857ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_AUTH]++;
867ac9a364SKalle Valo 			break;
877ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
887ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_DEAUTH]++;
897ac9a364SKalle Valo 			break;
907ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ACTION):
917ac9a364SKalle Valo 			stats->mgmt[MANAGEMENT_ACTION]++;
927ac9a364SKalle Valo 			break;
937ac9a364SKalle Valo 		}
947ac9a364SKalle Valo 	} else if (ieee80211_is_ctl(fc)) {
957ac9a364SKalle Valo 		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
967ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
977ac9a364SKalle Valo 			stats->ctrl[CONTROL_BACK_REQ]++;
987ac9a364SKalle Valo 			break;
997ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_BACK):
1007ac9a364SKalle Valo 			stats->ctrl[CONTROL_BACK]++;
1017ac9a364SKalle Valo 			break;
1027ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
1037ac9a364SKalle Valo 			stats->ctrl[CONTROL_PSPOLL]++;
1047ac9a364SKalle Valo 			break;
1057ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_RTS):
1067ac9a364SKalle Valo 			stats->ctrl[CONTROL_RTS]++;
1077ac9a364SKalle Valo 			break;
1087ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_CTS):
1097ac9a364SKalle Valo 			stats->ctrl[CONTROL_CTS]++;
1107ac9a364SKalle Valo 			break;
1117ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_ACK):
1127ac9a364SKalle Valo 			stats->ctrl[CONTROL_ACK]++;
1137ac9a364SKalle Valo 			break;
1147ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_CFEND):
1157ac9a364SKalle Valo 			stats->ctrl[CONTROL_CFEND]++;
1167ac9a364SKalle Valo 			break;
1177ac9a364SKalle Valo 		case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
1187ac9a364SKalle Valo 			stats->ctrl[CONTROL_CFENDACK]++;
1197ac9a364SKalle Valo 			break;
1207ac9a364SKalle Valo 		}
1217ac9a364SKalle Valo 	} else {
1227ac9a364SKalle Valo 		/* data */
1237ac9a364SKalle Valo 		stats->data_cnt++;
1247ac9a364SKalle Valo 		stats->data_bytes += len;
1257ac9a364SKalle Valo 	}
1267ac9a364SKalle Valo }
1277ac9a364SKalle Valo EXPORT_SYMBOL(il_update_stats);
1287ac9a364SKalle Valo 
1297ac9a364SKalle Valo /* create and remove of files */
1307ac9a364SKalle Valo #define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
1317ac9a364SKalle Valo 	if (!debugfs_create_file(#name, mode, parent, il,		\
1327ac9a364SKalle Valo 			 &il_dbgfs_##name##_ops))		\
1337ac9a364SKalle Valo 		goto err;						\
1347ac9a364SKalle Valo } while (0)
1357ac9a364SKalle Valo 
1367ac9a364SKalle Valo #define DEBUGFS_ADD_BOOL(name, parent, ptr) do {			\
1377ac9a364SKalle Valo 	struct dentry *__tmp;						\
1387ac9a364SKalle Valo 	__tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,		\
1397ac9a364SKalle Valo 				    parent, ptr);			\
1407ac9a364SKalle Valo 	if (IS_ERR(__tmp) || !__tmp)					\
1417ac9a364SKalle Valo 		goto err;						\
1427ac9a364SKalle Valo } while (0)
1437ac9a364SKalle Valo 
1447ac9a364SKalle Valo #define DEBUGFS_ADD_X32(name, parent, ptr) do {				\
1457ac9a364SKalle Valo 	struct dentry *__tmp;						\
1467ac9a364SKalle Valo 	__tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,		\
1477ac9a364SKalle Valo 				   parent, ptr);			\
1487ac9a364SKalle Valo 	if (IS_ERR(__tmp) || !__tmp)					\
1497ac9a364SKalle Valo 		goto err;						\
1507ac9a364SKalle Valo } while (0)
1517ac9a364SKalle Valo 
1527ac9a364SKalle Valo /* file operation */
1537ac9a364SKalle Valo #define DEBUGFS_READ_FUNC(name)                                         \
1547ac9a364SKalle Valo static ssize_t il_dbgfs_##name##_read(struct file *file,               \
1557ac9a364SKalle Valo 					char __user *user_buf,          \
1567ac9a364SKalle Valo 					size_t count, loff_t *ppos);
1577ac9a364SKalle Valo 
1587ac9a364SKalle Valo #define DEBUGFS_WRITE_FUNC(name)                                        \
1597ac9a364SKalle Valo static ssize_t il_dbgfs_##name##_write(struct file *file,              \
1607ac9a364SKalle Valo 					const char __user *user_buf,    \
1617ac9a364SKalle Valo 					size_t count, loff_t *ppos);
1627ac9a364SKalle Valo 
1637ac9a364SKalle Valo 
1647ac9a364SKalle Valo #define DEBUGFS_READ_FILE_OPS(name)				\
1657ac9a364SKalle Valo 	DEBUGFS_READ_FUNC(name);				\
1667ac9a364SKalle Valo static const struct file_operations il_dbgfs_##name##_ops = {	\
1677ac9a364SKalle Valo 	.read = il_dbgfs_##name##_read,				\
1687ac9a364SKalle Valo 	.open = simple_open,					\
1697ac9a364SKalle Valo 	.llseek = generic_file_llseek,				\
1707ac9a364SKalle Valo };
1717ac9a364SKalle Valo 
1727ac9a364SKalle Valo #define DEBUGFS_WRITE_FILE_OPS(name)				\
1737ac9a364SKalle Valo 	DEBUGFS_WRITE_FUNC(name);				\
1747ac9a364SKalle Valo static const struct file_operations il_dbgfs_##name##_ops = {	\
1757ac9a364SKalle Valo 	.write = il_dbgfs_##name##_write,			\
1767ac9a364SKalle Valo 	.open = simple_open,					\
1777ac9a364SKalle Valo 	.llseek = generic_file_llseek,				\
1787ac9a364SKalle Valo };
1797ac9a364SKalle Valo 
1807ac9a364SKalle Valo #define DEBUGFS_READ_WRITE_FILE_OPS(name)			\
1817ac9a364SKalle Valo 	DEBUGFS_READ_FUNC(name);				\
1827ac9a364SKalle Valo 	DEBUGFS_WRITE_FUNC(name);				\
1837ac9a364SKalle Valo static const struct file_operations il_dbgfs_##name##_ops = {	\
1847ac9a364SKalle Valo 	.write = il_dbgfs_##name##_write,			\
1857ac9a364SKalle Valo 	.read = il_dbgfs_##name##_read,				\
1867ac9a364SKalle Valo 	.open = simple_open,					\
1877ac9a364SKalle Valo 	.llseek = generic_file_llseek,				\
1887ac9a364SKalle Valo };
1897ac9a364SKalle Valo 
1907ac9a364SKalle Valo static const char *
1917ac9a364SKalle Valo il_get_mgmt_string(int cmd)
1927ac9a364SKalle Valo {
1937ac9a364SKalle Valo 	switch (cmd) {
1947ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_ASSOC_REQ);
1957ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_ASSOC_RESP);
1967ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_REASSOC_REQ);
1977ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_REASSOC_RESP);
1987ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_PROBE_REQ);
1997ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_PROBE_RESP);
2007ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_BEACON);
2017ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_ATIM);
2027ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_DISASSOC);
2037ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_AUTH);
2047ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_DEAUTH);
2057ac9a364SKalle Valo 	IL_CMD(MANAGEMENT_ACTION);
2067ac9a364SKalle Valo 	default:
2077ac9a364SKalle Valo 		return "UNKNOWN";
2087ac9a364SKalle Valo 
2097ac9a364SKalle Valo 	}
2107ac9a364SKalle Valo }
2117ac9a364SKalle Valo 
2127ac9a364SKalle Valo static const char *
2137ac9a364SKalle Valo il_get_ctrl_string(int cmd)
2147ac9a364SKalle Valo {
2157ac9a364SKalle Valo 	switch (cmd) {
2167ac9a364SKalle Valo 	IL_CMD(CONTROL_BACK_REQ);
2177ac9a364SKalle Valo 	IL_CMD(CONTROL_BACK);
2187ac9a364SKalle Valo 	IL_CMD(CONTROL_PSPOLL);
2197ac9a364SKalle Valo 	IL_CMD(CONTROL_RTS);
2207ac9a364SKalle Valo 	IL_CMD(CONTROL_CTS);
2217ac9a364SKalle Valo 	IL_CMD(CONTROL_ACK);
2227ac9a364SKalle Valo 	IL_CMD(CONTROL_CFEND);
2237ac9a364SKalle Valo 	IL_CMD(CONTROL_CFENDACK);
2247ac9a364SKalle Valo 	default:
2257ac9a364SKalle Valo 		return "UNKNOWN";
2267ac9a364SKalle Valo 
2277ac9a364SKalle Valo 	}
2287ac9a364SKalle Valo }
2297ac9a364SKalle Valo 
2307ac9a364SKalle Valo static ssize_t
2317ac9a364SKalle Valo il_dbgfs_tx_stats_read(struct file *file, char __user *user_buf, size_t count,
2327ac9a364SKalle Valo 		       loff_t *ppos)
2337ac9a364SKalle Valo {
2347ac9a364SKalle Valo 
2357ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
2367ac9a364SKalle Valo 	char *buf;
2377ac9a364SKalle Valo 	int pos = 0;
2387ac9a364SKalle Valo 
2397ac9a364SKalle Valo 	int cnt;
2407ac9a364SKalle Valo 	ssize_t ret;
2417ac9a364SKalle Valo 	const size_t bufsz =
2427ac9a364SKalle Valo 	    100 + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
2437ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
2447ac9a364SKalle Valo 	if (!buf)
2457ac9a364SKalle Valo 		return -ENOMEM;
2467ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
2477ac9a364SKalle Valo 	for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
2487ac9a364SKalle Valo 		pos +=
2497ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
2507ac9a364SKalle Valo 			      il_get_mgmt_string(cnt), il->tx_stats.mgmt[cnt]);
2517ac9a364SKalle Valo 	}
2527ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
2537ac9a364SKalle Valo 	for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
2547ac9a364SKalle Valo 		pos +=
2557ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
2567ac9a364SKalle Valo 			      il_get_ctrl_string(cnt), il->tx_stats.ctrl[cnt]);
2577ac9a364SKalle Valo 	}
2587ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
2597ac9a364SKalle Valo 	pos +=
2607ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
2617ac9a364SKalle Valo 		      il->tx_stats.data_cnt);
2627ac9a364SKalle Valo 	pos +=
2637ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
2647ac9a364SKalle Valo 		      il->tx_stats.data_bytes);
2657ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
2667ac9a364SKalle Valo 	kfree(buf);
2677ac9a364SKalle Valo 	return ret;
2687ac9a364SKalle Valo }
2697ac9a364SKalle Valo 
2707ac9a364SKalle Valo static ssize_t
2717ac9a364SKalle Valo il_dbgfs_clear_traffic_stats_write(struct file *file,
2727ac9a364SKalle Valo 				   const char __user *user_buf, size_t count,
2737ac9a364SKalle Valo 				   loff_t *ppos)
2747ac9a364SKalle Valo {
2757ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
2767ac9a364SKalle Valo 	u32 clear_flag;
2777ac9a364SKalle Valo 	char buf[8];
2787ac9a364SKalle Valo 	int buf_size;
2797ac9a364SKalle Valo 
2807ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
2817ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
2827ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
2837ac9a364SKalle Valo 		return -EFAULT;
2847ac9a364SKalle Valo 	if (sscanf(buf, "%x", &clear_flag) != 1)
2857ac9a364SKalle Valo 		return -EFAULT;
2867ac9a364SKalle Valo 	il_clear_traffic_stats(il);
2877ac9a364SKalle Valo 
2887ac9a364SKalle Valo 	return count;
2897ac9a364SKalle Valo }
2907ac9a364SKalle Valo 
2917ac9a364SKalle Valo static ssize_t
2927ac9a364SKalle Valo il_dbgfs_rx_stats_read(struct file *file, char __user *user_buf, size_t count,
2937ac9a364SKalle Valo 		       loff_t *ppos)
2947ac9a364SKalle Valo {
2957ac9a364SKalle Valo 
2967ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
2977ac9a364SKalle Valo 	char *buf;
2987ac9a364SKalle Valo 	int pos = 0;
2997ac9a364SKalle Valo 	int cnt;
3007ac9a364SKalle Valo 	ssize_t ret;
3017ac9a364SKalle Valo 	const size_t bufsz =
3027ac9a364SKalle Valo 	    100 + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
3037ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
3047ac9a364SKalle Valo 	if (!buf)
3057ac9a364SKalle Valo 		return -ENOMEM;
3067ac9a364SKalle Valo 
3077ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
3087ac9a364SKalle Valo 	for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
3097ac9a364SKalle Valo 		pos +=
3107ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
3117ac9a364SKalle Valo 			      il_get_mgmt_string(cnt), il->rx_stats.mgmt[cnt]);
3127ac9a364SKalle Valo 	}
3137ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
3147ac9a364SKalle Valo 	for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
3157ac9a364SKalle Valo 		pos +=
3167ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "\t%25s\t\t: %u\n",
3177ac9a364SKalle Valo 			      il_get_ctrl_string(cnt), il->rx_stats.ctrl[cnt]);
3187ac9a364SKalle Valo 	}
3197ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
3207ac9a364SKalle Valo 	pos +=
3217ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
3227ac9a364SKalle Valo 		      il->rx_stats.data_cnt);
3237ac9a364SKalle Valo 	pos +=
3247ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
3257ac9a364SKalle Valo 		      il->rx_stats.data_bytes);
3267ac9a364SKalle Valo 
3277ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
3287ac9a364SKalle Valo 	kfree(buf);
3297ac9a364SKalle Valo 	return ret;
3307ac9a364SKalle Valo }
3317ac9a364SKalle Valo 
3327ac9a364SKalle Valo #define BYTE1_MASK 0x000000ff;
3337ac9a364SKalle Valo #define BYTE2_MASK 0x0000ffff;
3347ac9a364SKalle Valo #define BYTE3_MASK 0x00ffffff;
3357ac9a364SKalle Valo static ssize_t
3367ac9a364SKalle Valo il_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count,
3377ac9a364SKalle Valo 		   loff_t *ppos)
3387ac9a364SKalle Valo {
3397ac9a364SKalle Valo 	u32 val;
3407ac9a364SKalle Valo 	char *buf;
3417ac9a364SKalle Valo 	ssize_t ret;
3427ac9a364SKalle Valo 	int i;
3437ac9a364SKalle Valo 	int pos = 0;
3447ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
3457ac9a364SKalle Valo 	size_t bufsz;
3467ac9a364SKalle Valo 
3477ac9a364SKalle Valo 	/* default is to dump the entire data segment */
3487ac9a364SKalle Valo 	if (!il->dbgfs_sram_offset && !il->dbgfs_sram_len) {
3497ac9a364SKalle Valo 		il->dbgfs_sram_offset = 0x800000;
3507ac9a364SKalle Valo 		if (il->ucode_type == UCODE_INIT)
3517ac9a364SKalle Valo 			il->dbgfs_sram_len = il->ucode_init_data.len;
3527ac9a364SKalle Valo 		else
3537ac9a364SKalle Valo 			il->dbgfs_sram_len = il->ucode_data.len;
3547ac9a364SKalle Valo 	}
3557ac9a364SKalle Valo 	bufsz = 30 + il->dbgfs_sram_len * sizeof(char) * 10;
3567ac9a364SKalle Valo 	buf = kmalloc(bufsz, GFP_KERNEL);
3577ac9a364SKalle Valo 	if (!buf)
3587ac9a364SKalle Valo 		return -ENOMEM;
3597ac9a364SKalle Valo 	pos +=
3607ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
3617ac9a364SKalle Valo 		      il->dbgfs_sram_len);
3627ac9a364SKalle Valo 	pos +=
3637ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
3647ac9a364SKalle Valo 		      il->dbgfs_sram_offset);
3657ac9a364SKalle Valo 	for (i = il->dbgfs_sram_len; i > 0; i -= 4) {
3667ac9a364SKalle Valo 		val =
3677ac9a364SKalle Valo 		    il_read_targ_mem(il,
3687ac9a364SKalle Valo 				     il->dbgfs_sram_offset +
3697ac9a364SKalle Valo 				     il->dbgfs_sram_len - i);
3707ac9a364SKalle Valo 		if (i < 4) {
3717ac9a364SKalle Valo 			switch (i) {
3727ac9a364SKalle Valo 			case 1:
3737ac9a364SKalle Valo 				val &= BYTE1_MASK;
3747ac9a364SKalle Valo 				break;
3757ac9a364SKalle Valo 			case 2:
3767ac9a364SKalle Valo 				val &= BYTE2_MASK;
3777ac9a364SKalle Valo 				break;
3787ac9a364SKalle Valo 			case 3:
3797ac9a364SKalle Valo 				val &= BYTE3_MASK;
3807ac9a364SKalle Valo 				break;
3817ac9a364SKalle Valo 			}
3827ac9a364SKalle Valo 		}
3837ac9a364SKalle Valo 		if (!(i % 16))
3847ac9a364SKalle Valo 			pos += scnprintf(buf + pos, bufsz - pos, "\n");
3857ac9a364SKalle Valo 		pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
3867ac9a364SKalle Valo 	}
3877ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
3887ac9a364SKalle Valo 
3897ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
3907ac9a364SKalle Valo 	kfree(buf);
3917ac9a364SKalle Valo 	return ret;
3927ac9a364SKalle Valo }
3937ac9a364SKalle Valo 
3947ac9a364SKalle Valo static ssize_t
3957ac9a364SKalle Valo il_dbgfs_sram_write(struct file *file, const char __user *user_buf,
3967ac9a364SKalle Valo 		    size_t count, loff_t *ppos)
3977ac9a364SKalle Valo {
3987ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
3997ac9a364SKalle Valo 	char buf[64];
4007ac9a364SKalle Valo 	int buf_size;
4017ac9a364SKalle Valo 	u32 offset, len;
4027ac9a364SKalle Valo 
4037ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
4047ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
4057ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
4067ac9a364SKalle Valo 		return -EFAULT;
4077ac9a364SKalle Valo 
4087ac9a364SKalle Valo 	if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
4097ac9a364SKalle Valo 		il->dbgfs_sram_offset = offset;
4107ac9a364SKalle Valo 		il->dbgfs_sram_len = len;
4117ac9a364SKalle Valo 	} else {
4127ac9a364SKalle Valo 		il->dbgfs_sram_offset = 0;
4137ac9a364SKalle Valo 		il->dbgfs_sram_len = 0;
4147ac9a364SKalle Valo 	}
4157ac9a364SKalle Valo 
4167ac9a364SKalle Valo 	return count;
4177ac9a364SKalle Valo }
4187ac9a364SKalle Valo 
4197ac9a364SKalle Valo static ssize_t
4207ac9a364SKalle Valo il_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count,
4217ac9a364SKalle Valo 		       loff_t *ppos)
4227ac9a364SKalle Valo {
4237ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
4247ac9a364SKalle Valo 	struct il_station_entry *station;
4257ac9a364SKalle Valo 	int max_sta = il->hw_params.max_stations;
4267ac9a364SKalle Valo 	char *buf;
4277ac9a364SKalle Valo 	int i, j, pos = 0;
4287ac9a364SKalle Valo 	ssize_t ret;
4297ac9a364SKalle Valo 	/* Add 30 for initial string */
4307ac9a364SKalle Valo 	const size_t bufsz = 30 + sizeof(char) * 500 * (il->num_stations);
4317ac9a364SKalle Valo 
4327ac9a364SKalle Valo 	buf = kmalloc(bufsz, GFP_KERNEL);
4337ac9a364SKalle Valo 	if (!buf)
4347ac9a364SKalle Valo 		return -ENOMEM;
4357ac9a364SKalle Valo 
4367ac9a364SKalle Valo 	pos +=
4377ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
4387ac9a364SKalle Valo 		      il->num_stations);
4397ac9a364SKalle Valo 
4407ac9a364SKalle Valo 	for (i = 0; i < max_sta; i++) {
4417ac9a364SKalle Valo 		station = &il->stations[i];
4427ac9a364SKalle Valo 		if (!station->used)
4437ac9a364SKalle Valo 			continue;
4447ac9a364SKalle Valo 		pos +=
4457ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
4467ac9a364SKalle Valo 			      "station %d - addr: %pM, flags: %#x\n", i,
4477ac9a364SKalle Valo 			      station->sta.sta.addr,
4487ac9a364SKalle Valo 			      station->sta.station_flags_msk);
4497ac9a364SKalle Valo 		pos +=
4507ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
4517ac9a364SKalle Valo 			      "TID\tseq_num\ttxq_id\tframes\ttfds\t");
4527ac9a364SKalle Valo 		pos +=
4537ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
4547ac9a364SKalle Valo 			      "start_idx\tbitmap\t\t\trate_n_flags\n");
4557ac9a364SKalle Valo 
4567ac9a364SKalle Valo 		for (j = 0; j < MAX_TID_COUNT; j++) {
4577ac9a364SKalle Valo 			pos +=
4587ac9a364SKalle Valo 			    scnprintf(buf + pos, bufsz - pos,
4597ac9a364SKalle Valo 				      "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
4607ac9a364SKalle Valo 				      j, station->tid[j].seq_number,
4617ac9a364SKalle Valo 				      station->tid[j].agg.txq_id,
4627ac9a364SKalle Valo 				      station->tid[j].agg.frame_count,
4637ac9a364SKalle Valo 				      station->tid[j].tfds_in_queue,
4647ac9a364SKalle Valo 				      station->tid[j].agg.start_idx,
4657ac9a364SKalle Valo 				      station->tid[j].agg.bitmap,
4667ac9a364SKalle Valo 				      station->tid[j].agg.rate_n_flags);
4677ac9a364SKalle Valo 
4687ac9a364SKalle Valo 			if (station->tid[j].agg.wait_for_ba)
4697ac9a364SKalle Valo 				pos +=
4707ac9a364SKalle Valo 				    scnprintf(buf + pos, bufsz - pos,
4717ac9a364SKalle Valo 					      " - waitforba");
4727ac9a364SKalle Valo 			pos += scnprintf(buf + pos, bufsz - pos, "\n");
4737ac9a364SKalle Valo 		}
4747ac9a364SKalle Valo 
4757ac9a364SKalle Valo 		pos += scnprintf(buf + pos, bufsz - pos, "\n");
4767ac9a364SKalle Valo 	}
4777ac9a364SKalle Valo 
4787ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
4797ac9a364SKalle Valo 	kfree(buf);
4807ac9a364SKalle Valo 	return ret;
4817ac9a364SKalle Valo }
4827ac9a364SKalle Valo 
4837ac9a364SKalle Valo static ssize_t
4847ac9a364SKalle Valo il_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count,
4857ac9a364SKalle Valo 		  loff_t *ppos)
4867ac9a364SKalle Valo {
4877ac9a364SKalle Valo 	ssize_t ret;
4887ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
4897ac9a364SKalle Valo 	int pos = 0, ofs = 0, buf_size = 0;
4907ac9a364SKalle Valo 	const u8 *ptr;
4917ac9a364SKalle Valo 	char *buf;
4927ac9a364SKalle Valo 	u16 eeprom_ver;
4937ac9a364SKalle Valo 	size_t eeprom_len = il->cfg->eeprom_size;
4947ac9a364SKalle Valo 	buf_size = 4 * eeprom_len + 256;
4957ac9a364SKalle Valo 
4967ac9a364SKalle Valo 	if (eeprom_len % 16) {
4977ac9a364SKalle Valo 		IL_ERR("NVM size is not multiple of 16.\n");
4987ac9a364SKalle Valo 		return -ENODATA;
4997ac9a364SKalle Valo 	}
5007ac9a364SKalle Valo 
5017ac9a364SKalle Valo 	ptr = il->eeprom;
5027ac9a364SKalle Valo 	if (!ptr) {
5037ac9a364SKalle Valo 		IL_ERR("Invalid EEPROM memory\n");
5047ac9a364SKalle Valo 		return -ENOMEM;
5057ac9a364SKalle Valo 	}
5067ac9a364SKalle Valo 
5077ac9a364SKalle Valo 	/* 4 characters for byte 0xYY */
5087ac9a364SKalle Valo 	buf = kzalloc(buf_size, GFP_KERNEL);
5097ac9a364SKalle Valo 	if (!buf) {
5107ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
5117ac9a364SKalle Valo 		return -ENOMEM;
5127ac9a364SKalle Valo 	}
5137ac9a364SKalle Valo 	eeprom_ver = il_eeprom_query16(il, EEPROM_VERSION);
5147ac9a364SKalle Valo 	pos +=
5157ac9a364SKalle Valo 	    scnprintf(buf + pos, buf_size - pos, "EEPROM " "version: 0x%x\n",
5167ac9a364SKalle Valo 		      eeprom_ver);
5177ac9a364SKalle Valo 	for (ofs = 0; ofs < eeprom_len; ofs += 16) {
5187ac9a364SKalle Valo 		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x %16ph\n",
5197ac9a364SKalle Valo 				 ofs, ptr + ofs);
5207ac9a364SKalle Valo 	}
5217ac9a364SKalle Valo 
5227ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
5237ac9a364SKalle Valo 	kfree(buf);
5247ac9a364SKalle Valo 	return ret;
5257ac9a364SKalle Valo }
5267ac9a364SKalle Valo 
5277ac9a364SKalle Valo static ssize_t
5287ac9a364SKalle Valo il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
5297ac9a364SKalle Valo 		       loff_t *ppos)
5307ac9a364SKalle Valo {
5317ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
5327ac9a364SKalle Valo 	struct ieee80211_channel *channels = NULL;
5337ac9a364SKalle Valo 	const struct ieee80211_supported_band *supp_band = NULL;
5347ac9a364SKalle Valo 	int pos = 0, i, bufsz = PAGE_SIZE;
5357ac9a364SKalle Valo 	char *buf;
5367ac9a364SKalle Valo 	ssize_t ret;
5377ac9a364SKalle Valo 
5387ac9a364SKalle Valo 	if (!test_bit(S_GEO_CONFIGURED, &il->status))
5397ac9a364SKalle Valo 		return -EAGAIN;
5407ac9a364SKalle Valo 
5417ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
5427ac9a364SKalle Valo 	if (!buf) {
5437ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
5447ac9a364SKalle Valo 		return -ENOMEM;
5457ac9a364SKalle Valo 	}
5467ac9a364SKalle Valo 
5477ac9a364SKalle Valo 	supp_band = il_get_hw_mode(il, IEEE80211_BAND_2GHZ);
5487ac9a364SKalle Valo 	if (supp_band) {
5497ac9a364SKalle Valo 		channels = supp_band->channels;
5507ac9a364SKalle Valo 
5517ac9a364SKalle Valo 		pos +=
5527ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
5537ac9a364SKalle Valo 			      "Displaying %d channels in 2.4GHz band 802.11bg):\n",
5547ac9a364SKalle Valo 			      supp_band->n_channels);
5557ac9a364SKalle Valo 
5567ac9a364SKalle Valo 		for (i = 0; i < supp_band->n_channels; i++)
5577ac9a364SKalle Valo 			pos +=
5587ac9a364SKalle Valo 			    scnprintf(buf + pos, bufsz - pos,
5597ac9a364SKalle Valo 				      "%d: %ddBm: BSS%s%s, %s.\n",
5607ac9a364SKalle Valo 				      channels[i].hw_value,
5617ac9a364SKalle Valo 				      channels[i].max_power,
5627ac9a364SKalle Valo 				      channels[i].
5637ac9a364SKalle Valo 				      flags & IEEE80211_CHAN_RADAR ?
5647ac9a364SKalle Valo 				      " (IEEE 802.11h required)" : "",
5657ac9a364SKalle Valo 				      ((channels[i].
5667ac9a364SKalle Valo 					flags & IEEE80211_CHAN_NO_IR) ||
5677ac9a364SKalle Valo 				       (channels[i].
5687ac9a364SKalle Valo 					flags & IEEE80211_CHAN_RADAR)) ? "" :
5697ac9a364SKalle Valo 				      ", IBSS",
5707ac9a364SKalle Valo 				      channels[i].
5717ac9a364SKalle Valo 				      flags & IEEE80211_CHAN_NO_IR ?
5727ac9a364SKalle Valo 				      "passive only" : "active/passive");
5737ac9a364SKalle Valo 	}
5747ac9a364SKalle Valo 	supp_band = il_get_hw_mode(il, IEEE80211_BAND_5GHZ);
5757ac9a364SKalle Valo 	if (supp_band) {
5767ac9a364SKalle Valo 		channels = supp_band->channels;
5777ac9a364SKalle Valo 
5787ac9a364SKalle Valo 		pos +=
5797ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
5807ac9a364SKalle Valo 			      "Displaying %d channels in 5.2GHz band (802.11a)\n",
5817ac9a364SKalle Valo 			      supp_band->n_channels);
5827ac9a364SKalle Valo 
5837ac9a364SKalle Valo 		for (i = 0; i < supp_band->n_channels; i++)
5847ac9a364SKalle Valo 			pos +=
5857ac9a364SKalle Valo 			    scnprintf(buf + pos, bufsz - pos,
5867ac9a364SKalle Valo 				      "%d: %ddBm: BSS%s%s, %s.\n",
5877ac9a364SKalle Valo 				      channels[i].hw_value,
5887ac9a364SKalle Valo 				      channels[i].max_power,
5897ac9a364SKalle Valo 				      channels[i].
5907ac9a364SKalle Valo 				      flags & IEEE80211_CHAN_RADAR ?
5917ac9a364SKalle Valo 				      " (IEEE 802.11h required)" : "",
5927ac9a364SKalle Valo 				      ((channels[i].
5937ac9a364SKalle Valo 					flags & IEEE80211_CHAN_NO_IR) ||
5947ac9a364SKalle Valo 				       (channels[i].
5957ac9a364SKalle Valo 					flags & IEEE80211_CHAN_RADAR)) ? "" :
5967ac9a364SKalle Valo 				      ", IBSS",
5977ac9a364SKalle Valo 				      channels[i].
5987ac9a364SKalle Valo 				      flags & IEEE80211_CHAN_NO_IR ?
5997ac9a364SKalle Valo 				      "passive only" : "active/passive");
6007ac9a364SKalle Valo 	}
6017ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
6027ac9a364SKalle Valo 	kfree(buf);
6037ac9a364SKalle Valo 	return ret;
6047ac9a364SKalle Valo }
6057ac9a364SKalle Valo 
6067ac9a364SKalle Valo static ssize_t
6077ac9a364SKalle Valo il_dbgfs_status_read(struct file *file, char __user *user_buf, size_t count,
6087ac9a364SKalle Valo 		     loff_t *ppos)
6097ac9a364SKalle Valo {
6107ac9a364SKalle Valo 
6117ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
6127ac9a364SKalle Valo 	char buf[512];
6137ac9a364SKalle Valo 	int pos = 0;
6147ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
6157ac9a364SKalle Valo 
6167ac9a364SKalle Valo 	pos +=
6177ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_HCMD_ACTIVE:\t %d\n",
6187ac9a364SKalle Valo 		      test_bit(S_HCMD_ACTIVE, &il->status));
6197ac9a364SKalle Valo 	pos +=
6207ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_INT_ENABLED:\t %d\n",
6217ac9a364SKalle Valo 		      test_bit(S_INT_ENABLED, &il->status));
6227ac9a364SKalle Valo 	pos +=
6237ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_RFKILL:\t %d\n",
6247ac9a364SKalle Valo 		      test_bit(S_RFKILL, &il->status));
6257ac9a364SKalle Valo 	pos +=
6267ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_CT_KILL:\t\t %d\n",
6277ac9a364SKalle Valo 		      test_bit(S_CT_KILL, &il->status));
6287ac9a364SKalle Valo 	pos +=
6297ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_INIT:\t\t %d\n",
6307ac9a364SKalle Valo 		      test_bit(S_INIT, &il->status));
6317ac9a364SKalle Valo 	pos +=
6327ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_ALIVE:\t\t %d\n",
6337ac9a364SKalle Valo 		      test_bit(S_ALIVE, &il->status));
6347ac9a364SKalle Valo 	pos +=
6357ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_READY:\t\t %d\n",
6367ac9a364SKalle Valo 		      test_bit(S_READY, &il->status));
6377ac9a364SKalle Valo 	pos +=
6387ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_TEMPERATURE:\t %d\n",
6397ac9a364SKalle Valo 		      test_bit(S_TEMPERATURE, &il->status));
6407ac9a364SKalle Valo 	pos +=
6417ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_GEO_CONFIGURED:\t %d\n",
6427ac9a364SKalle Valo 		      test_bit(S_GEO_CONFIGURED, &il->status));
6437ac9a364SKalle Valo 	pos +=
6447ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_EXIT_PENDING:\t %d\n",
6457ac9a364SKalle Valo 		      test_bit(S_EXIT_PENDING, &il->status));
6467ac9a364SKalle Valo 	pos +=
6477ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_STATS:\t %d\n",
6487ac9a364SKalle Valo 		      test_bit(S_STATS, &il->status));
6497ac9a364SKalle Valo 	pos +=
6507ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_SCANNING:\t %d\n",
6517ac9a364SKalle Valo 		      test_bit(S_SCANNING, &il->status));
6527ac9a364SKalle Valo 	pos +=
6537ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_SCAN_ABORTING:\t %d\n",
6547ac9a364SKalle Valo 		      test_bit(S_SCAN_ABORTING, &il->status));
6557ac9a364SKalle Valo 	pos +=
6567ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_SCAN_HW:\t\t %d\n",
6577ac9a364SKalle Valo 		      test_bit(S_SCAN_HW, &il->status));
6587ac9a364SKalle Valo 	pos +=
6597ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_POWER_PMI:\t %d\n",
6607ac9a364SKalle Valo 		      test_bit(S_POWER_PMI, &il->status));
6617ac9a364SKalle Valo 	pos +=
6627ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "S_FW_ERROR:\t %d\n",
6637ac9a364SKalle Valo 		      test_bit(S_FW_ERROR, &il->status));
6647ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
6657ac9a364SKalle Valo }
6667ac9a364SKalle Valo 
6677ac9a364SKalle Valo static ssize_t
6687ac9a364SKalle Valo il_dbgfs_interrupt_read(struct file *file, char __user *user_buf, size_t count,
6697ac9a364SKalle Valo 			loff_t *ppos)
6707ac9a364SKalle Valo {
6717ac9a364SKalle Valo 
6727ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
6737ac9a364SKalle Valo 	int pos = 0;
6747ac9a364SKalle Valo 	int cnt = 0;
6757ac9a364SKalle Valo 	char *buf;
6767ac9a364SKalle Valo 	int bufsz = 24 * 64;	/* 24 items * 64 char per item */
6777ac9a364SKalle Valo 	ssize_t ret;
6787ac9a364SKalle Valo 
6797ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
6807ac9a364SKalle Valo 	if (!buf) {
6817ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
6827ac9a364SKalle Valo 		return -ENOMEM;
6837ac9a364SKalle Valo 	}
6847ac9a364SKalle Valo 
6857ac9a364SKalle Valo 	pos +=
6867ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Interrupt Statistics Report:\n");
6877ac9a364SKalle Valo 
6887ac9a364SKalle Valo 	pos +=
6897ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
6907ac9a364SKalle Valo 		      il->isr_stats.hw);
6917ac9a364SKalle Valo 	pos +=
6927ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
6937ac9a364SKalle Valo 		      il->isr_stats.sw);
6947ac9a364SKalle Valo 	if (il->isr_stats.sw || il->isr_stats.hw) {
6957ac9a364SKalle Valo 		pos +=
6967ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
6977ac9a364SKalle Valo 			      "\tLast Restarting Code:  0x%X\n",
6987ac9a364SKalle Valo 			      il->isr_stats.err_code);
6997ac9a364SKalle Valo 	}
7007ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG
7017ac9a364SKalle Valo 	pos +=
7027ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
7037ac9a364SKalle Valo 		      il->isr_stats.sch);
7047ac9a364SKalle Valo 	pos +=
7057ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
7067ac9a364SKalle Valo 		      il->isr_stats.alive);
7077ac9a364SKalle Valo #endif
7087ac9a364SKalle Valo 	pos +=
7097ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
7107ac9a364SKalle Valo 		      "HW RF KILL switch toggled:\t %u\n",
7117ac9a364SKalle Valo 		      il->isr_stats.rfkill);
7127ac9a364SKalle Valo 
7137ac9a364SKalle Valo 	pos +=
7147ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
7157ac9a364SKalle Valo 		      il->isr_stats.ctkill);
7167ac9a364SKalle Valo 
7177ac9a364SKalle Valo 	pos +=
7187ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
7197ac9a364SKalle Valo 		      il->isr_stats.wakeup);
7207ac9a364SKalle Valo 
7217ac9a364SKalle Valo 	pos +=
7227ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Rx command responses:\t\t %u\n",
7237ac9a364SKalle Valo 		      il->isr_stats.rx);
7247ac9a364SKalle Valo 	for (cnt = 0; cnt < IL_CN_MAX; cnt++) {
7257ac9a364SKalle Valo 		if (il->isr_stats.handlers[cnt] > 0)
7267ac9a364SKalle Valo 			pos +=
7277ac9a364SKalle Valo 			    scnprintf(buf + pos, bufsz - pos,
7287ac9a364SKalle Valo 				      "\tRx handler[%36s]:\t\t %u\n",
7297ac9a364SKalle Valo 				      il_get_cmd_string(cnt),
7307ac9a364SKalle Valo 				      il->isr_stats.handlers[cnt]);
7317ac9a364SKalle Valo 	}
7327ac9a364SKalle Valo 
7337ac9a364SKalle Valo 	pos +=
7347ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
7357ac9a364SKalle Valo 		      il->isr_stats.tx);
7367ac9a364SKalle Valo 
7377ac9a364SKalle Valo 	pos +=
7387ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
7397ac9a364SKalle Valo 		      il->isr_stats.unhandled);
7407ac9a364SKalle Valo 
7417ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
7427ac9a364SKalle Valo 	kfree(buf);
7437ac9a364SKalle Valo 	return ret;
7447ac9a364SKalle Valo }
7457ac9a364SKalle Valo 
7467ac9a364SKalle Valo static ssize_t
7477ac9a364SKalle Valo il_dbgfs_interrupt_write(struct file *file, const char __user *user_buf,
7487ac9a364SKalle Valo 			 size_t count, loff_t *ppos)
7497ac9a364SKalle Valo {
7507ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
7517ac9a364SKalle Valo 	char buf[8];
7527ac9a364SKalle Valo 	int buf_size;
7537ac9a364SKalle Valo 	u32 reset_flag;
7547ac9a364SKalle Valo 
7557ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
7567ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
7577ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
7587ac9a364SKalle Valo 		return -EFAULT;
7597ac9a364SKalle Valo 	if (sscanf(buf, "%x", &reset_flag) != 1)
7607ac9a364SKalle Valo 		return -EFAULT;
7617ac9a364SKalle Valo 	if (reset_flag == 0)
7627ac9a364SKalle Valo 		il_clear_isr_stats(il);
7637ac9a364SKalle Valo 
7647ac9a364SKalle Valo 	return count;
7657ac9a364SKalle Valo }
7667ac9a364SKalle Valo 
7677ac9a364SKalle Valo static ssize_t
7687ac9a364SKalle Valo il_dbgfs_qos_read(struct file *file, char __user *user_buf, size_t count,
7697ac9a364SKalle Valo 		  loff_t *ppos)
7707ac9a364SKalle Valo {
7717ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
7727ac9a364SKalle Valo 	int pos = 0, i;
7737ac9a364SKalle Valo 	char buf[256];
7747ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
7757ac9a364SKalle Valo 
7767ac9a364SKalle Valo 	for (i = 0; i < AC_NUM; i++) {
7777ac9a364SKalle Valo 		pos +=
7787ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
7797ac9a364SKalle Valo 			      "\tcw_min\tcw_max\taifsn\ttxop\n");
7807ac9a364SKalle Valo 		pos +=
7817ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
7827ac9a364SKalle Valo 			      "AC[%d]\t%u\t%u\t%u\t%u\n", i,
7837ac9a364SKalle Valo 			      il->qos_data.def_qos_parm.ac[i].cw_min,
7847ac9a364SKalle Valo 			      il->qos_data.def_qos_parm.ac[i].cw_max,
7857ac9a364SKalle Valo 			      il->qos_data.def_qos_parm.ac[i].aifsn,
7867ac9a364SKalle Valo 			      il->qos_data.def_qos_parm.ac[i].edca_txop);
7877ac9a364SKalle Valo 	}
7887ac9a364SKalle Valo 
7897ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
7907ac9a364SKalle Valo }
7917ac9a364SKalle Valo 
7927ac9a364SKalle Valo static ssize_t
7937ac9a364SKalle Valo il_dbgfs_disable_ht40_write(struct file *file, const char __user *user_buf,
7947ac9a364SKalle Valo 			    size_t count, loff_t *ppos)
7957ac9a364SKalle Valo {
7967ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
7977ac9a364SKalle Valo 	char buf[8];
7987ac9a364SKalle Valo 	int buf_size;
7997ac9a364SKalle Valo 	int ht40;
8007ac9a364SKalle Valo 
8017ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
8027ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
8037ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
8047ac9a364SKalle Valo 		return -EFAULT;
8057ac9a364SKalle Valo 	if (sscanf(buf, "%d", &ht40) != 1)
8067ac9a364SKalle Valo 		return -EFAULT;
8077ac9a364SKalle Valo 	if (!il_is_any_associated(il))
8087ac9a364SKalle Valo 		il->disable_ht40 = ht40 ? true : false;
8097ac9a364SKalle Valo 	else {
8107ac9a364SKalle Valo 		IL_ERR("Sta associated with AP - "
8117ac9a364SKalle Valo 		       "Change to 40MHz channel support is not allowed\n");
8127ac9a364SKalle Valo 		return -EINVAL;
8137ac9a364SKalle Valo 	}
8147ac9a364SKalle Valo 
8157ac9a364SKalle Valo 	return count;
8167ac9a364SKalle Valo }
8177ac9a364SKalle Valo 
8187ac9a364SKalle Valo static ssize_t
8197ac9a364SKalle Valo il_dbgfs_disable_ht40_read(struct file *file, char __user *user_buf,
8207ac9a364SKalle Valo 			   size_t count, loff_t *ppos)
8217ac9a364SKalle Valo {
8227ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
8237ac9a364SKalle Valo 	char buf[100];
8247ac9a364SKalle Valo 	int pos = 0;
8257ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
8267ac9a364SKalle Valo 
8277ac9a364SKalle Valo 	pos +=
8287ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "11n 40MHz Mode: %s\n",
8297ac9a364SKalle Valo 		      il->disable_ht40 ? "Disabled" : "Enabled");
8307ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
8317ac9a364SKalle Valo }
8327ac9a364SKalle Valo 
8337ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(sram);
8347ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(nvm);
8357ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(stations);
8367ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(channels);
8377ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(status);
8387ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
8397ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(qos);
8407ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
8417ac9a364SKalle Valo 
8427ac9a364SKalle Valo static ssize_t
8437ac9a364SKalle Valo il_dbgfs_tx_queue_read(struct file *file, char __user *user_buf, size_t count,
8447ac9a364SKalle Valo 		       loff_t *ppos)
8457ac9a364SKalle Valo {
8467ac9a364SKalle Valo 
8477ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
8487ac9a364SKalle Valo 	struct il_tx_queue *txq;
8497ac9a364SKalle Valo 	struct il_queue *q;
8507ac9a364SKalle Valo 	char *buf;
8517ac9a364SKalle Valo 	int pos = 0;
8527ac9a364SKalle Valo 	int cnt;
8537ac9a364SKalle Valo 	int ret;
8547ac9a364SKalle Valo 	const size_t bufsz =
8557ac9a364SKalle Valo 	    sizeof(char) * 64 * il->cfg->num_of_queues;
8567ac9a364SKalle Valo 
8577ac9a364SKalle Valo 	if (!il->txq) {
8587ac9a364SKalle Valo 		IL_ERR("txq not ready\n");
8597ac9a364SKalle Valo 		return -EAGAIN;
8607ac9a364SKalle Valo 	}
8617ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
8627ac9a364SKalle Valo 	if (!buf)
8637ac9a364SKalle Valo 		return -ENOMEM;
8647ac9a364SKalle Valo 
8657ac9a364SKalle Valo 	for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) {
8667ac9a364SKalle Valo 		txq = &il->txq[cnt];
8677ac9a364SKalle Valo 		q = &txq->q;
8687ac9a364SKalle Valo 		pos +=
8697ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
8707ac9a364SKalle Valo 			      "hwq %.2d: read=%u write=%u stop=%d"
8717ac9a364SKalle Valo 			      " swq_id=%#.2x (ac %d/hwq %d)\n", cnt,
8727ac9a364SKalle Valo 			      q->read_ptr, q->write_ptr,
8737ac9a364SKalle Valo 			      !!test_bit(cnt, il->queue_stopped),
8747ac9a364SKalle Valo 			      txq->swq_id, txq->swq_id & 3,
8757ac9a364SKalle Valo 			      (txq->swq_id >> 2) & 0x1f);
8767ac9a364SKalle Valo 		if (cnt >= 4)
8777ac9a364SKalle Valo 			continue;
8787ac9a364SKalle Valo 		/* for the ACs, display the stop count too */
8797ac9a364SKalle Valo 		pos +=
8807ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
8817ac9a364SKalle Valo 			      "        stop-count: %d\n",
8827ac9a364SKalle Valo 			      atomic_read(&il->queue_stop_count[cnt]));
8837ac9a364SKalle Valo 	}
8847ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
8857ac9a364SKalle Valo 	kfree(buf);
8867ac9a364SKalle Valo 	return ret;
8877ac9a364SKalle Valo }
8887ac9a364SKalle Valo 
8897ac9a364SKalle Valo static ssize_t
8907ac9a364SKalle Valo il_dbgfs_rx_queue_read(struct file *file, char __user *user_buf, size_t count,
8917ac9a364SKalle Valo 		       loff_t *ppos)
8927ac9a364SKalle Valo {
8937ac9a364SKalle Valo 
8947ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
8957ac9a364SKalle Valo 	struct il_rx_queue *rxq = &il->rxq;
8967ac9a364SKalle Valo 	char buf[256];
8977ac9a364SKalle Valo 	int pos = 0;
8987ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
8997ac9a364SKalle Valo 
9007ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", rxq->read);
9017ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", rxq->write);
9027ac9a364SKalle Valo 	pos +=
9037ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
9047ac9a364SKalle Valo 		      rxq->free_count);
9057ac9a364SKalle Valo 	if (rxq->rb_stts) {
9067ac9a364SKalle Valo 		pos +=
9077ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
9087ac9a364SKalle Valo 			      le16_to_cpu(rxq->rb_stts->
9097ac9a364SKalle Valo 					  closed_rb_num) & 0x0FFF);
9107ac9a364SKalle Valo 	} else {
9117ac9a364SKalle Valo 		pos +=
9127ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos,
9137ac9a364SKalle Valo 			      "closed_rb_num: Not Allocated\n");
9147ac9a364SKalle Valo 	}
9157ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
9167ac9a364SKalle Valo }
9177ac9a364SKalle Valo 
9187ac9a364SKalle Valo static ssize_t
9197ac9a364SKalle Valo il_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf,
9207ac9a364SKalle Valo 			     size_t count, loff_t *ppos)
9217ac9a364SKalle Valo {
9227ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
9237ac9a364SKalle Valo 
9247ac9a364SKalle Valo 	return il->debugfs_ops->rx_stats_read(file, user_buf, count, ppos);
9257ac9a364SKalle Valo }
9267ac9a364SKalle Valo 
9277ac9a364SKalle Valo static ssize_t
9287ac9a364SKalle Valo il_dbgfs_ucode_tx_stats_read(struct file *file, char __user *user_buf,
9297ac9a364SKalle Valo 			     size_t count, loff_t *ppos)
9307ac9a364SKalle Valo {
9317ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
9327ac9a364SKalle Valo 
9337ac9a364SKalle Valo 	return il->debugfs_ops->tx_stats_read(file, user_buf, count, ppos);
9347ac9a364SKalle Valo }
9357ac9a364SKalle Valo 
9367ac9a364SKalle Valo static ssize_t
9377ac9a364SKalle Valo il_dbgfs_ucode_general_stats_read(struct file *file, char __user *user_buf,
9387ac9a364SKalle Valo 				  size_t count, loff_t *ppos)
9397ac9a364SKalle Valo {
9407ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
9417ac9a364SKalle Valo 
9427ac9a364SKalle Valo 	return il->debugfs_ops->general_stats_read(file, user_buf, count, ppos);
9437ac9a364SKalle Valo }
9447ac9a364SKalle Valo 
9457ac9a364SKalle Valo static ssize_t
9467ac9a364SKalle Valo il_dbgfs_sensitivity_read(struct file *file, char __user *user_buf,
9477ac9a364SKalle Valo 			  size_t count, loff_t *ppos)
9487ac9a364SKalle Valo {
9497ac9a364SKalle Valo 
9507ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
9517ac9a364SKalle Valo 	int pos = 0;
9527ac9a364SKalle Valo 	int cnt = 0;
9537ac9a364SKalle Valo 	char *buf;
9547ac9a364SKalle Valo 	int bufsz = sizeof(struct il_sensitivity_data) * 4 + 100;
9557ac9a364SKalle Valo 	ssize_t ret;
9567ac9a364SKalle Valo 	struct il_sensitivity_data *data;
9577ac9a364SKalle Valo 
9587ac9a364SKalle Valo 	data = &il->sensitivity_data;
9597ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
9607ac9a364SKalle Valo 	if (!buf) {
9617ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
9627ac9a364SKalle Valo 		return -ENOMEM;
9637ac9a364SKalle Valo 	}
9647ac9a364SKalle Valo 
9657ac9a364SKalle Valo 	pos +=
9667ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
9677ac9a364SKalle Valo 		      data->auto_corr_ofdm);
9687ac9a364SKalle Valo 	pos +=
9697ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_mrc:\t\t %u\n",
9707ac9a364SKalle Valo 		      data->auto_corr_ofdm_mrc);
9717ac9a364SKalle Valo 	pos +=
9727ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
9737ac9a364SKalle Valo 		      data->auto_corr_ofdm_x1);
9747ac9a364SKalle Valo 	pos +=
9757ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_mrc_x1:\t\t %u\n",
9767ac9a364SKalle Valo 		      data->auto_corr_ofdm_mrc_x1);
9777ac9a364SKalle Valo 	pos +=
9787ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
9797ac9a364SKalle Valo 		      data->auto_corr_cck);
9807ac9a364SKalle Valo 	pos +=
9817ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
9827ac9a364SKalle Valo 		      data->auto_corr_cck_mrc);
9837ac9a364SKalle Valo 	pos +=
9847ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
9857ac9a364SKalle Valo 		      "last_bad_plcp_cnt_ofdm:\t\t %u\n",
9867ac9a364SKalle Valo 		      data->last_bad_plcp_cnt_ofdm);
9877ac9a364SKalle Valo 	pos +=
9887ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
9897ac9a364SKalle Valo 		      data->last_fa_cnt_ofdm);
9907ac9a364SKalle Valo 	pos +=
9917ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "last_bad_plcp_cnt_cck:\t\t %u\n",
9927ac9a364SKalle Valo 		      data->last_bad_plcp_cnt_cck);
9937ac9a364SKalle Valo 	pos +=
9947ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
9957ac9a364SKalle Valo 		      data->last_fa_cnt_cck);
9967ac9a364SKalle Valo 	pos +=
9977ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
9987ac9a364SKalle Valo 		      data->nrg_curr_state);
9997ac9a364SKalle Valo 	pos +=
10007ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
10017ac9a364SKalle Valo 		      data->nrg_prev_state);
10027ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
10037ac9a364SKalle Valo 	for (cnt = 0; cnt < 10; cnt++) {
10047ac9a364SKalle Valo 		pos +=
10057ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, " %u",
10067ac9a364SKalle Valo 			      data->nrg_value[cnt]);
10077ac9a364SKalle Valo 	}
10087ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
10097ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
10107ac9a364SKalle Valo 	for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
10117ac9a364SKalle Valo 		pos +=
10127ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, " %u",
10137ac9a364SKalle Valo 			      data->nrg_silence_rssi[cnt]);
10147ac9a364SKalle Valo 	}
10157ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
10167ac9a364SKalle Valo 	pos +=
10177ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
10187ac9a364SKalle Valo 		      data->nrg_silence_ref);
10197ac9a364SKalle Valo 	pos +=
10207ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
10217ac9a364SKalle Valo 		      data->nrg_energy_idx);
10227ac9a364SKalle Valo 	pos +=
10237ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
10247ac9a364SKalle Valo 		      data->nrg_silence_idx);
10257ac9a364SKalle Valo 	pos +=
10267ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
10277ac9a364SKalle Valo 		      data->nrg_th_cck);
10287ac9a364SKalle Valo 	pos +=
10297ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
10307ac9a364SKalle Valo 		      "nrg_auto_corr_silence_diff:\t %u\n",
10317ac9a364SKalle Valo 		      data->nrg_auto_corr_silence_diff);
10327ac9a364SKalle Valo 	pos +=
10337ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
10347ac9a364SKalle Valo 		      data->num_in_cck_no_fa);
10357ac9a364SKalle Valo 	pos +=
10367ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
10377ac9a364SKalle Valo 		      data->nrg_th_ofdm);
10387ac9a364SKalle Valo 
10397ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
10407ac9a364SKalle Valo 	kfree(buf);
10417ac9a364SKalle Valo 	return ret;
10427ac9a364SKalle Valo }
10437ac9a364SKalle Valo 
10447ac9a364SKalle Valo static ssize_t
10457ac9a364SKalle Valo il_dbgfs_chain_noise_read(struct file *file, char __user *user_buf,
10467ac9a364SKalle Valo 			  size_t count, loff_t *ppos)
10477ac9a364SKalle Valo {
10487ac9a364SKalle Valo 
10497ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
10507ac9a364SKalle Valo 	int pos = 0;
10517ac9a364SKalle Valo 	int cnt = 0;
10527ac9a364SKalle Valo 	char *buf;
10537ac9a364SKalle Valo 	int bufsz = sizeof(struct il_chain_noise_data) * 4 + 100;
10547ac9a364SKalle Valo 	ssize_t ret;
10557ac9a364SKalle Valo 	struct il_chain_noise_data *data;
10567ac9a364SKalle Valo 
10577ac9a364SKalle Valo 	data = &il->chain_noise_data;
10587ac9a364SKalle Valo 	buf = kzalloc(bufsz, GFP_KERNEL);
10597ac9a364SKalle Valo 	if (!buf) {
10607ac9a364SKalle Valo 		IL_ERR("Can not allocate Buffer\n");
10617ac9a364SKalle Valo 		return -ENOMEM;
10627ac9a364SKalle Valo 	}
10637ac9a364SKalle Valo 
10647ac9a364SKalle Valo 	pos +=
10657ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
10667ac9a364SKalle Valo 		      data->active_chains);
10677ac9a364SKalle Valo 	pos +=
10687ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
10697ac9a364SKalle Valo 		      data->chain_noise_a);
10707ac9a364SKalle Valo 	pos +=
10717ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
10727ac9a364SKalle Valo 		      data->chain_noise_b);
10737ac9a364SKalle Valo 	pos +=
10747ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
10757ac9a364SKalle Valo 		      data->chain_noise_c);
10767ac9a364SKalle Valo 	pos +=
10777ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
10787ac9a364SKalle Valo 		      data->chain_signal_a);
10797ac9a364SKalle Valo 	pos +=
10807ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
10817ac9a364SKalle Valo 		      data->chain_signal_b);
10827ac9a364SKalle Valo 	pos +=
10837ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
10847ac9a364SKalle Valo 		      data->chain_signal_c);
10857ac9a364SKalle Valo 	pos +=
10867ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
10877ac9a364SKalle Valo 		      data->beacon_count);
10887ac9a364SKalle Valo 
10897ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
10907ac9a364SKalle Valo 	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
10917ac9a364SKalle Valo 		pos +=
10927ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, " %u",
10937ac9a364SKalle Valo 			      data->disconn_array[cnt]);
10947ac9a364SKalle Valo 	}
10957ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
10967ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
10977ac9a364SKalle Valo 	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
10987ac9a364SKalle Valo 		pos +=
10997ac9a364SKalle Valo 		    scnprintf(buf + pos, bufsz - pos, " %u",
11007ac9a364SKalle Valo 			      data->delta_gain_code[cnt]);
11017ac9a364SKalle Valo 	}
11027ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
11037ac9a364SKalle Valo 	pos +=
11047ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
11057ac9a364SKalle Valo 		      data->radio_write);
11067ac9a364SKalle Valo 	pos +=
11077ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
11087ac9a364SKalle Valo 		      data->state);
11097ac9a364SKalle Valo 
11107ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
11117ac9a364SKalle Valo 	kfree(buf);
11127ac9a364SKalle Valo 	return ret;
11137ac9a364SKalle Valo }
11147ac9a364SKalle Valo 
11157ac9a364SKalle Valo static ssize_t
11167ac9a364SKalle Valo il_dbgfs_power_save_status_read(struct file *file, char __user *user_buf,
11177ac9a364SKalle Valo 				size_t count, loff_t *ppos)
11187ac9a364SKalle Valo {
11197ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
11207ac9a364SKalle Valo 	char buf[60];
11217ac9a364SKalle Valo 	int pos = 0;
11227ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
11237ac9a364SKalle Valo 	u32 pwrsave_status;
11247ac9a364SKalle Valo 
11257ac9a364SKalle Valo 	pwrsave_status =
11267ac9a364SKalle Valo 	    _il_rd(il, CSR_GP_CNTRL) & CSR_GP_REG_POWER_SAVE_STATUS_MSK;
11277ac9a364SKalle Valo 
11287ac9a364SKalle Valo 	pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
11297ac9a364SKalle Valo 	pos +=
11307ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "%s\n",
11317ac9a364SKalle Valo 		      (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
11327ac9a364SKalle Valo 		      (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
11337ac9a364SKalle Valo 		      (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
11347ac9a364SKalle Valo 		      "error");
11357ac9a364SKalle Valo 
11367ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
11377ac9a364SKalle Valo }
11387ac9a364SKalle Valo 
11397ac9a364SKalle Valo static ssize_t
11407ac9a364SKalle Valo il_dbgfs_clear_ucode_stats_write(struct file *file,
11417ac9a364SKalle Valo 				 const char __user *user_buf, size_t count,
11427ac9a364SKalle Valo 				 loff_t *ppos)
11437ac9a364SKalle Valo {
11447ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
11457ac9a364SKalle Valo 	char buf[8];
11467ac9a364SKalle Valo 	int buf_size;
11477ac9a364SKalle Valo 	int clear;
11487ac9a364SKalle Valo 
11497ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
11507ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
11517ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
11527ac9a364SKalle Valo 		return -EFAULT;
11537ac9a364SKalle Valo 	if (sscanf(buf, "%d", &clear) != 1)
11547ac9a364SKalle Valo 		return -EFAULT;
11557ac9a364SKalle Valo 
11567ac9a364SKalle Valo 	/* make request to uCode to retrieve stats information */
11577ac9a364SKalle Valo 	mutex_lock(&il->mutex);
11587ac9a364SKalle Valo 	il_send_stats_request(il, CMD_SYNC, true);
11597ac9a364SKalle Valo 	mutex_unlock(&il->mutex);
11607ac9a364SKalle Valo 
11617ac9a364SKalle Valo 	return count;
11627ac9a364SKalle Valo }
11637ac9a364SKalle Valo 
11647ac9a364SKalle Valo static ssize_t
11657ac9a364SKalle Valo il_dbgfs_rxon_flags_read(struct file *file, char __user *user_buf,
11667ac9a364SKalle Valo 			 size_t count, loff_t *ppos)
11677ac9a364SKalle Valo {
11687ac9a364SKalle Valo 
11697ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
11707ac9a364SKalle Valo 	int len = 0;
11717ac9a364SKalle Valo 	char buf[20];
11727ac9a364SKalle Valo 
11737ac9a364SKalle Valo 	len = sprintf(buf, "0x%04X\n", le32_to_cpu(il->active.flags));
11747ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
11757ac9a364SKalle Valo }
11767ac9a364SKalle Valo 
11777ac9a364SKalle Valo static ssize_t
11787ac9a364SKalle Valo il_dbgfs_rxon_filter_flags_read(struct file *file, char __user *user_buf,
11797ac9a364SKalle Valo 				size_t count, loff_t *ppos)
11807ac9a364SKalle Valo {
11817ac9a364SKalle Valo 
11827ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
11837ac9a364SKalle Valo 	int len = 0;
11847ac9a364SKalle Valo 	char buf[20];
11857ac9a364SKalle Valo 
11867ac9a364SKalle Valo 	len =
11877ac9a364SKalle Valo 	    sprintf(buf, "0x%04X\n", le32_to_cpu(il->active.filter_flags));
11887ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
11897ac9a364SKalle Valo }
11907ac9a364SKalle Valo 
11917ac9a364SKalle Valo static ssize_t
11927ac9a364SKalle Valo il_dbgfs_fh_reg_read(struct file *file, char __user *user_buf, size_t count,
11937ac9a364SKalle Valo 		     loff_t *ppos)
11947ac9a364SKalle Valo {
11957ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
11967ac9a364SKalle Valo 	char *buf;
11977ac9a364SKalle Valo 	int pos = 0;
11987ac9a364SKalle Valo 	ssize_t ret = -EFAULT;
11997ac9a364SKalle Valo 
12007ac9a364SKalle Valo 	if (il->ops->dump_fh) {
12017ac9a364SKalle Valo 		ret = pos = il->ops->dump_fh(il, &buf, true);
12027ac9a364SKalle Valo 		if (buf) {
12037ac9a364SKalle Valo 			ret =
12047ac9a364SKalle Valo 			    simple_read_from_buffer(user_buf, count, ppos, buf,
12057ac9a364SKalle Valo 						    pos);
12067ac9a364SKalle Valo 			kfree(buf);
12077ac9a364SKalle Valo 		}
12087ac9a364SKalle Valo 	}
12097ac9a364SKalle Valo 
12107ac9a364SKalle Valo 	return ret;
12117ac9a364SKalle Valo }
12127ac9a364SKalle Valo 
12137ac9a364SKalle Valo static ssize_t
12147ac9a364SKalle Valo il_dbgfs_missed_beacon_read(struct file *file, char __user *user_buf,
12157ac9a364SKalle Valo 			    size_t count, loff_t *ppos)
12167ac9a364SKalle Valo {
12177ac9a364SKalle Valo 
12187ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
12197ac9a364SKalle Valo 	int pos = 0;
12207ac9a364SKalle Valo 	char buf[12];
12217ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
12227ac9a364SKalle Valo 
12237ac9a364SKalle Valo 	pos +=
12247ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "%d\n",
12257ac9a364SKalle Valo 		      il->missed_beacon_threshold);
12267ac9a364SKalle Valo 
12277ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
12287ac9a364SKalle Valo }
12297ac9a364SKalle Valo 
12307ac9a364SKalle Valo static ssize_t
12317ac9a364SKalle Valo il_dbgfs_missed_beacon_write(struct file *file, const char __user *user_buf,
12327ac9a364SKalle Valo 			     size_t count, loff_t *ppos)
12337ac9a364SKalle Valo {
12347ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
12357ac9a364SKalle Valo 	char buf[8];
12367ac9a364SKalle Valo 	int buf_size;
12377ac9a364SKalle Valo 	int missed;
12387ac9a364SKalle Valo 
12397ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
12407ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
12417ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
12427ac9a364SKalle Valo 		return -EFAULT;
12437ac9a364SKalle Valo 	if (sscanf(buf, "%d", &missed) != 1)
12447ac9a364SKalle Valo 		return -EINVAL;
12457ac9a364SKalle Valo 
12467ac9a364SKalle Valo 	if (missed < IL_MISSED_BEACON_THRESHOLD_MIN ||
12477ac9a364SKalle Valo 	    missed > IL_MISSED_BEACON_THRESHOLD_MAX)
12487ac9a364SKalle Valo 		il->missed_beacon_threshold = IL_MISSED_BEACON_THRESHOLD_DEF;
12497ac9a364SKalle Valo 	else
12507ac9a364SKalle Valo 		il->missed_beacon_threshold = missed;
12517ac9a364SKalle Valo 
12527ac9a364SKalle Valo 	return count;
12537ac9a364SKalle Valo }
12547ac9a364SKalle Valo 
12557ac9a364SKalle Valo static ssize_t
12567ac9a364SKalle Valo il_dbgfs_force_reset_read(struct file *file, char __user *user_buf,
12577ac9a364SKalle Valo 			  size_t count, loff_t *ppos)
12587ac9a364SKalle Valo {
12597ac9a364SKalle Valo 
12607ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
12617ac9a364SKalle Valo 	int pos = 0;
12627ac9a364SKalle Valo 	char buf[300];
12637ac9a364SKalle Valo 	const size_t bufsz = sizeof(buf);
12647ac9a364SKalle Valo 	struct il_force_reset *force_reset;
12657ac9a364SKalle Valo 
12667ac9a364SKalle Valo 	force_reset = &il->force_reset;
12677ac9a364SKalle Valo 
12687ac9a364SKalle Valo 	pos +=
12697ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\tnumber of reset request: %d\n",
12707ac9a364SKalle Valo 		      force_reset->reset_request_count);
12717ac9a364SKalle Valo 	pos +=
12727ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
12737ac9a364SKalle Valo 		      "\tnumber of reset request success: %d\n",
12747ac9a364SKalle Valo 		      force_reset->reset_success_count);
12757ac9a364SKalle Valo 	pos +=
12767ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos,
12777ac9a364SKalle Valo 		      "\tnumber of reset request reject: %d\n",
12787ac9a364SKalle Valo 		      force_reset->reset_reject_count);
12797ac9a364SKalle Valo 	pos +=
12807ac9a364SKalle Valo 	    scnprintf(buf + pos, bufsz - pos, "\treset duration: %lu\n",
12817ac9a364SKalle Valo 		      force_reset->reset_duration);
12827ac9a364SKalle Valo 
12837ac9a364SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
12847ac9a364SKalle Valo }
12857ac9a364SKalle Valo 
12867ac9a364SKalle Valo static ssize_t
12877ac9a364SKalle Valo il_dbgfs_force_reset_write(struct file *file, const char __user *user_buf,
12887ac9a364SKalle Valo 			   size_t count, loff_t *ppos)
12897ac9a364SKalle Valo {
12907ac9a364SKalle Valo 
12917ac9a364SKalle Valo 	int ret;
12927ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
12937ac9a364SKalle Valo 
12947ac9a364SKalle Valo 	ret = il_force_reset(il, true);
12957ac9a364SKalle Valo 
12967ac9a364SKalle Valo 	return ret ? ret : count;
12977ac9a364SKalle Valo }
12987ac9a364SKalle Valo 
12997ac9a364SKalle Valo static ssize_t
13007ac9a364SKalle Valo il_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf,
13017ac9a364SKalle Valo 			  size_t count, loff_t *ppos)
13027ac9a364SKalle Valo {
13037ac9a364SKalle Valo 
13047ac9a364SKalle Valo 	struct il_priv *il = file->private_data;
13057ac9a364SKalle Valo 	char buf[8];
13067ac9a364SKalle Valo 	int buf_size;
13077ac9a364SKalle Valo 	int timeout;
13087ac9a364SKalle Valo 
13097ac9a364SKalle Valo 	memset(buf, 0, sizeof(buf));
13107ac9a364SKalle Valo 	buf_size = min(count, sizeof(buf) - 1);
13117ac9a364SKalle Valo 	if (copy_from_user(buf, user_buf, buf_size))
13127ac9a364SKalle Valo 		return -EFAULT;
13137ac9a364SKalle Valo 	if (sscanf(buf, "%d", &timeout) != 1)
13147ac9a364SKalle Valo 		return -EINVAL;
13157ac9a364SKalle Valo 	if (timeout < 0 || timeout > IL_MAX_WD_TIMEOUT)
13167ac9a364SKalle Valo 		timeout = IL_DEF_WD_TIMEOUT;
13177ac9a364SKalle Valo 
13187ac9a364SKalle Valo 	il->cfg->wd_timeout = timeout;
13197ac9a364SKalle Valo 	il_setup_watchdog(il);
13207ac9a364SKalle Valo 	return count;
13217ac9a364SKalle Valo }
13227ac9a364SKalle Valo 
13237ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(rx_stats);
13247ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(tx_stats);
13257ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(rx_queue);
13267ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(tx_queue);
13277ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
13287ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
13297ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(ucode_general_stats);
13307ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(sensitivity);
13317ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(chain_noise);
13327ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(power_save_status);
13337ac9a364SKalle Valo DEBUGFS_WRITE_FILE_OPS(clear_ucode_stats);
13347ac9a364SKalle Valo DEBUGFS_WRITE_FILE_OPS(clear_traffic_stats);
13357ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(fh_reg);
13367ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
13377ac9a364SKalle Valo DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
13387ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(rxon_flags);
13397ac9a364SKalle Valo DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
13407ac9a364SKalle Valo DEBUGFS_WRITE_FILE_OPS(wd_timeout);
13417ac9a364SKalle Valo 
13427ac9a364SKalle Valo /*
13437ac9a364SKalle Valo  * Create the debugfs files and directories
13447ac9a364SKalle Valo  *
13457ac9a364SKalle Valo  */
13467ac9a364SKalle Valo int
13477ac9a364SKalle Valo il_dbgfs_register(struct il_priv *il, const char *name)
13487ac9a364SKalle Valo {
13497ac9a364SKalle Valo 	struct dentry *phyd = il->hw->wiphy->debugfsdir;
13507ac9a364SKalle Valo 	struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
13517ac9a364SKalle Valo 
13527ac9a364SKalle Valo 	dir_drv = debugfs_create_dir(name, phyd);
13537ac9a364SKalle Valo 	if (!dir_drv)
13547ac9a364SKalle Valo 		return -ENOMEM;
13557ac9a364SKalle Valo 
13567ac9a364SKalle Valo 	il->debugfs_dir = dir_drv;
13577ac9a364SKalle Valo 
13587ac9a364SKalle Valo 	dir_data = debugfs_create_dir("data", dir_drv);
13597ac9a364SKalle Valo 	if (!dir_data)
13607ac9a364SKalle Valo 		goto err;
13617ac9a364SKalle Valo 	dir_rf = debugfs_create_dir("rf", dir_drv);
13627ac9a364SKalle Valo 	if (!dir_rf)
13637ac9a364SKalle Valo 		goto err;
13647ac9a364SKalle Valo 	dir_debug = debugfs_create_dir("debug", dir_drv);
13657ac9a364SKalle Valo 	if (!dir_debug)
13667ac9a364SKalle Valo 		goto err;
13677ac9a364SKalle Valo 
13687ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
13697ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
13707ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
13717ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
13727ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
13737ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
13747ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
13757ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
13767ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(rx_stats, dir_debug, S_IRUSR);
13777ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(tx_stats, dir_debug, S_IRUSR);
13787ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
13797ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
13807ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
13817ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(clear_ucode_stats, dir_debug, S_IWUSR);
13827ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(clear_traffic_stats, dir_debug, S_IWUSR);
13837ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
13847ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
13857ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
13867ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
13877ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
13887ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
13897ac9a364SKalle Valo 
13907ac9a364SKalle Valo 	if (il->cfg->sensitivity_calib_by_driver)
13917ac9a364SKalle Valo 		DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
13927ac9a364SKalle Valo 	if (il->cfg->chain_noise_calib_by_driver)
13937ac9a364SKalle Valo 		DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
13947ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
13957ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
13967ac9a364SKalle Valo 	DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
13977ac9a364SKalle Valo 	if (il->cfg->sensitivity_calib_by_driver)
13987ac9a364SKalle Valo 		DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
13997ac9a364SKalle Valo 				 &il->disable_sens_cal);
14007ac9a364SKalle Valo 	if (il->cfg->chain_noise_calib_by_driver)
14017ac9a364SKalle Valo 		DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
14027ac9a364SKalle Valo 				 &il->disable_chain_noise_cal);
14037ac9a364SKalle Valo 	DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, &il->disable_tx_power_cal);
14047ac9a364SKalle Valo 	return 0;
14057ac9a364SKalle Valo 
14067ac9a364SKalle Valo err:
14077ac9a364SKalle Valo 	IL_ERR("Can't create the debugfs directory\n");
14087ac9a364SKalle Valo 	il_dbgfs_unregister(il);
14097ac9a364SKalle Valo 	return -ENOMEM;
14107ac9a364SKalle Valo }
14117ac9a364SKalle Valo EXPORT_SYMBOL(il_dbgfs_register);
14127ac9a364SKalle Valo 
14137ac9a364SKalle Valo /**
14147ac9a364SKalle Valo  * Remove the debugfs files and directories
14157ac9a364SKalle Valo  *
14167ac9a364SKalle Valo  */
14177ac9a364SKalle Valo void
14187ac9a364SKalle Valo il_dbgfs_unregister(struct il_priv *il)
14197ac9a364SKalle Valo {
14207ac9a364SKalle Valo 	if (!il->debugfs_dir)
14217ac9a364SKalle Valo 		return;
14227ac9a364SKalle Valo 
14237ac9a364SKalle Valo 	debugfs_remove_recursive(il->debugfs_dir);
14247ac9a364SKalle Valo 	il->debugfs_dir = NULL;
14257ac9a364SKalle Valo }
14267ac9a364SKalle Valo EXPORT_SYMBOL(il_dbgfs_unregister);
1427