Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
   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 <net/mac80211.h>
  30
  31
  32#include "iwl-dev.h"
  33#include "iwl-debug.h"
  34#include "iwl-core.h"
  35#include "iwl-io.h"
  36
  37/* create and remove of files */
  38#define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
  39	if (!debugfs_create_file(#name, mode, parent, priv,		\
  40			 &iwl_legacy_dbgfs_##name##_ops))		\
  41		goto err;						\
  42} while (0)
  43
  44#define DEBUGFS_ADD_BOOL(name, parent, ptr) do {			\
  45	struct dentry *__tmp;						\
  46	__tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,		\
  47				    parent, ptr);			\
  48	if (IS_ERR(__tmp) || !__tmp)					\
  49		goto err;						\
  50} while (0)
  51
  52#define DEBUGFS_ADD_X32(name, parent, ptr) do {				\
  53	struct dentry *__tmp;						\
  54	__tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,		\
  55				   parent, ptr);			\
  56	if (IS_ERR(__tmp) || !__tmp)					\
  57		goto err;						\
  58} while (0)
  59
  60/* file operation */
  61#define DEBUGFS_READ_FUNC(name)                                         \
  62static ssize_t iwl_legacy_dbgfs_##name##_read(struct file *file,               \
  63					char __user *user_buf,          \
  64					size_t count, loff_t *ppos);
  65
  66#define DEBUGFS_WRITE_FUNC(name)                                        \
  67static ssize_t iwl_legacy_dbgfs_##name##_write(struct file *file,              \
  68					const char __user *user_buf,    \
  69					size_t count, loff_t *ppos);
  70
  71
  72static int
  73iwl_legacy_dbgfs_open_file_generic(struct inode *inode, struct file *file)
  74{
  75	file->private_data = inode->i_private;
  76	return 0;
  77}
  78
  79#define DEBUGFS_READ_FILE_OPS(name) 				\
  80	DEBUGFS_READ_FUNC(name);                                        \
  81static const struct file_operations iwl_legacy_dbgfs_##name##_ops = {	\
  82	.read = iwl_legacy_dbgfs_##name##_read,				\
  83	.open = iwl_legacy_dbgfs_open_file_generic,                    	\
  84	.llseek = generic_file_llseek,					\
  85};
  86
  87#define DEBUGFS_WRITE_FILE_OPS(name) 				\
  88	DEBUGFS_WRITE_FUNC(name);                                       \
  89static const struct file_operations iwl_legacy_dbgfs_##name##_ops = {	\
  90	.write = iwl_legacy_dbgfs_##name##_write,			\
  91	.open = iwl_legacy_dbgfs_open_file_generic,                    	\
  92	.llseek = generic_file_llseek,					\
  93};
  94
  95#define DEBUGFS_READ_WRITE_FILE_OPS(name)                           \
  96	DEBUGFS_READ_FUNC(name);                                        \
  97	DEBUGFS_WRITE_FUNC(name);                                       \
  98static const struct file_operations iwl_legacy_dbgfs_##name##_ops = {	\
  99	.write = iwl_legacy_dbgfs_##name##_write,			\
 100	.read = iwl_legacy_dbgfs_##name##_read,				\
 101	.open = iwl_legacy_dbgfs_open_file_generic,			\
 102	.llseek = generic_file_llseek,					\
 103};
 104
 105static ssize_t iwl_legacy_dbgfs_tx_statistics_read(struct file *file,
 106						char __user *user_buf,
 107						size_t count, loff_t *ppos) {
 108
 109	struct iwl_priv *priv = file->private_data;
 110	char *buf;
 111	int pos = 0;
 112
 113	int cnt;
 114	ssize_t ret;
 115	const size_t bufsz = 100 +
 116		sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
 117	buf = kzalloc(bufsz, GFP_KERNEL);
 118	if (!buf)
 119		return -ENOMEM;
 120	pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
 121	for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
 122		pos += scnprintf(buf + pos, bufsz - pos,
 123				 "\t%25s\t\t: %u\n",
 124				 iwl_legacy_get_mgmt_string(cnt),
 125				 priv->tx_stats.mgmt[cnt]);
 126	}
 127	pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
 128	for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
 129		pos += scnprintf(buf + pos, bufsz - pos,
 130				 "\t%25s\t\t: %u\n",
 131				 iwl_legacy_get_ctrl_string(cnt),
 132				 priv->tx_stats.ctrl[cnt]);
 133	}
 134	pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
 135	pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
 136			 priv->tx_stats.data_cnt);
 137	pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
 138			 priv->tx_stats.data_bytes);
 139	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 140	kfree(buf);
 141	return ret;
 142}
 143
 144static ssize_t
 145iwl_legacy_dbgfs_clear_traffic_statistics_write(struct file *file,
 146					const char __user *user_buf,
 147					size_t count, loff_t *ppos)
 148{
 149	struct iwl_priv *priv = file->private_data;
 150	u32 clear_flag;
 151	char buf[8];
 152	int buf_size;
 153
 154	memset(buf, 0, sizeof(buf));
 155	buf_size = min(count, sizeof(buf) -  1);
 156	if (copy_from_user(buf, user_buf, buf_size))
 157		return -EFAULT;
 158	if (sscanf(buf, "%x", &clear_flag) != 1)
 159		return -EFAULT;
 160	iwl_legacy_clear_traffic_stats(priv);
 161
 162	return count;
 163}
 164
 165static ssize_t iwl_legacy_dbgfs_rx_statistics_read(struct file *file,
 166						char __user *user_buf,
 167						size_t count, loff_t *ppos) {
 168
 169	struct iwl_priv *priv = file->private_data;
 170	char *buf;
 171	int pos = 0;
 172	int cnt;
 173	ssize_t ret;
 174	const size_t bufsz = 100 +
 175		sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
 176	buf = kzalloc(bufsz, GFP_KERNEL);
 177	if (!buf)
 178		return -ENOMEM;
 179
 180	pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
 181	for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
 182		pos += scnprintf(buf + pos, bufsz - pos,
 183				 "\t%25s\t\t: %u\n",
 184				 iwl_legacy_get_mgmt_string(cnt),
 185				 priv->rx_stats.mgmt[cnt]);
 186	}
 187	pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
 188	for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
 189		pos += scnprintf(buf + pos, bufsz - pos,
 190				 "\t%25s\t\t: %u\n",
 191				 iwl_legacy_get_ctrl_string(cnt),
 192				 priv->rx_stats.ctrl[cnt]);
 193	}
 194	pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
 195	pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
 196			 priv->rx_stats.data_cnt);
 197	pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
 198			 priv->rx_stats.data_bytes);
 199
 200	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 201	kfree(buf);
 202	return ret;
 203}
 204
 205#define BYTE1_MASK 0x000000ff;
 206#define BYTE2_MASK 0x0000ffff;
 207#define BYTE3_MASK 0x00ffffff;
 208static ssize_t iwl_legacy_dbgfs_sram_read(struct file *file,
 209					char __user *user_buf,
 210					size_t count, loff_t *ppos)
 211{
 212	u32 val;
 213	char *buf;
 214	ssize_t ret;
 215	int i;
 216	int pos = 0;
 217	struct iwl_priv *priv = file->private_data;
 218	size_t bufsz;
 219
 220	/* default is to dump the entire data segment */
 221	if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
 222		priv->dbgfs_sram_offset = 0x800000;
 223		if (priv->ucode_type == UCODE_INIT)
 224			priv->dbgfs_sram_len = priv->ucode_init_data.len;
 225		else
 226			priv->dbgfs_sram_len = priv->ucode_data.len;
 227	}
 228	bufsz =  30 + priv->dbgfs_sram_len * sizeof(char) * 10;
 229	buf = kmalloc(bufsz, GFP_KERNEL);
 230	if (!buf)
 231		return -ENOMEM;
 232	pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
 233			priv->dbgfs_sram_len);
 234	pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
 235			priv->dbgfs_sram_offset);
 236	for (i = priv->dbgfs_sram_len; i > 0; i -= 4) {
 237		val = iwl_legacy_read_targ_mem(priv, priv->dbgfs_sram_offset + \
 238					priv->dbgfs_sram_len - i);
 239		if (i < 4) {
 240			switch (i) {
 241			case 1:
 242				val &= BYTE1_MASK;
 243				break;
 244			case 2:
 245				val &= BYTE2_MASK;
 246				break;
 247			case 3:
 248				val &= BYTE3_MASK;
 249				break;
 250			}
 251		}
 252		if (!(i % 16))
 253			pos += scnprintf(buf + pos, bufsz - pos, "\n");
 254		pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
 255	}
 256	pos += scnprintf(buf + pos, bufsz - pos, "\n");
 257
 258	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 259	kfree(buf);
 260	return ret;
 261}
 262
 263static ssize_t iwl_legacy_dbgfs_sram_write(struct file *file,
 264					const char __user *user_buf,
 265					size_t count, loff_t *ppos)
 266{
 267	struct iwl_priv *priv = file->private_data;
 268	char buf[64];
 269	int buf_size;
 270	u32 offset, len;
 271
 272	memset(buf, 0, sizeof(buf));
 273	buf_size = min(count, sizeof(buf) -  1);
 274	if (copy_from_user(buf, user_buf, buf_size))
 275		return -EFAULT;
 276
 277	if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
 278		priv->dbgfs_sram_offset = offset;
 279		priv->dbgfs_sram_len = len;
 280	} else {
 281		priv->dbgfs_sram_offset = 0;
 282		priv->dbgfs_sram_len = 0;
 283	}
 284
 285	return count;
 286}
 287
 288static ssize_t
 289iwl_legacy_dbgfs_stations_read(struct file *file, char __user *user_buf,
 290					size_t count, loff_t *ppos)
 291{
 292	struct iwl_priv *priv = file->private_data;
 293	struct iwl_station_entry *station;
 294	int max_sta = priv->hw_params.max_stations;
 295	char *buf;
 296	int i, j, pos = 0;
 297	ssize_t ret;
 298	/* Add 30 for initial string */
 299	const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
 300
 301	buf = kmalloc(bufsz, GFP_KERNEL);
 302	if (!buf)
 303		return -ENOMEM;
 304
 305	pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
 306			priv->num_stations);
 307
 308	for (i = 0; i < max_sta; i++) {
 309		station = &priv->stations[i];
 310		if (!station->used)
 311			continue;
 312		pos += scnprintf(buf + pos, bufsz - pos,
 313				 "station %d - addr: %pM, flags: %#x\n",
 314				 i, station->sta.sta.addr,
 315				 station->sta.station_flags_msk);
 316		pos += scnprintf(buf + pos, bufsz - pos,
 317				"TID\tseq_num\ttxq_id\tframes\ttfds\t");
 318		pos += scnprintf(buf + pos, bufsz - pos,
 319				"start_idx\tbitmap\t\t\trate_n_flags\n");
 320
 321		for (j = 0; j < MAX_TID_COUNT; j++) {
 322			pos += scnprintf(buf + pos, bufsz - pos,
 323				"%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
 324				j, station->tid[j].seq_number,
 325				station->tid[j].agg.txq_id,
 326				station->tid[j].agg.frame_count,
 327				station->tid[j].tfds_in_queue,
 328				station->tid[j].agg.start_idx,
 329				station->tid[j].agg.bitmap,
 330				station->tid[j].agg.rate_n_flags);
 331
 332			if (station->tid[j].agg.wait_for_ba)
 333				pos += scnprintf(buf + pos, bufsz - pos,
 334						 " - waitforba");
 335			pos += scnprintf(buf + pos, bufsz - pos, "\n");
 336		}
 337
 338		pos += scnprintf(buf + pos, bufsz - pos, "\n");
 339	}
 340
 341	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 342	kfree(buf);
 343	return ret;
 344}
 345
 346static ssize_t iwl_legacy_dbgfs_nvm_read(struct file *file,
 347				       char __user *user_buf,
 348				       size_t count,
 349				       loff_t *ppos)
 350{
 351	ssize_t ret;
 352	struct iwl_priv *priv = file->private_data;
 353	int pos = 0, ofs = 0, buf_size = 0;
 354	const u8 *ptr;
 355	char *buf;
 356	u16 eeprom_ver;
 357	size_t eeprom_len = priv->cfg->base_params->eeprom_size;
 358	buf_size = 4 * eeprom_len + 256;
 359
 360	if (eeprom_len % 16) {
 361		IWL_ERR(priv, "NVM size is not multiple of 16.\n");
 362		return -ENODATA;
 363	}
 364
 365	ptr = priv->eeprom;
 366	if (!ptr) {
 367		IWL_ERR(priv, "Invalid EEPROM memory\n");
 368		return -ENOMEM;
 369	}
 370
 371	/* 4 characters for byte 0xYY */
 372	buf = kzalloc(buf_size, GFP_KERNEL);
 373	if (!buf) {
 374		IWL_ERR(priv, "Can not allocate Buffer\n");
 375		return -ENOMEM;
 376	}
 377	eeprom_ver = iwl_legacy_eeprom_query16(priv, EEPROM_VERSION);
 378	pos += scnprintf(buf + pos, buf_size - pos, "EEPROM "
 379			"version: 0x%x\n", eeprom_ver);
 380	for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
 381		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
 382		hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
 383				   buf_size - pos, 0);
 384		pos += strlen(buf + pos);
 385		if (buf_size - pos > 0)
 386			buf[pos++] = '\n';
 387	}
 388
 389	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 390	kfree(buf);
 391	return ret;
 392}
 393
 394static ssize_t
 395iwl_legacy_dbgfs_channels_read(struct file *file, char __user *user_buf,
 396				       size_t count, loff_t *ppos)
 397{
 398	struct iwl_priv *priv = file->private_data;
 399	struct ieee80211_channel *channels = NULL;
 400	const struct ieee80211_supported_band *supp_band = NULL;
 401	int pos = 0, i, bufsz = PAGE_SIZE;
 402	char *buf;
 403	ssize_t ret;
 404
 405	if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
 406		return -EAGAIN;
 407
 408	buf = kzalloc(bufsz, GFP_KERNEL);
 409	if (!buf) {
 410		IWL_ERR(priv, "Can not allocate Buffer\n");
 411		return -ENOMEM;
 412	}
 413
 414	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
 415	if (supp_band) {
 416		channels = supp_band->channels;
 417
 418		pos += scnprintf(buf + pos, bufsz - pos,
 419				"Displaying %d channels in 2.4GHz band 802.11bg):\n",
 420				supp_band->n_channels);
 421
 422		for (i = 0; i < supp_band->n_channels; i++)
 423			pos += scnprintf(buf + pos, bufsz - pos,
 424				"%d: %ddBm: BSS%s%s, %s.\n",
 425				channels[i].hw_value,
 426				channels[i].max_power,
 427				channels[i].flags & IEEE80211_CHAN_RADAR ?
 428				" (IEEE 802.11h required)" : "",
 429				((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
 430				|| (channels[i].flags &
 431				IEEE80211_CHAN_RADAR)) ? "" :
 432				", IBSS",
 433				channels[i].flags &
 434				IEEE80211_CHAN_PASSIVE_SCAN ?
 435				"passive only" : "active/passive");
 436	}
 437	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
 438	if (supp_band) {
 439		channels = supp_band->channels;
 440
 441		pos += scnprintf(buf + pos, bufsz - pos,
 442				"Displaying %d channels in 5.2GHz band (802.11a)\n",
 443				supp_band->n_channels);
 444
 445		for (i = 0; i < supp_band->n_channels; i++)
 446			pos += scnprintf(buf + pos, bufsz - pos,
 447				"%d: %ddBm: BSS%s%s, %s.\n",
 448				channels[i].hw_value,
 449				channels[i].max_power,
 450				channels[i].flags & IEEE80211_CHAN_RADAR ?
 451				" (IEEE 802.11h required)" : "",
 452				((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
 453				|| (channels[i].flags &
 454				IEEE80211_CHAN_RADAR)) ? "" :
 455				", IBSS",
 456				channels[i].flags &
 457				IEEE80211_CHAN_PASSIVE_SCAN ?
 458				"passive only" : "active/passive");
 459	}
 460	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 461	kfree(buf);
 462	return ret;
 463}
 464
 465static ssize_t iwl_legacy_dbgfs_status_read(struct file *file,
 466						char __user *user_buf,
 467						size_t count, loff_t *ppos) {
 468
 469	struct iwl_priv *priv = file->private_data;
 470	char buf[512];
 471	int pos = 0;
 472	const size_t bufsz = sizeof(buf);
 473
 474	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
 475		test_bit(STATUS_HCMD_ACTIVE, &priv->status));
 476	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
 477		test_bit(STATUS_INT_ENABLED, &priv->status));
 478	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
 479		test_bit(STATUS_RF_KILL_HW, &priv->status));
 480	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
 481		test_bit(STATUS_CT_KILL, &priv->status));
 482	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
 483		test_bit(STATUS_INIT, &priv->status));
 484	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
 485		test_bit(STATUS_ALIVE, &priv->status));
 486	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
 487		test_bit(STATUS_READY, &priv->status));
 488	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n",
 489		test_bit(STATUS_TEMPERATURE, &priv->status));
 490	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
 491		test_bit(STATUS_GEO_CONFIGURED, &priv->status));
 492	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
 493		test_bit(STATUS_EXIT_PENDING, &priv->status));
 494	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
 495		test_bit(STATUS_STATISTICS, &priv->status));
 496	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
 497		test_bit(STATUS_SCANNING, &priv->status));
 498	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
 499		test_bit(STATUS_SCAN_ABORTING, &priv->status));
 500	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
 501		test_bit(STATUS_SCAN_HW, &priv->status));
 502	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
 503		test_bit(STATUS_POWER_PMI, &priv->status));
 504	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
 505		test_bit(STATUS_FW_ERROR, &priv->status));
 506	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 507}
 508
 509static ssize_t iwl_legacy_dbgfs_interrupt_read(struct file *file,
 510					char __user *user_buf,
 511					size_t count, loff_t *ppos) {
 512
 513	struct iwl_priv *priv = file->private_data;
 514	int pos = 0;
 515	int cnt = 0;
 516	char *buf;
 517	int bufsz = 24 * 64; /* 24 items * 64 char per item */
 518	ssize_t ret;
 519
 520	buf = kzalloc(bufsz, GFP_KERNEL);
 521	if (!buf) {
 522		IWL_ERR(priv, "Can not allocate Buffer\n");
 523		return -ENOMEM;
 524	}
 525
 526	pos += scnprintf(buf + pos, bufsz - pos,
 527			"Interrupt Statistics Report:\n");
 528
 529	pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
 530		priv->isr_stats.hw);
 531	pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
 532		priv->isr_stats.sw);
 533	if (priv->isr_stats.sw || priv->isr_stats.hw) {
 534		pos += scnprintf(buf + pos, bufsz - pos,
 535			"\tLast Restarting Code:  0x%X\n",
 536			priv->isr_stats.err_code);
 537	}
 538#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
 539	pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
 540		priv->isr_stats.sch);
 541	pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
 542		priv->isr_stats.alive);
 543#endif
 544	pos += scnprintf(buf + pos, bufsz - pos,
 545		"HW RF KILL switch toggled:\t %u\n",
 546		priv->isr_stats.rfkill);
 547
 548	pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
 549		priv->isr_stats.ctkill);
 550
 551	pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
 552		priv->isr_stats.wakeup);
 553
 554	pos += scnprintf(buf + pos, bufsz - pos,
 555		"Rx command responses:\t\t %u\n",
 556		priv->isr_stats.rx);
 557	for (cnt = 0; cnt < REPLY_MAX; cnt++) {
 558		if (priv->isr_stats.rx_handlers[cnt] > 0)
 559			pos += scnprintf(buf + pos, bufsz - pos,
 560				"\tRx handler[%36s]:\t\t %u\n",
 561				iwl_legacy_get_cmd_string(cnt),
 562				priv->isr_stats.rx_handlers[cnt]);
 563	}
 564
 565	pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
 566		priv->isr_stats.tx);
 567
 568	pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
 569		priv->isr_stats.unhandled);
 570
 571	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 572	kfree(buf);
 573	return ret;
 574}
 575
 576static ssize_t iwl_legacy_dbgfs_interrupt_write(struct file *file,
 577					 const char __user *user_buf,
 578					 size_t count, loff_t *ppos)
 579{
 580	struct iwl_priv *priv = file->private_data;
 581	char buf[8];
 582	int buf_size;
 583	u32 reset_flag;
 584
 585	memset(buf, 0, sizeof(buf));
 586	buf_size = min(count, sizeof(buf) -  1);
 587	if (copy_from_user(buf, user_buf, buf_size))
 588		return -EFAULT;
 589	if (sscanf(buf, "%x", &reset_flag) != 1)
 590		return -EFAULT;
 591	if (reset_flag == 0)
 592		iwl_legacy_clear_isr_stats(priv);
 593
 594	return count;
 595}
 596
 597static ssize_t
 598iwl_legacy_dbgfs_qos_read(struct file *file, char __user *user_buf,
 599				       size_t count, loff_t *ppos)
 600{
 601	struct iwl_priv *priv = file->private_data;
 602	struct iwl_rxon_context *ctx;
 603	int pos = 0, i;
 604	char buf[256 * NUM_IWL_RXON_CTX];
 605	const size_t bufsz = sizeof(buf);
 606
 607	for_each_context(priv, ctx) {
 608		pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
 609				 ctx->ctxid);
 610		for (i = 0; i < AC_NUM; i++) {
 611			pos += scnprintf(buf + pos, bufsz - pos,
 612				"\tcw_min\tcw_max\taifsn\ttxop\n");
 613			pos += scnprintf(buf + pos, bufsz - pos,
 614				"AC[%d]\t%u\t%u\t%u\t%u\n", i,
 615				ctx->qos_data.def_qos_parm.ac[i].cw_min,
 616				ctx->qos_data.def_qos_parm.ac[i].cw_max,
 617				ctx->qos_data.def_qos_parm.ac[i].aifsn,
 618				ctx->qos_data.def_qos_parm.ac[i].edca_txop);
 619		}
 620		pos += scnprintf(buf + pos, bufsz - pos, "\n");
 621	}
 622	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 623}
 624
 625static ssize_t iwl_legacy_dbgfs_disable_ht40_write(struct file *file,
 626					 const char __user *user_buf,
 627					 size_t count, loff_t *ppos)
 628{
 629	struct iwl_priv *priv = file->private_data;
 630	char buf[8];
 631	int buf_size;
 632	int ht40;
 633
 634	memset(buf, 0, sizeof(buf));
 635	buf_size = min(count, sizeof(buf) -  1);
 636	if (copy_from_user(buf, user_buf, buf_size))
 637		return -EFAULT;
 638	if (sscanf(buf, "%d", &ht40) != 1)
 639		return -EFAULT;
 640	if (!iwl_legacy_is_any_associated(priv))
 641		priv->disable_ht40 = ht40 ? true : false;
 642	else {
 643		IWL_ERR(priv, "Sta associated with AP - "
 644			"Change to 40MHz channel support is not allowed\n");
 645		return -EINVAL;
 646	}
 647
 648	return count;
 649}
 650
 651static ssize_t iwl_legacy_dbgfs_disable_ht40_read(struct file *file,
 652					 char __user *user_buf,
 653					 size_t count, loff_t *ppos)
 654{
 655	struct iwl_priv *priv = file->private_data;
 656	char buf[100];
 657	int pos = 0;
 658	const size_t bufsz = sizeof(buf);
 659
 660	pos += scnprintf(buf + pos, bufsz - pos,
 661			"11n 40MHz Mode: %s\n",
 662			priv->disable_ht40 ? "Disabled" : "Enabled");
 663	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 664}
 665
 666DEBUGFS_READ_WRITE_FILE_OPS(sram);
 667DEBUGFS_READ_FILE_OPS(nvm);
 668DEBUGFS_READ_FILE_OPS(stations);
 669DEBUGFS_READ_FILE_OPS(channels);
 670DEBUGFS_READ_FILE_OPS(status);
 671DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
 672DEBUGFS_READ_FILE_OPS(qos);
 673DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
 674
 675static ssize_t iwl_legacy_dbgfs_traffic_log_read(struct file *file,
 676					 char __user *user_buf,
 677					 size_t count, loff_t *ppos)
 678{
 679	struct iwl_priv *priv = file->private_data;
 680	int pos = 0, ofs = 0;
 681	int cnt = 0, entry;
 682	struct iwl_tx_queue *txq;
 683	struct iwl_queue *q;
 684	struct iwl_rx_queue *rxq = &priv->rxq;
 685	char *buf;
 686	int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
 687		(priv->cfg->base_params->num_of_queues * 32 * 8) + 400;
 688	const u8 *ptr;
 689	ssize_t ret;
 690
 691	if (!priv->txq) {
 692		IWL_ERR(priv, "txq not ready\n");
 693		return -EAGAIN;
 694	}
 695	buf = kzalloc(bufsz, GFP_KERNEL);
 696	if (!buf) {
 697		IWL_ERR(priv, "Can not allocate buffer\n");
 698		return -ENOMEM;
 699	}
 700	pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
 701	for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
 702		txq = &priv->txq[cnt];
 703		q = &txq->q;
 704		pos += scnprintf(buf + pos, bufsz - pos,
 705				"q[%d]: read_ptr: %u, write_ptr: %u\n",
 706				cnt, q->read_ptr, q->write_ptr);
 707	}
 708	if (priv->tx_traffic && (iwlegacy_debug_level & IWL_DL_TX)) {
 709		ptr = priv->tx_traffic;
 710		pos += scnprintf(buf + pos, bufsz - pos,
 711				"Tx Traffic idx: %u\n",	priv->tx_traffic_idx);
 712		for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
 713			for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
 714			     entry++,  ofs += 16) {
 715				pos += scnprintf(buf + pos, bufsz - pos,
 716						"0x%.4x ", ofs);
 717				hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
 718						   buf + pos, bufsz - pos, 0);
 719				pos += strlen(buf + pos);
 720				if (bufsz - pos > 0)
 721					buf[pos++] = '\n';
 722			}
 723		}
 724	}
 725
 726	pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
 727	pos += scnprintf(buf + pos, bufsz - pos,
 728			"read: %u, write: %u\n",
 729			 rxq->read, rxq->write);
 730
 731	if (priv->rx_traffic && (iwlegacy_debug_level & IWL_DL_RX)) {
 732		ptr = priv->rx_traffic;
 733		pos += scnprintf(buf + pos, bufsz - pos,
 734				"Rx Traffic idx: %u\n",	priv->rx_traffic_idx);
 735		for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
 736			for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
 737			     entry++,  ofs += 16) {
 738				pos += scnprintf(buf + pos, bufsz - pos,
 739						"0x%.4x ", ofs);
 740				hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
 741						   buf + pos, bufsz - pos, 0);
 742				pos += strlen(buf + pos);
 743				if (bufsz - pos > 0)
 744					buf[pos++] = '\n';
 745			}
 746		}
 747	}
 748
 749	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 750	kfree(buf);
 751	return ret;
 752}
 753
 754static ssize_t iwl_legacy_dbgfs_traffic_log_write(struct file *file,
 755					 const char __user *user_buf,
 756					 size_t count, loff_t *ppos)
 757{
 758	struct iwl_priv *priv = file->private_data;
 759	char buf[8];
 760	int buf_size;
 761	int traffic_log;
 762
 763	memset(buf, 0, sizeof(buf));
 764	buf_size = min(count, sizeof(buf) -  1);
 765	if (copy_from_user(buf, user_buf, buf_size))
 766		return -EFAULT;
 767	if (sscanf(buf, "%d", &traffic_log) != 1)
 768		return -EFAULT;
 769	if (traffic_log == 0)
 770		iwl_legacy_reset_traffic_log(priv);
 771
 772	return count;
 773}
 774
 775static ssize_t iwl_legacy_dbgfs_tx_queue_read(struct file *file,
 776						char __user *user_buf,
 777						size_t count, loff_t *ppos) {
 778
 779	struct iwl_priv *priv = file->private_data;
 780	struct iwl_tx_queue *txq;
 781	struct iwl_queue *q;
 782	char *buf;
 783	int pos = 0;
 784	int cnt;
 785	int ret;
 786	const size_t bufsz = sizeof(char) * 64 *
 787				priv->cfg->base_params->num_of_queues;
 788
 789	if (!priv->txq) {
 790		IWL_ERR(priv, "txq not ready\n");
 791		return -EAGAIN;
 792	}
 793	buf = kzalloc(bufsz, GFP_KERNEL);
 794	if (!buf)
 795		return -ENOMEM;
 796
 797	for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
 798		txq = &priv->txq[cnt];
 799		q = &txq->q;
 800		pos += scnprintf(buf + pos, bufsz - pos,
 801				"hwq %.2d: read=%u write=%u stop=%d"
 802				" swq_id=%#.2x (ac %d/hwq %d)\n",
 803				cnt, q->read_ptr, q->write_ptr,
 804				!!test_bit(cnt, priv->queue_stopped),
 805				txq->swq_id, txq->swq_id & 3,
 806				(txq->swq_id >> 2) & 0x1f);
 807		if (cnt >= 4)
 808			continue;
 809		/* for the ACs, display the stop count too */
 810		pos += scnprintf(buf + pos, bufsz - pos,
 811				"        stop-count: %d\n",
 812				atomic_read(&priv->queue_stop_count[cnt]));
 813	}
 814	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 815	kfree(buf);
 816	return ret;
 817}
 818
 819static ssize_t iwl_legacy_dbgfs_rx_queue_read(struct file *file,
 820						char __user *user_buf,
 821						size_t count, loff_t *ppos) {
 822
 823	struct iwl_priv *priv = file->private_data;
 824	struct iwl_rx_queue *rxq = &priv->rxq;
 825	char buf[256];
 826	int pos = 0;
 827	const size_t bufsz = sizeof(buf);
 828
 829	pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
 830						rxq->read);
 831	pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
 832						rxq->write);
 833	pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
 834						rxq->free_count);
 835	if (rxq->rb_stts) {
 836		pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
 837			 le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
 838	} else {
 839		pos += scnprintf(buf + pos, bufsz - pos,
 840					"closed_rb_num: Not Allocated\n");
 841	}
 842	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 843}
 844
 845static ssize_t iwl_legacy_dbgfs_ucode_rx_stats_read(struct file *file,
 846					char __user *user_buf,
 847					size_t count, loff_t *ppos)
 848{
 849	struct iwl_priv *priv = file->private_data;
 850	return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
 851			user_buf, count, ppos);
 852}
 853
 854static ssize_t iwl_legacy_dbgfs_ucode_tx_stats_read(struct file *file,
 855					char __user *user_buf,
 856					size_t count, loff_t *ppos)
 857{
 858	struct iwl_priv *priv = file->private_data;
 859	return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
 860			user_buf, count, ppos);
 861}
 862
 863static ssize_t iwl_legacy_dbgfs_ucode_general_stats_read(struct file *file,
 864					char __user *user_buf,
 865					size_t count, loff_t *ppos)
 866{
 867	struct iwl_priv *priv = file->private_data;
 868	return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
 869			user_buf, count, ppos);
 870}
 871
 872static ssize_t iwl_legacy_dbgfs_sensitivity_read(struct file *file,
 873					char __user *user_buf,
 874					size_t count, loff_t *ppos) {
 875
 876	struct iwl_priv *priv = file->private_data;
 877	int pos = 0;
 878	int cnt = 0;
 879	char *buf;
 880	int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
 881	ssize_t ret;
 882	struct iwl_sensitivity_data *data;
 883
 884	data = &priv->sensitivity_data;
 885	buf = kzalloc(bufsz, GFP_KERNEL);
 886	if (!buf) {
 887		IWL_ERR(priv, "Can not allocate Buffer\n");
 888		return -ENOMEM;
 889	}
 890
 891	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
 892			data->auto_corr_ofdm);
 893	pos += scnprintf(buf + pos, bufsz - pos,
 894			"auto_corr_ofdm_mrc:\t\t %u\n",
 895			data->auto_corr_ofdm_mrc);
 896	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
 897			data->auto_corr_ofdm_x1);
 898	pos += scnprintf(buf + pos, bufsz - pos,
 899			"auto_corr_ofdm_mrc_x1:\t\t %u\n",
 900			data->auto_corr_ofdm_mrc_x1);
 901	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
 902			data->auto_corr_cck);
 903	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
 904			data->auto_corr_cck_mrc);
 905	pos += scnprintf(buf + pos, bufsz - pos,
 906			"last_bad_plcp_cnt_ofdm:\t\t %u\n",
 907			data->last_bad_plcp_cnt_ofdm);
 908	pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
 909			data->last_fa_cnt_ofdm);
 910	pos += scnprintf(buf + pos, bufsz - pos,
 911			"last_bad_plcp_cnt_cck:\t\t %u\n",
 912			data->last_bad_plcp_cnt_cck);
 913	pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
 914			data->last_fa_cnt_cck);
 915	pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
 916			data->nrg_curr_state);
 917	pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
 918			data->nrg_prev_state);
 919	pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
 920	for (cnt = 0; cnt < 10; cnt++) {
 921		pos += scnprintf(buf + pos, bufsz - pos, " %u",
 922				data->nrg_value[cnt]);
 923	}
 924	pos += scnprintf(buf + pos, bufsz - pos, "\n");
 925	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
 926	for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
 927		pos += scnprintf(buf + pos, bufsz - pos, " %u",
 928				data->nrg_silence_rssi[cnt]);
 929	}
 930	pos += scnprintf(buf + pos, bufsz - pos, "\n");
 931	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
 932			data->nrg_silence_ref);
 933	pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
 934			data->nrg_energy_idx);
 935	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
 936			data->nrg_silence_idx);
 937	pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
 938			data->nrg_th_cck);
 939	pos += scnprintf(buf + pos, bufsz - pos,
 940			"nrg_auto_corr_silence_diff:\t %u\n",
 941			data->nrg_auto_corr_silence_diff);
 942	pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
 943			data->num_in_cck_no_fa);
 944	pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
 945			data->nrg_th_ofdm);
 946
 947	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 948	kfree(buf);
 949	return ret;
 950}
 951
 952
 953static ssize_t iwl_legacy_dbgfs_chain_noise_read(struct file *file,
 954					char __user *user_buf,
 955					size_t count, loff_t *ppos) {
 956
 957	struct iwl_priv *priv = file->private_data;
 958	int pos = 0;
 959	int cnt = 0;
 960	char *buf;
 961	int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
 962	ssize_t ret;
 963	struct iwl_chain_noise_data *data;
 964
 965	data = &priv->chain_noise_data;
 966	buf = kzalloc(bufsz, GFP_KERNEL);
 967	if (!buf) {
 968		IWL_ERR(priv, "Can not allocate Buffer\n");
 969		return -ENOMEM;
 970	}
 971
 972	pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
 973			data->active_chains);
 974	pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
 975			data->chain_noise_a);
 976	pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
 977			data->chain_noise_b);
 978	pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
 979			data->chain_noise_c);
 980	pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
 981			data->chain_signal_a);
 982	pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
 983			data->chain_signal_b);
 984	pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
 985			data->chain_signal_c);
 986	pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
 987			data->beacon_count);
 988
 989	pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
 990	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
 991		pos += scnprintf(buf + pos, bufsz - pos, " %u",
 992				data->disconn_array[cnt]);
 993	}
 994	pos += scnprintf(buf + pos, bufsz - pos, "\n");
 995	pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
 996	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
 997		pos += scnprintf(buf + pos, bufsz - pos, " %u",
 998				data->delta_gain_code[cnt]);
 999	}
