[go: nahoru, domu]

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