Linux Audio

Check our new training course

In-person Linux kernel drivers training

Jun 16-20, 2025
Register
Loading...
Note: File does not exist in v3.1.
   1/******************************************************************************
   2 *
   3 * This file is provided under a dual BSD/GPLv2 license.  When using or
   4 * redistributing this file, you may do so under either license.
   5 *
   6 * GPL LICENSE SUMMARY
   7 *
   8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of version 2 of the GNU General Public License as
  12 * published by the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but
  15 * WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  22 * USA
  23 *
  24 * The full GNU General Public License is included in this distribution
  25 * in the file called COPYING.
  26 *
  27 * Contact Information:
  28 *  Intel Linux Wireless <ilw@linux.intel.com>
  29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  30 *
  31 * BSD LICENSE
  32 *
  33 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  34 * All rights reserved.
  35 *
  36 * Redistribution and use in source and binary forms, with or without
  37 * modification, are permitted provided that the following conditions
  38 * are met:
  39 *
  40 *  * Redistributions of source code must retain the above copyright
  41 *    notice, this list of conditions and the following disclaimer.
  42 *  * Redistributions in binary form must reproduce the above copyright
  43 *    notice, this list of conditions and the following disclaimer in
  44 *    the documentation and/or other materials provided with the
  45 *    distribution.
  46 *  * Neither the name Intel Corporation nor the names of its
  47 *    contributors may be used to endorse or promote products derived
  48 *    from this software without specific prior written permission.
  49 *
  50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61 *
  62 *****************************************************************************/
  63#include <linux/vmalloc.h>
  64
  65#include "mvm.h"
  66#include "sta.h"
  67#include "iwl-io.h"
  68#include "iwl-prph.h"
  69#include "debugfs.h"
  70#include "fw-error-dump.h"
  71
  72static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
  73					size_t count, loff_t *ppos)
  74{
  75	int ret;
  76	u32 scd_q_msk;
  77
  78	if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
  79		return -EIO;
  80
  81	if (sscanf(buf, "%x", &scd_q_msk) != 1)
  82		return -EINVAL;
  83
  84	IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk);
  85
  86	mutex_lock(&mvm->mutex);
  87	ret =  iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count;
  88	mutex_unlock(&mvm->mutex);
  89
  90	return ret;
  91}
  92
  93static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
  94					 size_t count, loff_t *ppos)
  95{
  96	struct iwl_mvm_sta *mvmsta;
  97	int sta_id, drain, ret;
  98
  99	if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
 100		return -EIO;
 101
 102	if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
 103		return -EINVAL;
 104	if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT)
 105		return -EINVAL;
 106	if (drain < 0 || drain > 1)
 107		return -EINVAL;
 108
 109	mutex_lock(&mvm->mutex);
 110
 111	mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
 112
 113	if (!mvmsta)
 114		ret = -ENOENT;
 115	else
 116		ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count;
 117
 118	mutex_unlock(&mvm->mutex);
 119
 120	return ret;
 121}
 122
 123static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file)
 124{
 125	struct iwl_mvm *mvm = inode->i_private;
 126	int ret;
 127
 128	if (!mvm)
 129		return -EINVAL;
 130
 131	mutex_lock(&mvm->mutex);
 132	if (!mvm->fw_error_dump) {
 133		ret = -ENODATA;
 134		goto out;
 135	}
 136
 137	file->private_data = mvm->fw_error_dump;
 138	mvm->fw_error_dump = NULL;
 139	kfree(mvm->fw_error_sram);
 140	mvm->fw_error_sram = NULL;
 141	mvm->fw_error_sram_len = 0;
 142	ret = 0;
 143
 144out:
 145	mutex_unlock(&mvm->mutex);
 146	return ret;
 147}
 148
 149static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
 150					    char __user *user_buf,
 151					    size_t count, loff_t *ppos)
 152{
 153	struct iwl_fw_error_dump_file *dump_file = file->private_data;
 154
 155	return simple_read_from_buffer(user_buf, count, ppos,
 156				       dump_file,
 157				       le32_to_cpu(dump_file->file_len));
 158}
 159
 160static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
 161					   struct file *file)
 162{
 163	vfree(file->private_data);
 164
 165	return 0;
 166}
 167
 168static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
 169				   size_t count, loff_t *ppos)
 170{
 171	struct iwl_mvm *mvm = file->private_data;
 172	const struct fw_img *img;
 173	unsigned int ofs, len;
 174	size_t ret;
 175	u8 *ptr;
 176
 177	if (!mvm->ucode_loaded)
 178		return -EINVAL;
 179
 180	/* default is to dump the entire data segment */
 181	img = &mvm->fw->img[mvm->cur_ucode];
 182	ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
 183	len = img->sec[IWL_UCODE_SECTION_DATA].len;
 184
 185	if (mvm->dbgfs_sram_len) {
 186		ofs = mvm->dbgfs_sram_offset;
 187		len = mvm->dbgfs_sram_len;
 188	}
 189
 190	ptr = kzalloc(len, GFP_KERNEL);
 191	if (!ptr)
 192		return -ENOMEM;
 193
 194	iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len);
 195
 196	ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len);
 197
 198	kfree(ptr);
 199
 200	return ret;
 201}
 202
 203static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
 204				    size_t count, loff_t *ppos)
 205{
 206	const struct fw_img *img;
 207	u32 offset, len;
 208	u32 img_offset, img_len;
 209
 210	if (!mvm->ucode_loaded)
 211		return -EINVAL;
 212
 213	img = &mvm->fw->img[mvm->cur_ucode];
 214	img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset;
 215	img_len = img->sec[IWL_UCODE_SECTION_DATA].len;
 216
 217	if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
 218		if ((offset & 0x3) || (len & 0x3))
 219			return -EINVAL;
 220
 221		if (offset + len > img_offset + img_len)
 222			return -EINVAL;
 223
 224		mvm->dbgfs_sram_offset = offset;
 225		mvm->dbgfs_sram_len = len;
 226	} else {
 227		mvm->dbgfs_sram_offset = 0;
 228		mvm->dbgfs_sram_len = 0;
 229	}
 230
 231	return count;
 232}
 233
 234static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
 235				       size_t count, loff_t *ppos)
 236{
 237	struct iwl_mvm *mvm = file->private_data;
 238	struct ieee80211_sta *sta;
 239	char buf[400];
 240	int i, pos = 0, bufsz = sizeof(buf);
 241
 242	mutex_lock(&mvm->mutex);
 243
 244	for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
 245		pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
 246		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
 247						lockdep_is_held(&mvm->mutex));
 248		if (!sta)
 249			pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
 250		else if (IS_ERR(sta))
 251			pos += scnprintf(buf + pos, bufsz - pos, "%ld\n",
 252					 PTR_ERR(sta));
 253		else
 254			pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
 255					 sta->addr);
 256	}
 257
 258	mutex_unlock(&mvm->mutex);
 259
 260	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 261}
 262
 263static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
 264						char __user *user_buf,
 265						size_t count, loff_t *ppos)
 266{
 267	struct iwl_mvm *mvm = file->private_data;
 268	char buf[64];
 269	int bufsz = sizeof(buf);
 270	int pos = 0;
 271
 272	pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d0=%d\n",
 273			 mvm->disable_power_off);
 274	pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d3=%d\n",
 275			 mvm->disable_power_off_d3);
 276
 277	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 278}
 279
 280static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,
 281						 size_t count, loff_t *ppos)
 282{
 283	int ret, val;
 284
 285	if (!mvm->ucode_loaded)
 286		return -EIO;
 287
 288	if (!strncmp("disable_power_off_d0=", buf, 21)) {
 289		if (sscanf(buf + 21, "%d", &val) != 1)
 290			return -EINVAL;
 291		mvm->disable_power_off = val;
 292	} else if (!strncmp("disable_power_off_d3=", buf, 21)) {
 293		if (sscanf(buf + 21, "%d", &val) != 1)
 294			return -EINVAL;
 295		mvm->disable_power_off_d3 = val;
 296	} else {
 297		return -EINVAL;
 298	}
 299
 300	mutex_lock(&mvm->mutex);
 301	ret = iwl_mvm_power_update_device(mvm);
 302	mutex_unlock(&mvm->mutex);
 303
 304	return ret ?: count;
 305}
 306
 307#define BT_MBOX_MSG(_notif, _num, _field)				     \
 308	((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
 309	>> BT_MBOX##_num##_##_field##_POS)
 310
 311
 312#define BT_MBOX_PRINT(_num, _field, _end)				    \
 313			pos += scnprintf(buf + pos, bufsz - pos,	    \
 314					 "\t%s: %d%s",			    \
 315					 #_field,			    \
 316					 BT_MBOX_MSG(notif, _num, _field),  \
 317					 true ? "\n" : ", ");
 318
 319static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
 320				       size_t count, loff_t *ppos)
 321{
 322	struct iwl_mvm *mvm = file->private_data;
 323	struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
 324	char *buf;
 325	int ret, pos = 0, bufsz = sizeof(char) * 1024;
 326
 327	buf = kmalloc(bufsz, GFP_KERNEL);
 328	if (!buf)
 329		return -ENOMEM;
 330
 331	mutex_lock(&mvm->mutex);
 332
 333	pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
 334
 335	BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
 336	BT_MBOX_PRINT(0, LE_PROF1, false);
 337	BT_MBOX_PRINT(0, LE_PROF2, false);
 338	BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
 339	BT_MBOX_PRINT(0, CHL_SEQ_N, false);
 340	BT_MBOX_PRINT(0, INBAND_S, false);
 341	BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
 342	BT_MBOX_PRINT(0, LE_SCAN, false);
 343	BT_MBOX_PRINT(0, LE_ADV, false);
 344	BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
 345	BT_MBOX_PRINT(0, OPEN_CON_1, true);
 346
 347	pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
 348
 349	BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
 350	BT_MBOX_PRINT(1, IP_SR, false);
 351	BT_MBOX_PRINT(1, LE_MSTR, false);
 352	BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
 353	BT_MBOX_PRINT(1, MSG_TYPE, false);
 354	BT_MBOX_PRINT(1, SSN, true);
 355
 356	pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
 357
 358	BT_MBOX_PRINT(2, SNIFF_ACT, false);
 359	BT_MBOX_PRINT(2, PAG, false);
 360	BT_MBOX_PRINT(2, INQUIRY, false);
 361	BT_MBOX_PRINT(2, CONN, false);
 362	BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
 363	BT_MBOX_PRINT(2, DISC, false);
 364	BT_MBOX_PRINT(2, SCO_TX_ACT, false);
 365	BT_MBOX_PRINT(2, SCO_RX_ACT, false);
 366	BT_MBOX_PRINT(2, ESCO_RE_TX, false);
 367	BT_MBOX_PRINT(2, SCO_DURATION, true);
 368
 369	pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
 370
 371	BT_MBOX_PRINT(3, SCO_STATE, false);
 372	BT_MBOX_PRINT(3, SNIFF_STATE, false);
 373	BT_MBOX_PRINT(3, A2DP_STATE, false);
 374	BT_MBOX_PRINT(3, ACL_STATE, false);
 375	BT_MBOX_PRINT(3, MSTR_STATE, false);
 376	BT_MBOX_PRINT(3, OBX_STATE, false);
 377	BT_MBOX_PRINT(3, OPEN_CON_2, false);
 378	BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
 379	BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
 380	BT_MBOX_PRINT(3, INBAND_P, false);
 381	BT_MBOX_PRINT(3, MSG_TYPE_2, false);
 382	BT_MBOX_PRINT(3, SSN_2, false);
 383	BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
 384
 385	pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n",
 386			 notif->bt_status);
 387	pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n",
 388			 notif->bt_open_conn);
 389	pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n",
 390			 notif->bt_traffic_load);
 391	pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n",
 392			 notif->bt_agg_traffic_load);
 393	pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
 394			 notif->bt_ci_compliance);
 395	pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n",
 396			 le32_to_cpu(notif->primary_ch_lut));
 397	pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n",
 398			 le32_to_cpu(notif->secondary_ch_lut));
 399	pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n",
 400			 le32_to_cpu(notif->bt_activity_grading));
 401	pos += scnprintf(buf+pos, bufsz-pos,
 402			 "antenna isolation = %d CORUN LUT index = %d\n",
 403			 mvm->last_ant_isol, mvm->last_corun_lut);
 404
 405	mutex_unlock(&mvm->mutex);
 406
 407	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 408	kfree(buf);
 409
 410	return ret;
 411}
 412#undef BT_MBOX_PRINT
 413
 414static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
 415				     size_t count, loff_t *ppos)
 416{
 417	struct iwl_mvm *mvm = file->private_data;
 418	struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
 419	char buf[256];
 420	int bufsz = sizeof(buf);
 421	int pos = 0;
 422
 423	mutex_lock(&mvm->mutex);
 424
 425	pos += scnprintf(buf+pos, bufsz-pos, "Channel inhibition CMD\n");
 426	pos += scnprintf(buf+pos, bufsz-pos,
 427		       "\tPrimary Channel Bitmap 0x%016llx Fat: %d\n",
 428		       le64_to_cpu(cmd->bt_primary_ci),
 429		       !!cmd->co_run_bw_primary);
 430	pos += scnprintf(buf+pos, bufsz-pos,
 431		       "\tSecondary Channel Bitmap 0x%016llx Fat: %d\n",
 432		       le64_to_cpu(cmd->bt_secondary_ci),
 433		       !!cmd->co_run_bw_secondary);
 434
 435	pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n");
 436	pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n",
 437			 iwl_bt_ack_kill_msk[mvm->bt_kill_msk]);
 438	pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n",
 439			 iwl_bt_cts_kill_msk[mvm->bt_kill_msk]);
 440
 441	mutex_unlock(&mvm->mutex);
 442
 443	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 444}
 445
 446static ssize_t
 447iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf,
 448			   size_t count, loff_t *ppos)
 449{
 450	u32 bt_tx_prio;
 451
 452	if (sscanf(buf, "%u", &bt_tx_prio) != 1)
 453		return -EINVAL;
 454	if (bt_tx_prio > 4)
 455		return -EINVAL;
 456
 457	mvm->bt_tx_prio = bt_tx_prio;
 458
 459	return count;
 460}
 461
 462#define PRINT_STATS_LE32(_str, _val)					\
 463			 pos += scnprintf(buf + pos, bufsz - pos,	\
 464					  fmt_table, _str,		\
 465					  le32_to_cpu(_val))
 466
 467static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
 468					  char __user *user_buf, size_t count,
 469					  loff_t *ppos)
 470{
 471	struct iwl_mvm *mvm = file->private_data;
 472	static const char *fmt_table = "\t%-30s %10u\n";
 473	static const char *fmt_header = "%-32s\n";
 474	int pos = 0;
 475	char *buf;
 476	int ret;
 477	/* 43 is the size of each data line, 33 is the size of each header */
 478	size_t bufsz =
 479		((sizeof(struct mvm_statistics_rx) / sizeof(__le32)) * 43) +
 480		(4 * 33) + 1;
 481
 482	struct mvm_statistics_rx_phy *ofdm;
 483	struct mvm_statistics_rx_phy *cck;
 484	struct mvm_statistics_rx_non_phy *general;
 485	struct mvm_statistics_rx_ht_phy *ht;
 486
 487	buf = kzalloc(bufsz, GFP_KERNEL);
 488	if (!buf)
 489		return -ENOMEM;
 490
 491	mutex_lock(&mvm->mutex);
 492
 493	ofdm = &mvm->rx_stats.ofdm;
 494	cck = &mvm->rx_stats.cck;
 495	general = &mvm->rx_stats.general;
 496	ht = &mvm->rx_stats.ofdm_ht;
 497
 498	pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 499			 "Statistics_Rx - OFDM");
 500	PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt);
 501	PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt);
 502	PRINT_STATS_LE32("plcp_err", ofdm->plcp_err);
 503	PRINT_STATS_LE32("crc32_err", ofdm->crc32_err);
 504	PRINT_STATS_LE32("overrun_err", ofdm->overrun_err);
 505	PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err);
 506	PRINT_STATS_LE32("crc32_good", ofdm->crc32_good);
 507	PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt);
 508	PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt);
 509	PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout);
 510	PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout);
 511	PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts);
 512	PRINT_STATS_LE32("rxe_frame_lmt_overrun",
 513			 ofdm->rxe_frame_limit_overrun);
 514	PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt);
 515	PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt);
 516	PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt);
 517	PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill);
 518	PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err);
 519	PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum);
 520	PRINT_STATS_LE32("reserved", ofdm->reserved);
 521
 522	pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 523			 "Statistics_Rx - CCK");
 524	PRINT_STATS_LE32("ina_cnt", cck->ina_cnt);
 525	PRINT_STATS_LE32("fina_cnt", cck->fina_cnt);
 526	PRINT_STATS_LE32("plcp_err", cck->plcp_err);
 527	PRINT_STATS_LE32("crc32_err", cck->crc32_err);
 528	PRINT_STATS_LE32("overrun_err", cck->overrun_err);
 529	PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err);
 530	PRINT_STATS_LE32("crc32_good", cck->crc32_good);
 531	PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt);
 532	PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt);
 533	PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout);
 534	PRINT_STATS_LE32("fina_timeout", cck->fina_timeout);
 535	PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts);
 536	PRINT_STATS_LE32("rxe_frame_lmt_overrun",
 537			 cck->rxe_frame_limit_overrun);
 538	PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt);
 539	PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt);
 540	PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt);
 541	PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill);
 542	PRINT_STATS_LE32("mh_format_err", cck->mh_format_err);
 543	PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum);
 544	PRINT_STATS_LE32("reserved", cck->reserved);
 545
 546	pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 547			 "Statistics_Rx - GENERAL");
 548	PRINT_STATS_LE32("bogus_cts", general->bogus_cts);
 549	PRINT_STATS_LE32("bogus_ack", general->bogus_ack);
 550	PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames);
 551	PRINT_STATS_LE32("filtered_frames", general->filtered_frames);
 552	PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons);
 553	PRINT_STATS_LE32("channel_beacons", general->channel_beacons);
 554	PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon);
 555	PRINT_STATS_LE32("adc_rx_saturation_time",
 556			 general->adc_rx_saturation_time);
 557	PRINT_STATS_LE32("ina_detection_search_time",
 558			 general->ina_detection_search_time);
 559	PRINT_STATS_LE32("beacon_silence_rssi_a",
 560			 general->beacon_silence_rssi_a);
 561	PRINT_STATS_LE32("beacon_silence_rssi_b",
 562			 general->beacon_silence_rssi_b);
 563	PRINT_STATS_LE32("beacon_silence_rssi_c",
 564			 general->beacon_silence_rssi_c);
 565	PRINT_STATS_LE32("interference_data_flag",
 566			 general->interference_data_flag);
 567	PRINT_STATS_LE32("channel_load", general->channel_load);
 568	PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms);
 569	PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a);
 570	PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b);
 571	PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c);
 572	PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a);
 573	PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b);
 574	PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c);
 575	PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills);
 576	PRINT_STATS_LE32("mac_id", general->mac_id);
 577	PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu);
 578
 579	pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
 580			 "Statistics_Rx - HT");
 581	PRINT_STATS_LE32("plcp_err", ht->plcp_err);
 582	PRINT_STATS_LE32("overrun_err", ht->overrun_err);
 583	PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err);
 584	PRINT_STATS_LE32("crc32_good", ht->crc32_good);
 585	PRINT_STATS_LE32("crc32_err", ht->crc32_err);
 586	PRINT_STATS_LE32("mh_format_err", ht->mh_format_err);
 587	PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good);
 588	PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt);
 589	PRINT_STATS_LE32("agg_cnt", ht->agg_cnt);
 590	PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs);
 591
 592	mutex_unlock(&mvm->mutex);
 593
 594	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 595	kfree(buf);
 596
 597	return ret;
 598}
 599#undef PRINT_STAT_LE32
 600
 601static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
 602					  char __user *user_buf, size_t count,
 603					  loff_t *ppos,
 604					  struct iwl_mvm_frame_stats *stats)
 605{
 606	char *buff, *pos, *endpos;
 607	int idx, i;
 608	int ret;
 609	static const size_t bufsz = 1024;
 610
 611	buff = kmalloc(bufsz, GFP_KERNEL);
 612	if (!buff)
 613		return -ENOMEM;
 614
 615	spin_lock_bh(&mvm->drv_stats_lock);
 616
 617	pos = buff;
 618	endpos = pos + bufsz;
 619
 620	pos += scnprintf(pos, endpos - pos,
 621			 "Legacy/HT/VHT\t:\t%d/%d/%d\n",
 622			 stats->legacy_frames,
 623			 stats->ht_frames,
 624			 stats->vht_frames);
 625	pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n",
 626			 stats->bw_20_frames,
 627			 stats->bw_40_frames,
 628			 stats->bw_80_frames);
 629	pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n",
 630			 stats->ngi_frames,
 631			 stats->sgi_frames);
 632	pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n",
 633			 stats->siso_frames,
 634			 stats->mimo2_frames);
 635	pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n",
 636			 stats->fail_frames,
 637			 stats->success_frames);
 638	pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n",
 639			 stats->agg_frames);
 640	pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n",
 641			 stats->ampdu_count);
 642	pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n",
 643			 stats->ampdu_count > 0 ?
 644			 (stats->agg_frames / stats->ampdu_count) : 0);
 645
 646	pos += scnprintf(pos, endpos - pos, "Last Rates\n");
 647
 648	idx = stats->last_frame_idx - 1;
 649	for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) {
 650		idx = (idx + 1) % ARRAY_SIZE(stats->last_rates);
 651		if (stats->last_rates[idx] == 0)
 652			continue;
 653		pos += scnprintf(pos, endpos - pos, "Rate[%d]: ",
 654				 (int)(ARRAY_SIZE(stats->last_rates) - i));
 655		pos += rs_pretty_print_rate(pos, stats->last_rates[idx]);
 656	}
 657	spin_unlock_bh(&mvm->drv_stats_lock);
 658
 659	ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
 660	kfree(buff);
 661
 662	return ret;
 663}
 664
 665static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file,
 666					   char __user *user_buf, size_t count,
 667					   loff_t *ppos)
 668{
 669	struct iwl_mvm *mvm = file->private_data;
 670
 671	return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos,
 672					  &mvm->drv_rx_stats);
 673}
 674
 675static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
 676					  size_t count, loff_t *ppos)
 677{
 678	int ret;
 679
 680	mutex_lock(&mvm->mutex);
 681
 682	/* allow one more restart that we're provoking here */
 683	if (mvm->restart_fw >= 0)
 684		mvm->restart_fw++;
 685
 686	/* take the return value to make compiler happy - it will fail anyway */
 687	ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL);
 688
 689	mutex_unlock(&mvm->mutex);
 690
 691	return count;
 692}
 693
 694static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
 695				      size_t count, loff_t *ppos)
 696{
 697	iwl_write_prph(mvm->trans, DEVICE_SET_NMI_REG, 1);
 698
 699	return count;
 700}
 701
 702static ssize_t
 703iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
 704				char __user *user_buf,
 705				size_t count, loff_t *ppos)
 706{
 707	struct iwl_mvm *mvm = file->private_data;
 708	int pos = 0;
 709	char buf[32];
 710	const size_t bufsz = sizeof(buf);
 711
 712	/* print which antennas were set for the scan command by the user */
 713	pos += scnprintf(buf + pos, bufsz - pos, "Antennas for scan: ");
 714	if (mvm->scan_rx_ant & ANT_A)
 715		pos += scnprintf(buf + pos, bufsz - pos, "A");
 716	if (mvm->scan_rx_ant & ANT_B)
 717		pos += scnprintf(buf + pos, bufsz - pos, "B");
 718	if (mvm->scan_rx_ant & ANT_C)
 719		pos += scnprintf(buf + pos, bufsz - pos, "C");
 720	pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant);
 721
 722	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 723}
 724
 725static ssize_t
 726iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
 727				 size_t count, loff_t *ppos)
 728{
 729	u8 scan_rx_ant;
 730
 731	if (sscanf(buf, "%hhx", &scan_rx_ant) != 1)
 732		return -EINVAL;
 733	if (scan_rx_ant > ANT_ABC)
 734		return -EINVAL;
 735	if (scan_rx_ant & ~mvm->fw->valid_rx_ant)
 736		return -EINVAL;
 737
 738	mvm->scan_rx_ant = scan_rx_ant;
 739
 740	return count;
 741}
 742
 743#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
 744#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 745static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
 746					    char __user *user_buf,
 747					    size_t count, loff_t *ppos)
 748{
 749	struct iwl_mvm *mvm = file->private_data;
 750	struct iwl_bcast_filter_cmd cmd;
 751	const struct iwl_fw_bcast_filter *filter;
 752	char *buf;
 753	int bufsz = 1024;
 754	int i, j, pos = 0;
 755	ssize_t ret;
 756
 757	buf = kzalloc(bufsz, GFP_KERNEL);
 758	if (!buf)
 759		return -ENOMEM;
 760
 761	mutex_lock(&mvm->mutex);
 762	if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
 763		ADD_TEXT("None\n");
 764		mutex_unlock(&mvm->mutex);
 765		goto out;
 766	}
 767	mutex_unlock(&mvm->mutex);
 768
 769	for (i = 0; cmd.filters[i].attrs[0].mask; i++) {
 770		filter = &cmd.filters[i];
 771
 772		ADD_TEXT("Filter [%d]:\n", i);
 773		ADD_TEXT("\tDiscard=%d\n", filter->discard);
 774		ADD_TEXT("\tFrame Type: %s\n",
 775			 filter->frame_type ? "IPv4" : "Generic");
 776
 777		for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) {
 778			const struct iwl_fw_bcast_filter_attr *attr;
 779
 780			attr = &filter->attrs[j];
 781			if (!attr->mask)
 782				break;
 783
 784			ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n",
 785				 j, attr->offset,
 786				 attr->offset_type ? "IP End" :
 787						     "Payload Start",
 788				 be32_to_cpu(attr->mask),
 789				 be32_to_cpu(attr->val),
 790				 le16_to_cpu(attr->reserved1));
 791		}
 792	}
 793out:
 794	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 795	kfree(buf);
 796	return ret;
 797}
 798
 799static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf,
 800					     size_t count, loff_t *ppos)
 801{
 802	int pos, next_pos;
 803	struct iwl_fw_bcast_filter filter = {};
 804	struct iwl_bcast_filter_cmd cmd;
 805	u32 filter_id, attr_id, mask, value;
 806	int err = 0;
 807
 808	if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard,
 809		   &filter.frame_type, &pos) != 3)
 810		return -EINVAL;
 811
 812	if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) ||
 813	    filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4)
 814		return -EINVAL;
 815
 816	for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs);
 817	     attr_id++) {
 818		struct iwl_fw_bcast_filter_attr *attr =
 819				&filter.attrs[attr_id];
 820
 821		if (pos >= count)
 822			break;
 823
 824		if (sscanf(&buf[pos], "%hhi %hhi %i %i %n",
 825			   &attr->offset, &attr->offset_type,
 826			   &mask, &value, &next_pos) != 4)
 827			return -EINVAL;
 828
 829		attr->mask = cpu_to_be32(mask);
 830		attr->val = cpu_to_be32(value);
 831		if (mask)
 832			filter.num_attrs++;
 833
 834		pos += next_pos;
 835	}
 836
 837	mutex_lock(&mvm->mutex);
 838	memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id],
 839	       &filter, sizeof(filter));
 840
 841	/* send updated bcast filtering configuration */
 842	if (mvm->dbgfs_bcast_filtering.override &&
 843	    iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
 844		err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC,
 845					   sizeof(cmd), &cmd);
 846	mutex_unlock(&mvm->mutex);
 847
 848	return err ?: count;
 849}
 850
 851static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file,
 852						 char __user *user_buf,
 853						 size_t count, loff_t *ppos)
 854{
 855	struct iwl_mvm *mvm = file->private_data;
 856	struct iwl_bcast_filter_cmd cmd;
 857	char *buf;
 858	int bufsz = 1024;
 859	int i, pos = 0;
 860	ssize_t ret;
 861
 862	buf = kzalloc(bufsz, GFP_KERNEL);
 863	if (!buf)
 864		return -ENOMEM;
 865
 866	mutex_lock(&mvm->mutex);
 867	if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
 868		ADD_TEXT("None\n");
 869		mutex_unlock(&mvm->mutex);
 870		goto out;
 871	}
 872	mutex_unlock(&mvm->mutex);
 873
 874	for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) {
 875		const struct iwl_fw_bcast_mac *mac = &cmd.macs[i];
 876
 877		ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n",
 878			 i, mac->default_discard, mac->attached_filters);
 879	}
 880out:
 881	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 882	kfree(buf);
 883	return ret;
 884}
 885
 886static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
 887						  char *buf, size_t count,
 888						  loff_t *ppos)
 889{
 890	struct iwl_bcast_filter_cmd cmd;
 891	struct iwl_fw_bcast_mac mac = {};
 892	u32 mac_id, attached_filters;
 893	int err = 0;
 894
 895	if (!mvm->bcast_filters)
 896		return -ENOENT;
 897
 898	if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard,
 899		   &attached_filters) != 3)
 900		return -EINVAL;
 901
 902	if (mac_id >= ARRAY_SIZE(cmd.macs) ||
 903	    mac.default_discard > 1 ||
 904	    attached_filters >= BIT(ARRAY_SIZE(cmd.filters)))
 905		return -EINVAL;
 906
 907	mac.attached_filters = cpu_to_le16(attached_filters);
 908
 909	mutex_lock(&mvm->mutex);
 910	memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id],
 911	       &mac, sizeof(mac));
 912
 913	/* send updated bcast filtering configuration */
 914	if (mvm->dbgfs_bcast_filtering.override &&
 915	    iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
 916		err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC,
 917					   sizeof(cmd), &cmd);
 918	mutex_unlock(&mvm->mutex);
 919
 920	return err ?: count;
 921}
 922#endif
 923
 924#ifdef CONFIG_PM_SLEEP
 925static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf,
 926				       size_t count, loff_t *ppos)
 927{
 928	int store;
 929
 930	if (sscanf(buf, "%d", &store) != 1)
 931		return -EINVAL;
 932
 933	mvm->store_d3_resume_sram = store;
 934
 935	return count;
 936}
 937
 938static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
 939				      size_t count, loff_t *ppos)
 940{
 941	struct iwl_mvm *mvm = file->private_data;
 942	const struct fw_img *img;
 943	int ofs, len, pos = 0;
 944	size_t bufsz, ret;
 945	char *buf;
 946	u8 *ptr = mvm->d3_resume_sram;
 947
 948	img = &mvm->fw->img[IWL_UCODE_WOWLAN];
 949	len = img->sec[IWL_UCODE_SECTION_DATA].len;
 950
 951	bufsz = len * 4 + 256;
 952	buf = kzalloc(bufsz, GFP_KERNEL);
 953	if (!buf)
 954		return -ENOMEM;
 955
 956	pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n",
 957			 mvm->store_d3_resume_sram ? "en" : "dis");
 958
 959	if (ptr) {
 960		for (ofs = 0; ofs < len; ofs += 16) {
 961			pos += scnprintf(buf + pos, bufsz - pos,
 962					 "0x%.4x ", ofs);
 963			hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
 964					   bufsz - pos, false);
 965			pos += strlen(buf + pos);
 966			if (bufsz - pos > 0)
 967				buf[pos++] = '\n';
 968		}
 969	} else {
 970		pos += scnprintf(buf + pos, bufsz - pos,
 971				 "(no data captured)\n");
 972	}
 973
 974	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 975
 976	kfree(buf);
 977
 978	return ret;
 979}
 980#endif
 981
 982#define PRINT_MVM_REF(ref) do {					\
 983	if (test_bit(ref, mvm->ref_bitmap))			\
 984		pos += scnprintf(buf + pos, bufsz - pos,	\
 985				 "\t(0x%lx) %s\n",		\
 986				 BIT(ref), #ref);		\
 987} while (0)
 988
 989static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
 990					char __user *user_buf,
 991					size_t count, loff_t *ppos)
 992{
 993	struct iwl_mvm *mvm = file->private_data;
 994	int pos = 0;
 995	char buf[256];
 996	const size_t bufsz = sizeof(buf);
 997
 998	pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n",
 999			 mvm->ref_bitmap[0]);