1000	pos += scnprintf(buf + pos, bufsz - pos, "\n");
1001	pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
1002			data->radio_write);
1003	pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
1004			data->state);
1005
1006	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1007	kfree(buf);
1008	return ret;
1009}
1010
1011static ssize_t iwl_legacy_dbgfs_power_save_status_read(struct file *file,
1012						    char __user *user_buf,
1013						    size_t count, loff_t *ppos)
1014{
1015	struct iwl_priv *priv = file->private_data;
1016	char buf[60];
1017	int pos = 0;
1018	const size_t bufsz = sizeof(buf);
1019	u32 pwrsave_status;
1020
1021	pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
1022			CSR_GP_REG_POWER_SAVE_STATUS_MSK;
1023
1024	pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
1025	pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
1026		(pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
1027		(pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
1028		(pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
1029		"error");
1030
1031	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1032}
1033
1034static ssize_t iwl_legacy_dbgfs_clear_ucode_statistics_write(struct file *file,
1035					 const char __user *user_buf,
1036					 size_t count, loff_t *ppos)
1037{
1038	struct iwl_priv *priv = file->private_data;
1039	char buf[8];
1040	int buf_size;
1041	int clear;
1042
1043	memset(buf, 0, sizeof(buf));
1044	buf_size = min(count, sizeof(buf) -  1);
1045	if (copy_from_user(buf, user_buf, buf_size))
1046		return -EFAULT;
1047	if (sscanf(buf, "%d", &clear) != 1)
1048		return -EFAULT;
1049
1050	/* make request to uCode to retrieve statistics information */
1051	mutex_lock(&priv->mutex);
1052	iwl_legacy_send_statistics_request(priv, CMD_SYNC, true);
1053	mutex_unlock(&priv->mutex);
1054
1055	return count;
1056}
1057
1058static ssize_t iwl_legacy_dbgfs_rxon_flags_read(struct file *file,
1059					 char __user *user_buf,
1060					 size_t count, loff_t *ppos) {
1061
1062	struct iwl_priv *priv = file->private_data;
1063	int len = 0;
1064	char buf[20];
1065
1066	len = sprintf(buf, "0x%04X\n",
1067		le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
1068	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1069}
1070
1071static ssize_t iwl_legacy_dbgfs_rxon_filter_flags_read(struct file *file,
1072						char __user *user_buf,
1073						size_t count, loff_t *ppos) {
1074
1075	struct iwl_priv *priv = file->private_data;
1076	int len = 0;
1077	char buf[20];
1078
1079	len = sprintf(buf, "0x%04X\n",
1080	le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
1081	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1082}
1083
1084static ssize_t iwl_legacy_dbgfs_fh_reg_read(struct file *file,
1085					 char __user *user_buf,
1086					 size_t count, loff_t *ppos)
1087{
1088	struct iwl_priv *priv = file->private_data;
1089	char *buf;
1090	int pos = 0;
1091	ssize_t ret = -EFAULT;
1092
1093	if (priv->cfg->ops->lib->dump_fh) {
1094		ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
1095		if (buf) {
1096			ret = simple_read_from_buffer(user_buf,
1097						      count, ppos, buf, pos);
1098			kfree(buf);
1099		}
1100	}
1101
1102	return ret;
1103}
1104
1105static ssize_t iwl_legacy_dbgfs_missed_beacon_read(struct file *file,
1106					char __user *user_buf,
1107					size_t count, loff_t *ppos) {
1108
1109	struct iwl_priv *priv = file->private_data;
1110	int pos = 0;
1111	char buf[12];
1112	const size_t bufsz = sizeof(buf);
1113
1114	pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
1115			priv->missed_beacon_threshold);
1116
1117	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1118}
1119
1120static ssize_t iwl_legacy_dbgfs_missed_beacon_write(struct file *file,
1121					 const char __user *user_buf,
1122					 size_t count, loff_t *ppos)
1123{
1124	struct iwl_priv *priv = file->private_data;
1125	char buf[8];
1126	int buf_size;
1127	int missed;
1128
1129	memset(buf, 0, sizeof(buf));
1130	buf_size = min(count, sizeof(buf) -  1);
1131	if (copy_from_user(buf, user_buf, buf_size))
1132		return -EFAULT;
1133	if (sscanf(buf, "%d", &missed) != 1)
1134		return -EINVAL;
1135
1136	if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
1137	    missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
1138		priv->missed_beacon_threshold =
1139			IWL_MISSED_BEACON_THRESHOLD_DEF;
1140	else
1141		priv->missed_beacon_threshold = missed;
1142
1143	return count;
1144}
1145
1146static ssize_t iwl_legacy_dbgfs_force_reset_read(struct file *file,
1147					char __user *user_buf,
1148					size_t count, loff_t *ppos) {
1149
1150	struct iwl_priv *priv = file->private_data;
1151	int pos = 0;
1152	char buf[300];
1153	const size_t bufsz = sizeof(buf);
1154	struct iwl_force_reset *force_reset;
1155
1156	force_reset = &priv->force_reset;
1157
1158	pos += scnprintf(buf + pos, bufsz - pos,
1159			"\tnumber of reset request: %d\n",
1160			force_reset->reset_request_count);
1161	pos += scnprintf(buf + pos, bufsz - pos,
1162			"\tnumber of reset request success: %d\n",
1163			force_reset->reset_success_count);
1164	pos += scnprintf(buf + pos, bufsz - pos,
1165			"\tnumber of reset request reject: %d\n",
1166			force_reset->reset_reject_count);
1167	pos += scnprintf(buf + pos, bufsz - pos,
1168			"\treset duration: %lu\n",
1169			force_reset->reset_duration);
1170
1171	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1172}
1173
1174static ssize_t iwl_legacy_dbgfs_force_reset_write(struct file *file,
1175					const char __user *user_buf,
1176					size_t count, loff_t *ppos) {
1177
1178	int ret;
1179	struct iwl_priv *priv = file->private_data;
1180
1181	ret = iwl_legacy_force_reset(priv, true);
1182
1183	return ret ? ret : count;
1184}
1185
1186static ssize_t iwl_legacy_dbgfs_wd_timeout_write(struct file *file,
1187					const char __user *user_buf,
1188					size_t count, loff_t *ppos) {
1189
1190	struct iwl_priv *priv = file->private_data;
1191	char buf[8];
1192	int buf_size;
1193	int timeout;
1194
1195	memset(buf, 0, sizeof(buf));
1196	buf_size = min(count, sizeof(buf) -  1);
1197	if (copy_from_user(buf, user_buf, buf_size))
1198		return -EFAULT;
1199	if (sscanf(buf, "%d", &timeout) != 1)
1200		return -EINVAL;
1201	if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT)
1202		timeout = IWL_DEF_WD_TIMEOUT;
1203
1204	priv->cfg->base_params->wd_timeout = timeout;
1205	iwl_legacy_setup_watchdog(priv);
1206	return count;
1207}
1208
1209DEBUGFS_READ_FILE_OPS(rx_statistics);
1210DEBUGFS_READ_FILE_OPS(tx_statistics);
1211DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
1212DEBUGFS_READ_FILE_OPS(rx_queue);
1213DEBUGFS_READ_FILE_OPS(tx_queue);
1214DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
1215DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
1216DEBUGFS_READ_FILE_OPS(ucode_general_stats);
1217DEBUGFS_READ_FILE_OPS(sensitivity);
1218DEBUGFS_READ_FILE_OPS(chain_noise);
1219DEBUGFS_READ_FILE_OPS(power_save_status);
1220DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
1221DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
1222DEBUGFS_READ_FILE_OPS(fh_reg);
1223DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
1224DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
1225DEBUGFS_READ_FILE_OPS(rxon_flags);
1226DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
1227DEBUGFS_WRITE_FILE_OPS(wd_timeout);
1228
1229/*
1230 * Create the debugfs files and directories
1231 *
1232 */
1233int iwl_legacy_dbgfs_register(struct iwl_priv *priv, const char *name)
1234{
1235	struct dentry *phyd = priv->hw->wiphy->debugfsdir;
1236	struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
1237
1238	dir_drv = debugfs_create_dir(name, phyd);
1239	if (!dir_drv)
1240		return -ENOMEM;
1241
1242	priv->debugfs_dir = dir_drv;
1243
1244	dir_data = debugfs_create_dir("data", dir_drv);
1245	if (!dir_data)
1246		goto err;
1247	dir_rf = debugfs_create_dir("rf", dir_drv);
1248	if (!dir_rf)
1249		goto err;
1250	dir_debug = debugfs_create_dir("debug", dir_drv);
1251	if (!dir_debug)
1252		goto err;
1253
1254	DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
1255	DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
1256	DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
1257	DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
1258	DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
1259	DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
1260	DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
1261	DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
1262	DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
1263	DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
1264	DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
1265	DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
1266	DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
1267	DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
1268	DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
1269	DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
1270	DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
1271	DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
1272	DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
1273	DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
1274	DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
1275	DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
1276
1277	if (priv->cfg->base_params->sensitivity_calib_by_driver)
1278		DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
1279	if (priv->cfg->base_params->chain_noise_calib_by_driver)
1280		DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
1281	DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
1282	DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
1283	DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
1284	if (priv->cfg->base_params->sensitivity_calib_by_driver)
1285		DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
1286				 &priv->disable_sens_cal);
1287	if (priv->cfg->base_params->chain_noise_calib_by_driver)
1288		DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
1289				 &priv->disable_chain_noise_cal);
1290	DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
1291				&priv->disable_tx_power_cal);
1292	return 0;
1293
1294err:
1295	IWL_ERR(priv, "Can't create the debugfs directory\n");
1296	iwl_legacy_dbgfs_unregister(priv);
1297	return -ENOMEM;
1298}
1299EXPORT_SYMBOL(iwl_legacy_dbgfs_register);
1300
1301/**
1302 * Remove the debugfs files and directories
1303 *
1304 */
1305void iwl_legacy_dbgfs_unregister(struct iwl_priv *priv)
1306{
1307	if (!priv->debugfs_dir)
1308		return;
1309
1310	debugfs_remove_recursive(priv->debugfs_dir);
1311	priv->debugfs_dir = NULL;
1312}
1313EXPORT_SYMBOL(iwl_legacy_dbgfs_unregister);