1000
1001	PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
1002	PRINT_MVM_REF(IWL_MVM_REF_SCAN);
1003	PRINT_MVM_REF(IWL_MVM_REF_ROC);
1004	PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
1005	PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
1006	PRINT_MVM_REF(IWL_MVM_REF_USER);
1007
1008	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1009}
1010
1011static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
1012					 size_t count, loff_t *ppos)
1013{
1014	unsigned long value;
1015	int ret;
1016	bool taken;
1017
1018	ret = kstrtoul(buf, 10, &value);
1019	if (ret < 0)
1020		return ret;
1021
1022	mutex_lock(&mvm->mutex);
1023
1024	taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap);
1025	if (value == 1 && !taken)
1026		iwl_mvm_ref(mvm, IWL_MVM_REF_USER);
1027	else if (value == 0 && taken)
1028		iwl_mvm_unref(mvm, IWL_MVM_REF_USER);
1029	else
1030		ret = -EINVAL;
1031
1032	mutex_unlock(&mvm->mutex);
1033
1034	if (ret < 0)
1035		return ret;
1036	return count;
1037}
1038
1039#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1040	_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
1041#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1042	_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
1043#define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do {	\
1044		if (!debugfs_create_file(alias, mode, parent, mvm,	\
1045					 &iwl_dbgfs_##name##_ops))	\
1046			goto err;					\
1047	} while (0)
1048#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
1049	MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
1050
1051static ssize_t
1052iwl_dbgfs_prph_reg_read(struct file *file,
1053			char __user *user_buf,
1054			size_t count, loff_t *ppos)
1055{
1056	struct iwl_mvm *mvm = file->private_data;
1057	int pos = 0;
1058	char buf[32];
1059	const size_t bufsz = sizeof(buf);
1060
1061	if (!mvm->dbgfs_prph_reg_addr)
1062		return -EINVAL;
1063
1064	pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
1065		mvm->dbgfs_prph_reg_addr,
1066		iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
1067
1068	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1069}
1070
1071static ssize_t
1072iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
1073			 size_t count, loff_t *ppos)
1074{
1075	u8 args;
1076	u32 value;
1077
1078	args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
1079	/* if we only want to set the reg address - nothing more to do */
1080	if (args == 1)
1081		goto out;
1082
1083	/* otherwise, make sure we have both address and value */
1084	if (args != 2)
1085		return -EINVAL;
1086
1087	iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
1088out:
1089	return count;
1090}
1091
1092MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
1093
1094/* Device wide debugfs entries */
1095MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
1096MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
1097MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
1098MVM_DEBUGFS_READ_FILE_OPS(stations);
1099MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
1100MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
1101MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
1102MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
1103MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
1104MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
1105MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
1106MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
1107MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
1108MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
1109
1110static const struct file_operations iwl_dbgfs_fw_error_dump_ops = {
1111        .open = iwl_dbgfs_fw_error_dump_open,
1112        .read = iwl_dbgfs_fw_error_dump_read,
1113        .release = iwl_dbgfs_fw_error_dump_release,
1114};
1115
1116#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1117MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
1118MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
1119#endif
1120
1121#ifdef CONFIG_PM_SLEEP
1122MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
1123#endif
1124
1125int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
1126{
1127	struct dentry *bcast_dir __maybe_unused;
1128	char buf[100];
1129
1130	spin_lock_init(&mvm->drv_stats_lock);
1131
1132	mvm->debugfs_dir = dbgfs_dir;
1133
1134	MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
1135	MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
1136	MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
1137	MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
1138	MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
1139	MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
1140	MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
1141	if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)
1142		MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
1143				     S_IRUSR | S_IWUSR);
1144	MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
1145	MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
1146	MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
1147	MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
1148	MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR);
1149	MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
1150			     S_IWUSR | S_IRUSR);
1151	MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
1152	MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
1153
1154#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1155	if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
1156		bcast_dir = debugfs_create_dir("bcast_filtering",
1157					       mvm->debugfs_dir);
1158		if (!bcast_dir)
1159			goto err;
1160
1161		if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR,
1162				bcast_dir,
1163				&mvm->dbgfs_bcast_filtering.override))
1164			goto err;
1165
1166		MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters,
1167					   bcast_dir, S_IWUSR | S_IRUSR);
1168		MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs,
1169					   bcast_dir, S_IWUSR | S_IRUSR);
1170	}
1171#endif
1172
1173#ifdef CONFIG_PM_SLEEP
1174	MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
1175	MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
1176	if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
1177				 mvm->debugfs_dir, &mvm->d3_wake_sysassert))
1178		goto err;
1179#endif
1180
1181	if (!debugfs_create_blob("nvm_hw", S_IRUSR,
1182				  mvm->debugfs_dir, &mvm->nvm_hw_blob))
1183		goto err;
1184	if (!debugfs_create_blob("nvm_sw", S_IRUSR,
1185				  mvm->debugfs_dir, &mvm->nvm_sw_blob))
1186		goto err;
1187	if (!debugfs_create_blob("nvm_calib", S_IRUSR,
1188				  mvm->debugfs_dir, &mvm->nvm_calib_blob))
1189		goto err;
1190	if (!debugfs_create_blob("nvm_prod", S_IRUSR,
1191				  mvm->debugfs_dir, &mvm->nvm_prod_blob))
1192		goto err;
1193
1194	/*
1195	 * Create a symlink with mac80211. It will be removed when mac80211
1196	 * exists (before the opmode exists which removes the target.)
1197	 */
1198	snprintf(buf, 100, "../../%s/%s",
1199		 dbgfs_dir->d_parent->d_parent->d_name.name,
1200		 dbgfs_dir->d_parent->d_name.name);
1201	if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
1202		goto err;
1203
1204	return 0;
1205err:
1206	IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
1207	return -ENOMEM;
1208}