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 - 2015 Intel Mobile Communications GmbH
10  * Copyright(c) 2016        Intel Deutschland GmbH
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of version 2 of the GNU General Public License as
14  * published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
24  * USA
25  *
26  * The full GNU General Public License is included in this distribution
27  * in the file called COPYING.
28  *
29  * Contact Information:
30  *  Intel Linux Wireless <linuxwifi@intel.com>
31  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
32  *
33  * BSD LICENSE
34  *
35  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
36  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
37  * Copyright(c) 2016        Intel Deutschland GmbH
38  * All rights reserved.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  *
44  *  * Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  *  * Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in
48  *    the documentation and/or other materials provided with the
49  *    distribution.
50  *  * Neither the name Intel Corporation nor the names of its
51  *    contributors may be used to endorse or promote products derived
52  *    from this software without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
55  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
56  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
57  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
58  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
60  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
61  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
62  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
64  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65  *
66  *****************************************************************************/
67 #include "mvm.h"
68 #include "fw-api-tof.h"
69 #include "debugfs.h"
70 
71 static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
72 				 struct ieee80211_vif *vif,
73 				 enum iwl_dbgfs_pm_mask param, int val)
74 {
75 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
76 	struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
77 
78 	dbgfs_pm->mask |= param;
79 
80 	switch (param) {
81 	case MVM_DEBUGFS_PM_KEEP_ALIVE: {
82 		int dtimper = vif->bss_conf.dtim_period ?: 1;
83 		int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
84 
85 		IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
86 		if (val * MSEC_PER_SEC < 3 * dtimper_msec)
87 			IWL_WARN(mvm,
88 				 "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
89 				 val * MSEC_PER_SEC, 3 * dtimper_msec);
90 		dbgfs_pm->keep_alive_seconds = val;
91 		break;
92 	}
93 	case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
94 		IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
95 				val ? "enabled" : "disabled");
96 		dbgfs_pm->skip_over_dtim = val;
97 		break;
98 	case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
99 		IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
100 		dbgfs_pm->skip_dtim_periods = val;
101 		break;
102 	case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
103 		IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
104 		dbgfs_pm->rx_data_timeout = val;
105 		break;
106 	case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
107 		IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
108 		dbgfs_pm->tx_data_timeout = val;
109 		break;
110 	case MVM_DEBUGFS_PM_LPRX_ENA:
111 		IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
112 		dbgfs_pm->lprx_ena = val;
113 		break;
114 	case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
115 		IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
116 		dbgfs_pm->lprx_rssi_threshold = val;
117 		break;
118 	case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
119 		IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
120 		dbgfs_pm->snooze_ena = val;
121 		break;
122 	case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
123 		IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
124 		dbgfs_pm->uapsd_misbehaving = val;
125 		break;
126 	case MVM_DEBUGFS_PM_USE_PS_POLL:
127 		IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val);
128 		dbgfs_pm->use_ps_poll = val;
129 		break;
130 	}
131 }
132 
133 static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
134 					 size_t count, loff_t *ppos)
135 {
136 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
137 	struct iwl_mvm *mvm = mvmvif->mvm;
138 	enum iwl_dbgfs_pm_mask param;
139 	int val, ret;
140 
141 	if (!strncmp("keep_alive=", buf, 11)) {
142 		if (sscanf(buf + 11, "%d", &val) != 1)
143 			return -EINVAL;
144 		param = MVM_DEBUGFS_PM_KEEP_ALIVE;
145 	} else if (!strncmp("skip_over_dtim=", buf, 15)) {
146 		if (sscanf(buf + 15, "%d", &val) != 1)
147 			return -EINVAL;
148 		param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
149 	} else if (!strncmp("skip_dtim_periods=", buf, 18)) {
150 		if (sscanf(buf + 18, "%d", &val) != 1)
151 			return -EINVAL;
152 		param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
153 	} else if (!strncmp("rx_data_timeout=", buf, 16)) {
154 		if (sscanf(buf + 16, "%d", &val) != 1)
155 			return -EINVAL;
156 		param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
157 	} else if (!strncmp("tx_data_timeout=", buf, 16)) {
158 		if (sscanf(buf + 16, "%d", &val) != 1)
159 			return -EINVAL;
160 		param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
161 	} else if (!strncmp("lprx=", buf, 5)) {
162 		if (sscanf(buf + 5, "%d", &val) != 1)
163 			return -EINVAL;
164 		param = MVM_DEBUGFS_PM_LPRX_ENA;
165 	} else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
166 		if (sscanf(buf + 20, "%d", &val) != 1)
167 			return -EINVAL;
168 		if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
169 		    POWER_LPRX_RSSI_THRESHOLD_MIN)
170 			return -EINVAL;
171 		param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
172 	} else if (!strncmp("snooze_enable=", buf, 14)) {
173 		if (sscanf(buf + 14, "%d", &val) != 1)
174 			return -EINVAL;
175 		param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
176 	} else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
177 		if (sscanf(buf + 18, "%d", &val) != 1)
178 			return -EINVAL;
179 		param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
180 	} else if (!strncmp("use_ps_poll=", buf, 12)) {
181 		if (sscanf(buf + 12, "%d", &val) != 1)
182 			return -EINVAL;
183 		param = MVM_DEBUGFS_PM_USE_PS_POLL;
184 	} else {
185 		return -EINVAL;
186 	}
187 
188 	mutex_lock(&mvm->mutex);
189 	iwl_dbgfs_update_pm(mvm, vif, param, val);
190 	ret = iwl_mvm_power_update_mac(mvm);
191 	mutex_unlock(&mvm->mutex);
192 
193 	return ret ?: count;
194 }
195 
196 static ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file,
197 					 char __user *user_buf,
198 					 size_t count, loff_t *ppos)
199 {
200 	struct ieee80211_vif *vif = file->private_data;
201 	char buf[64];
202 	int bufsz = sizeof(buf);
203 	int pos;
204 
205 	pos = scnprintf(buf, bufsz, "bss limit = %d\n",
206 			vif->bss_conf.txpower);
207 
208 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
209 }
210 
211 static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
212 					char __user *user_buf,
213 					size_t count, loff_t *ppos)
214 {
215 	struct ieee80211_vif *vif = file->private_data;
216 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
217 	struct iwl_mvm *mvm = mvmvif->mvm;
218 	char buf[512];
219 	int bufsz = sizeof(buf);
220 	int pos;
221 
222 	pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz);
223 
224 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
225 }
226 
227 static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
228 					 char __user *user_buf,
229 					 size_t count, loff_t *ppos)
230 {
231 	struct ieee80211_vif *vif = file->private_data;
232 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
233 	struct iwl_mvm *mvm = mvmvif->mvm;
234 	u8 ap_sta_id;
235 	struct ieee80211_chanctx_conf *chanctx_conf;
236 	char buf[512];
237 	int bufsz = sizeof(buf);
238 	int pos = 0;
239 	int i;
240 
241 	mutex_lock(&mvm->mutex);
242 
243 	ap_sta_id = mvmvif->ap_sta_id;
244 
245 	switch (ieee80211_vif_type_p2p(vif)) {
246 	case NL80211_IFTYPE_ADHOC:
247 		pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n");
248 		break;
249 	case NL80211_IFTYPE_STATION:
250 		pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n");
251 		break;
252 	case NL80211_IFTYPE_AP:
253 		pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n");
254 		break;
255 	case NL80211_IFTYPE_P2P_CLIENT:
256 		pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n");
257 		break;
258 	case NL80211_IFTYPE_P2P_GO:
259 		pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n");
260 		break;
261 	case NL80211_IFTYPE_P2P_DEVICE:
262 		pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n");
263 		break;
264 	default:
265 		break;
266 	}
267 
268 	pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
269 			 mvmvif->id, mvmvif->color);
270 	pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
271 			 vif->bss_conf.bssid);
272 	pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
273 	for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++)
274 		pos += scnprintf(buf+pos, bufsz-pos,
275 				 "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
276 				 i, mvmvif->queue_params[i].txop,
277 				 mvmvif->queue_params[i].cw_min,
278 				 mvmvif->queue_params[i].cw_max,
279 				 mvmvif->queue_params[i].aifs,
280 				 mvmvif->queue_params[i].uapsd);
281 
282 	if (vif->type == NL80211_IFTYPE_STATION &&
283 	    ap_sta_id != IWL_MVM_STATION_COUNT) {
284 		struct iwl_mvm_sta *mvm_sta;
285 
286 		mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id);
287 		if (mvm_sta) {
288 			pos += scnprintf(buf+pos, bufsz-pos,
289 					 "ap_sta_id %d - reduced Tx power %d\n",
290 					 ap_sta_id,
291 					 mvm_sta->bt_reduced_txpower);
292 		}
293 	}
294 
295 	rcu_read_lock();
296 	chanctx_conf = rcu_dereference(vif->chanctx_conf);
297 	if (chanctx_conf)
298 		pos += scnprintf(buf+pos, bufsz-pos,
299 				 "idle rx chains %d, active rx chains: %d\n",
300 				 chanctx_conf->rx_chains_static,
301 				 chanctx_conf->rx_chains_dynamic);
302 	rcu_read_unlock();
303 
304 	mutex_unlock(&mvm->mutex);
305 
306 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
307 }
308 
309 static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
310 				enum iwl_dbgfs_bf_mask param, int value)
311 {
312 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
313 	struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
314 
315 	dbgfs_bf->mask |= param;
316 
317 	switch (param) {
318 	case MVM_DEBUGFS_BF_ENERGY_DELTA:
319 		dbgfs_bf->bf_energy_delta = value;
320 		break;
321 	case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
322 		dbgfs_bf->bf_roaming_energy_delta = value;
323 		break;
324 	case MVM_DEBUGFS_BF_ROAMING_STATE:
325 		dbgfs_bf->bf_roaming_state = value;
326 		break;
327 	case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
328 		dbgfs_bf->bf_temp_threshold = value;
329 		break;
330 	case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
331 		dbgfs_bf->bf_temp_fast_filter = value;
332 		break;
333 	case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
334 		dbgfs_bf->bf_temp_slow_filter = value;
335 		break;
336 	case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
337 		dbgfs_bf->bf_enable_beacon_filter = value;
338 		break;
339 	case MVM_DEBUGFS_BF_DEBUG_FLAG:
340 		dbgfs_bf->bf_debug_flag = value;
341 		break;
342 	case MVM_DEBUGFS_BF_ESCAPE_TIMER:
343 		dbgfs_bf->bf_escape_timer = value;
344 		break;
345 	case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
346 		dbgfs_bf->ba_enable_beacon_abort = value;
347 		break;
348 	case MVM_DEBUGFS_BA_ESCAPE_TIMER:
349 		dbgfs_bf->ba_escape_timer = value;
350 		break;
351 	}
352 }
353 
354 static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
355 					 size_t count, loff_t *ppos)
356 {
357 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
358 	struct iwl_mvm *mvm = mvmvif->mvm;
359 	enum iwl_dbgfs_bf_mask param;
360 	int value, ret = 0;
361 
362 	if (!strncmp("bf_energy_delta=", buf, 16)) {
363 		if (sscanf(buf+16, "%d", &value) != 1)
364 			return -EINVAL;
365 		if (value < IWL_BF_ENERGY_DELTA_MIN ||
366 		    value > IWL_BF_ENERGY_DELTA_MAX)
367 			return -EINVAL;
368 		param = MVM_DEBUGFS_BF_ENERGY_DELTA;
369 	} else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
370 		if (sscanf(buf+24, "%d", &value) != 1)
371 			return -EINVAL;
372 		if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
373 		    value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
374 			return -EINVAL;
375 		param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
376 	} else if (!strncmp("bf_roaming_state=", buf, 17)) {
377 		if (sscanf(buf+17, "%d", &value) != 1)
378 			return -EINVAL;
379 		if (value < IWL_BF_ROAMING_STATE_MIN ||
380 		    value > IWL_BF_ROAMING_STATE_MAX)
381 			return -EINVAL;
382 		param = MVM_DEBUGFS_BF_ROAMING_STATE;
383 	} else if (!strncmp("bf_temp_threshold=", buf, 18)) {
384 		if (sscanf(buf+18, "%d", &value) != 1)
385 			return -EINVAL;
386 		if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
387 		    value > IWL_BF_TEMP_THRESHOLD_MAX)
388 			return -EINVAL;
389 		param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
390 	} else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
391 		if (sscanf(buf+20, "%d", &value) != 1)
392 			return -EINVAL;
393 		if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
394 		    value > IWL_BF_TEMP_FAST_FILTER_MAX)
395 			return -EINVAL;
396 		param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
397 	} else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
398 		if (sscanf(buf+20, "%d", &value) != 1)
399 			return -EINVAL;
400 		if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
401 		    value > IWL_BF_TEMP_SLOW_FILTER_MAX)
402 			return -EINVAL;
403 		param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
404 	} else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
405 		if (sscanf(buf+24, "%d", &value) != 1)
406 			return -EINVAL;
407 		if (value < 0 || value > 1)
408 			return -EINVAL;
409 		param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
410 	} else if (!strncmp("bf_debug_flag=", buf, 14)) {
411 		if (sscanf(buf+14, "%d", &value) != 1)
412 			return -EINVAL;
413 		if (value < 0 || value > 1)
414 			return -EINVAL;
415 		param = MVM_DEBUGFS_BF_DEBUG_FLAG;
416 	} else if (!strncmp("bf_escape_timer=", buf, 16)) {
417 		if (sscanf(buf+16, "%d", &value) != 1)
418 			return -EINVAL;
419 		if (value < IWL_BF_ESCAPE_TIMER_MIN ||
420 		    value > IWL_BF_ESCAPE_TIMER_MAX)
421 			return -EINVAL;
422 		param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
423 	} else if (!strncmp("ba_escape_timer=", buf, 16)) {
424 		if (sscanf(buf+16, "%d", &value) != 1)
425 			return -EINVAL;
426 		if (value < IWL_BA_ESCAPE_TIMER_MIN ||
427 		    value > IWL_BA_ESCAPE_TIMER_MAX)
428 			return -EINVAL;
429 		param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
430 	} else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
431 		if (sscanf(buf+23, "%d", &value) != 1)
432 			return -EINVAL;
433 		if (value < 0 || value > 1)
434 			return -EINVAL;
435 		param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
436 	} else {
437 		return -EINVAL;
438 	}
439 
440 	mutex_lock(&mvm->mutex);
441 	iwl_dbgfs_update_bf(vif, param, value);
442 	if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
443 		ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
444 	else
445 		ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0);
446 	mutex_unlock(&mvm->mutex);
447 
448 	return ret ?: count;
449 }
450 
451 static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
452 					char __user *user_buf,
453 					size_t count, loff_t *ppos)
454 {
455 	struct ieee80211_vif *vif = file->private_data;
456 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
457 	char buf[256];
458 	int pos = 0;
459 	const size_t bufsz = sizeof(buf);
460 	struct iwl_beacon_filter_cmd cmd = {
461 		IWL_BF_CMD_CONFIG_DEFAULTS,
462 		.bf_enable_beacon_filter =
463 			cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
464 		.ba_enable_beacon_abort =
465 			cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
466 	};
467 
468 	iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
469 	if (mvmvif->bf_data.bf_enabled)
470 		cmd.bf_enable_beacon_filter = cpu_to_le32(1);
471 	else
472 		cmd.bf_enable_beacon_filter = 0;
473 
474 	pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
475 			 le32_to_cpu(cmd.bf_energy_delta));
476 	pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
477 			 le32_to_cpu(cmd.bf_roaming_energy_delta));
478 	pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
479 			 le32_to_cpu(cmd.bf_roaming_state));
480 	pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
481 			 le32_to_cpu(cmd.bf_temp_threshold));
482 	pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
483 			 le32_to_cpu(cmd.bf_temp_fast_filter));
484 	pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
485 			 le32_to_cpu(cmd.bf_temp_slow_filter));
486 	pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
487 			 le32_to_cpu(cmd.bf_enable_beacon_filter));
488 	pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
489 			 le32_to_cpu(cmd.bf_debug_flag));
490 	pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
491 			 le32_to_cpu(cmd.bf_escape_timer));
492 	pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
493 			 le32_to_cpu(cmd.ba_escape_timer));
494 	pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
495 			 le32_to_cpu(cmd.ba_enable_beacon_abort));
496 
497 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
498 }
499 
500 static inline char *iwl_dbgfs_is_match(char *name, char *buf)
501 {
502 	int len = strlen(name);
503 
504 	return !strncmp(name, buf, len) ? buf + len : NULL;
505 }
506 
507 static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
508 					  char *buf,
509 					  size_t count, loff_t *ppos)
510 {
511 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
512 	struct iwl_mvm *mvm = mvmvif->mvm;
513 	u32 value;
514 	int ret = -EINVAL;
515 	char *data;
516 
517 	mutex_lock(&mvm->mutex);
518 
519 	data = iwl_dbgfs_is_match("tof_disabled=", buf);
520 	if (data) {
521 		ret = kstrtou32(data, 10, &value);
522 		if (ret == 0)
523 			mvm->tof_data.tof_cfg.tof_disabled = value;
524 		goto out;
525 	}
526 
527 	data = iwl_dbgfs_is_match("one_sided_disabled=", buf);
528 	if (data) {
529 		ret = kstrtou32(data, 10, &value);
530 		if (ret == 0)
531 			mvm->tof_data.tof_cfg.one_sided_disabled = value;
532 		goto out;
533 	}
534 
535 	data = iwl_dbgfs_is_match("is_debug_mode=", buf);
536 	if (data) {
537 		ret = kstrtou32(data, 10, &value);
538 		if (ret == 0)
539 			mvm->tof_data.tof_cfg.is_debug_mode = value;
540 		goto out;
541 	}
542 
543 	data = iwl_dbgfs_is_match("is_buf=", buf);
544 	if (data) {
545 		ret = kstrtou32(data, 10, &value);
546 		if (ret == 0)
547 			mvm->tof_data.tof_cfg.is_buf_required = value;
548 		goto out;
549 	}
550 
551 	data = iwl_dbgfs_is_match("send_tof_cfg=", buf);
552 	if (data) {
553 		ret = kstrtou32(data, 10, &value);
554 		if (ret == 0 && value) {
555 			ret = iwl_mvm_tof_config_cmd(mvm);
556 			goto out;
557 		}
558 	}
559 
560 out:
561 	mutex_unlock(&mvm->mutex);
562 
563 	return ret ?: count;
564 }
565 
566 static ssize_t iwl_dbgfs_tof_enable_read(struct file *file,
567 					 char __user *user_buf,
568 					 size_t count, loff_t *ppos)
569 {
570 	struct ieee80211_vif *vif = file->private_data;
571 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
572 	struct iwl_mvm *mvm = mvmvif->mvm;
573 	char buf[256];
574 	int pos = 0;
575 	const size_t bufsz = sizeof(buf);
576 	struct iwl_tof_config_cmd *cmd;
577 
578 	cmd = &mvm->tof_data.tof_cfg;
579 
580 	mutex_lock(&mvm->mutex);
581 
582 	pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n",
583 			 cmd->tof_disabled);
584 	pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n",
585 			 cmd->one_sided_disabled);
586 	pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n",
587 			 cmd->is_debug_mode);
588 	pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n",
589 			 cmd->is_buf_required);
590 
591 	mutex_unlock(&mvm->mutex);
592 
593 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
594 }
595 
596 static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
597 						    char *buf,
598 						    size_t count, loff_t *ppos)
599 {
600 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
601 	struct iwl_mvm *mvm = mvmvif->mvm;
602 	u32 value;
603 	int ret = 0;
604 	char *data;
605 
606 	mutex_lock(&mvm->mutex);
607 
608 	data = iwl_dbgfs_is_match("burst_period=", buf);
609 	if (data) {
610 		ret = kstrtou32(data, 10, &value);
611 		if (!ret)
612 			mvm->tof_data.responder_cfg.burst_period =
613 							cpu_to_le16(value);
614 		goto out;
615 	}
616 
617 	data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
618 	if (data) {
619 		ret = kstrtou32(data, 10, &value);
620 		if (ret == 0)
621 			mvm->tof_data.responder_cfg.min_delta_ftm = value;
622 		goto out;
623 	}
624 
625 	data = iwl_dbgfs_is_match("burst_duration=", buf);
626 	if (data) {
627 		ret = kstrtou32(data, 10, &value);
628 		if (ret == 0)
629 			mvm->tof_data.responder_cfg.burst_duration = value;
630 		goto out;
631 	}
632 
633 	data = iwl_dbgfs_is_match("num_of_burst_exp=", buf);
634 	if (data) {
635 		ret = kstrtou32(data, 10, &value);
636 		if (ret == 0)
637 			mvm->tof_data.responder_cfg.num_of_burst_exp = value;
638 		goto out;
639 	}
640 
641 	data = iwl_dbgfs_is_match("abort_responder=", buf);
642 	if (data) {
643 		ret = kstrtou32(data, 10, &value);
644 		if (ret == 0)
645 			mvm->tof_data.responder_cfg.abort_responder = value;
646 		goto out;
647 	}
648 
649 	data = iwl_dbgfs_is_match("get_ch_est=", buf);
650 	if (data) {
651 		ret = kstrtou32(data, 10, &value);
652 		if (ret == 0)
653 			mvm->tof_data.responder_cfg.get_ch_est = value;
654 		goto out;
655 	}
656 
657 	data = iwl_dbgfs_is_match("recv_sta_req_params=", buf);
658 	if (data) {
659 		ret = kstrtou32(data, 10, &value);
660 		if (ret == 0)
661 			mvm->tof_data.responder_cfg.recv_sta_req_params = value;
662 		goto out;
663 	}
664 
665 	data = iwl_dbgfs_is_match("channel_num=", buf);
666 	if (data) {
667 		ret = kstrtou32(data, 10, &value);
668 		if (ret == 0)
669 			mvm->tof_data.responder_cfg.channel_num = value;
670 		goto out;
671 	}
672 
673 	data = iwl_dbgfs_is_match("bandwidth=", buf);
674 	if (data) {
675 		ret = kstrtou32(data, 10, &value);
676 		if (ret == 0)
677 			mvm->tof_data.responder_cfg.bandwidth = value;
678 		goto out;
679 	}
680 
681 	data = iwl_dbgfs_is_match("rate=", buf);
682 	if (data) {
683 		ret = kstrtou32(data, 10, &value);
684 		if (ret == 0)
685 			mvm->tof_data.responder_cfg.rate = value;
686 		goto out;
687 	}
688 
689 	data = iwl_dbgfs_is_match("bssid=", buf);
690 	if (data) {
691 		u8 *mac = mvm->tof_data.responder_cfg.bssid;
692 
693 		if (!mac_pton(data, mac)) {
694 			ret = -EINVAL;
695 			goto out;
696 		}
697 	}
698 
699 	data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf);
700 	if (data) {
701 		ret = kstrtou32(data, 10, &value);
702 		if (ret == 0)
703 			mvm->tof_data.responder_cfg.tsf_timer_offset_msecs =
704 							cpu_to_le16(value);
705 		goto out;
706 	}
707 
708 	data = iwl_dbgfs_is_match("toa_offset=", buf);
709 	if (data) {
710 		ret = kstrtou32(data, 10, &value);
711 		if (ret == 0)
712 			mvm->tof_data.responder_cfg.toa_offset =
713 							cpu_to_le16(value);
714 		goto out;
715 	}
716 
717 	data = iwl_dbgfs_is_match("center_freq=", buf);
718 	if (data) {
719 		struct iwl_tof_responder_config_cmd *cmd =
720 			&mvm->tof_data.responder_cfg;
721 
722 		ret = kstrtou32(data, 10, &value);
723 		if (ret == 0 && value) {
724 			enum nl80211_band band = (cmd->channel_num <= 14) ?
725 						   NL80211_BAND_2GHZ :
726 						   NL80211_BAND_5GHZ;
727 			struct ieee80211_channel chn = {
728 				.band = band,
729 				.center_freq = ieee80211_channel_to_frequency(
730 					cmd->channel_num, band),
731 				};
732 			struct cfg80211_chan_def chandef = {
733 				.chan =  &chn,
734 				.center_freq1 =
735 					ieee80211_channel_to_frequency(value,
736 								       band),
737 			};
738 
739 			cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef);
740 		}
741 		goto out;
742 	}
743 
744 	data = iwl_dbgfs_is_match("ftm_per_burst=", buf);
745 	if (data) {
746 		ret = kstrtou32(data, 10, &value);
747 		if (ret == 0)
748 			mvm->tof_data.responder_cfg.ftm_per_burst = value;
749 		goto out;
750 	}
751 
752 	data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf);
753 	if (data) {
754 		ret = kstrtou32(data, 10, &value);
755 		if (ret == 0)
756 			mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value;
757 		goto out;
758 	}
759 
760 	data = iwl_dbgfs_is_match("asap_mode=", buf);
761 	if (data) {
762 		ret = kstrtou32(data, 10, &value);
763 		if (ret == 0)
764 			mvm->tof_data.responder_cfg.asap_mode = value;
765 		goto out;
766 	}
767 
768 	data = iwl_dbgfs_is_match("send_responder_cfg=", buf);
769 	if (data) {
770 		ret = kstrtou32(data, 10, &value);
771 		if (ret == 0 && value) {
772 			ret = iwl_mvm_tof_responder_cmd(mvm, vif);
773 			goto out;
774 		}
775 	}
776 
777 out:
778 	mutex_unlock(&mvm->mutex);
779 
780 	return ret ?: count;
781 }
782 
783 static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file,
784 						   char __user *user_buf,
785 						   size_t count, loff_t *ppos)
786 {
787 	struct ieee80211_vif *vif = file->private_data;
788 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
789 	struct iwl_mvm *mvm = mvmvif->mvm;
790 	char buf[256];
791 	int pos = 0;
792 	const size_t bufsz = sizeof(buf);
793 	struct iwl_tof_responder_config_cmd *cmd;
794 
795 	cmd = &mvm->tof_data.responder_cfg;
796 
797 	mutex_lock(&mvm->mutex);
798 
799 	pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n",
800 			 le16_to_cpu(cmd->burst_period));
801 	pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n",
802 			 cmd->burst_duration);
803 	pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n",
804 			 cmd->bandwidth);
805 	pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n",
806 			 cmd->channel_num);
807 	pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n",
808 			 cmd->ctrl_ch_position);
809 	pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n",
810 			 cmd->bssid);
811 	pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n",
812 			 cmd->min_delta_ftm);
813 	pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n",
814 			 cmd->num_of_burst_exp);
815 	pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate);
816 	pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n",
817 			 cmd->abort_responder);
818 	pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n",
819 			 cmd->get_ch_est);
820 	pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n",
821 			 cmd->recv_sta_req_params);
822 	pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n",
823 			 cmd->ftm_per_burst);
824 	pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n",
825 			 cmd->ftm_resp_ts_avail);
826 	pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n",
827 			 cmd->asap_mode);
828 	pos += scnprintf(buf + pos, bufsz - pos,
829 			 "tsf_timer_offset_msecs = %d\n",
830 			 le16_to_cpu(cmd->tsf_timer_offset_msecs));
831 	pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n",
832 			 le16_to_cpu(cmd->toa_offset));
833 
834 	mutex_unlock(&mvm->mutex);
835 
836 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
837 }
838 
839 static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
840 						 char *buf, size_t count,
841 						 loff_t *ppos)
842 {
843 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
844 	struct iwl_mvm *mvm = mvmvif->mvm;
845 	u32 value;
846 	int ret = 0;
847 	char *data;
848 
849 	mutex_lock(&mvm->mutex);
850 
851 	data = iwl_dbgfs_is_match("request_id=", buf);
852 	if (data) {
853 		ret = kstrtou32(data, 10, &value);
854 		if (ret == 0)
855 			mvm->tof_data.range_req.request_id = value;
856 		goto out;
857 	}
858 
859 	data = iwl_dbgfs_is_match("initiator=", buf);
860 	if (data) {
861 		ret = kstrtou32(data, 10, &value);
862 		if (ret == 0)
863 			mvm->tof_data.range_req.initiator = value;
864 		goto out;
865 	}
866 
867 	data = iwl_dbgfs_is_match("one_sided_los_disable=", buf);
868 	if (data) {
869 		ret = kstrtou32(data, 10, &value);
870 		if (ret == 0)
871 			mvm->tof_data.range_req.one_sided_los_disable = value;
872 		goto out;
873 	}
874 
875 	data = iwl_dbgfs_is_match("req_timeout=", buf);
876 	if (data) {
877 		ret = kstrtou32(data, 10, &value);
878 		if (ret == 0)
879 			mvm->tof_data.range_req.req_timeout = value;
880 		goto out;
881 	}
882 
883 	data = iwl_dbgfs_is_match("report_policy=", buf);
884 	if (data) {
885 		ret = kstrtou32(data, 10, &value);
886 		if (ret == 0)
887 			mvm->tof_data.range_req.report_policy = value;
888 		goto out;
889 	}
890 
891 	data = iwl_dbgfs_is_match("macaddr_random=", buf);
892 	if (data) {
893 		ret = kstrtou32(data, 10, &value);
894 		if (ret == 0)
895 			mvm->tof_data.range_req.macaddr_random = value;
896 		goto out;
897 	}
898 
899 	data = iwl_dbgfs_is_match("num_of_ap=", buf);
900 	if (data) {
901 		ret = kstrtou32(data, 10, &value);
902 		if (ret == 0)
903 			mvm->tof_data.range_req.num_of_ap = value;
904 		goto out;
905 	}
906 
907 	data = iwl_dbgfs_is_match("macaddr_template=", buf);
908 	if (data) {
909 		u8 mac[ETH_ALEN];
910 
911 		if (!mac_pton(data, mac)) {
912 			ret = -EINVAL;
913 			goto out;
914 		}
915 		memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN);
916 		goto out;
917 	}
918 
919 	data = iwl_dbgfs_is_match("macaddr_mask=", buf);
920 	if (data) {
921 		u8 mac[ETH_ALEN];
922 
923 		if (!mac_pton(data, mac)) {
924 			ret = -EINVAL;
925 			goto out;
926 		}
927 		memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN);
928 		goto out;
929 	}
930 
931 	data = iwl_dbgfs_is_match("ap=", buf);
932 	if (data) {
933 		struct iwl_tof_range_req_ap_entry ap = {};
934 		int size = sizeof(struct iwl_tof_range_req_ap_entry);
935 		u16 burst_period;
936 		u8 *mac = ap.bssid;
937 		unsigned int i;
938 
939 		if (sscanf(data, "%u %hhd %hhd %hhd"
940 			   "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"
941 			   "%hhd %hhd %hd"
942 			   "%hhd %hhd %d"
943 			   "%hhx %hhd %hhd %hhd",
944 			   &i, &ap.channel_num, &ap.bandwidth,
945 			   &ap.ctrl_ch_position,
946 			   mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
947 			   &ap.measure_type, &ap.num_of_bursts,
948 			   &burst_period,
949 			   &ap.samples_per_burst, &ap.retries_per_sample,
950 			   &ap.tsf_delta, &ap.location_req, &ap.asap_mode,
951 			   &ap.enable_dyn_ack, &ap.rssi) != 20) {
952 			ret = -EINVAL;
953 			goto out;
954 		}
955 		if (i >= IWL_MVM_TOF_MAX_APS) {
956 			IWL_ERR(mvm, "Invalid AP index %d\n", i);
957 			ret = -EINVAL;
958 			goto out;
959 		}
960 
961 		ap.burst_period = cpu_to_le16(burst_period);
962 
963 		memcpy(&mvm->tof_data.range_req.ap[i], &ap, size);
964 		goto out;
965 	}
966 
967 	data = iwl_dbgfs_is_match("send_range_request=", buf);
968 	if (data) {
969 		ret = kstrtou32(data, 10, &value);
970 		if (ret == 0 && value)
971 			ret = iwl_mvm_tof_range_request_cmd(mvm, vif);
972 		goto out;
973 	}
974 
975 	ret = -EINVAL;
976 out:
977 	mutex_unlock(&mvm->mutex);
978 	return ret ?: count;
979 }
980 
981 static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file,
982 						char __user *user_buf,
983 						size_t count, loff_t *ppos)
984 {
985 	struct ieee80211_vif *vif = file->private_data;
986 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
987 	struct iwl_mvm *mvm = mvmvif->mvm;
988 	char buf[512];
989 	int pos = 0;
990 	const size_t bufsz = sizeof(buf);
991 	struct iwl_tof_range_req_cmd *cmd;
992 	int i;
993 
994 	cmd = &mvm->tof_data.range_req;
995 
996 	mutex_lock(&mvm->mutex);
997 
998 	pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n",
999 			 cmd->request_id);
1000 	pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n",
1001 			 cmd->initiator);
1002 	pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n",
1003 			 cmd->one_sided_los_disable);
1004 	pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n",
1005 			 cmd->req_timeout);
1006 	pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n",
1007 			 cmd->report_policy);
1008 	pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n",
1009 			 cmd->macaddr_random);
1010 	pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n",
1011 			 cmd->macaddr_template);
1012 	pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n",
1013 			 cmd->macaddr_mask);
1014 	pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n",
1015 			 cmd->num_of_ap);
1016 	for (i = 0; i < cmd->num_of_ap; i++) {
1017 		struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i];
1018 
1019 		pos += scnprintf(buf + pos, bufsz - pos,
1020 				"ap %.2d: channel_num=%hhd bw=%hhd"
1021 				" control=%hhd bssid=%pM type=%hhd"
1022 				" num_of_bursts=%hhd burst_period=%hd ftm=%hhd"
1023 				" retries=%hhd tsf_delta=%d"
1024 				" tsf_delta_direction=%hhd location_req=0x%hhx "
1025 				" asap=%hhd enable=%hhd rssi=%hhd\n",
1026 				i, ap->channel_num, ap->bandwidth,
1027 				ap->ctrl_ch_position, ap->bssid,
1028 				ap->measure_type, ap->num_of_bursts,
1029 				ap->burst_period, ap->samples_per_burst,
1030 				ap->retries_per_sample, ap->tsf_delta,
1031 				ap->tsf_delta_direction,
1032 				ap->location_req, ap->asap_mode,
1033 				ap->enable_dyn_ack, ap->rssi);
1034 	}
1035 
1036 	mutex_unlock(&mvm->mutex);
1037 
1038 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1039 }
1040 
1041 static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
1042 						 char *buf,
1043 						 size_t count, loff_t *ppos)
1044 {
1045 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1046 	struct iwl_mvm *mvm = mvmvif->mvm;
1047 	u32 value;
1048 	int ret = 0;
1049 	char *data;
1050 
1051 	mutex_lock(&mvm->mutex);
1052 
1053 	data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf);
1054 	if (data) {
1055 		ret = kstrtou32(data, 10, &value);
1056 		if (ret == 0)
1057 			mvm->tof_data.range_req_ext.tsf_timer_offset_msec =
1058 							cpu_to_le16(value);
1059 		goto out;
1060 	}
1061 
1062 	data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
1063 	if (data) {
1064 		ret = kstrtou32(data, 10, &value);
1065 		if (ret == 0)
1066 			mvm->tof_data.range_req_ext.min_delta_ftm = value;
1067 		goto out;
1068 	}
1069 
1070 	data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf);
1071 	if (data) {
1072 		ret = kstrtou32(data, 10, &value);
1073 		if (ret == 0)
1074 			mvm->tof_data.range_req_ext.ftm_format_and_bw20M =
1075 									value;
1076 		goto out;
1077 	}
1078 
1079 	data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf);
1080 	if (data) {
1081 		ret = kstrtou32(data, 10, &value);
1082 		if (ret == 0)
1083 			mvm->tof_data.range_req_ext.ftm_format_and_bw40M =
1084 									value;
1085 		goto out;
1086 	}
1087 
1088 	data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf);
1089 	if (data) {
1090 		ret = kstrtou32(data, 10, &value);
1091 		if (ret == 0)
1092 			mvm->tof_data.range_req_ext.ftm_format_and_bw80M =
1093 									value;
1094 		goto out;
1095 	}
1096 
1097 	data = iwl_dbgfs_is_match("send_range_req_ext=", buf);
1098 	if (data) {
1099 		ret = kstrtou32(data, 10, &value);
1100 		if (ret == 0 && value)
1101 			ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif);
1102 		goto out;
1103 	}
1104 
1105 	ret = -EINVAL;
1106 out:
1107 	mutex_unlock(&mvm->mutex);
1108 	return ret ?: count;
1109 }
1110 
1111 static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file,
1112 						char __user *user_buf,
1113 						size_t count, loff_t *ppos)
1114 {
1115 	struct ieee80211_vif *vif = file->private_data;
1116 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1117 	struct iwl_mvm *mvm = mvmvif->mvm;
1118 	char buf[256];
1119 	int pos = 0;
1120 	const size_t bufsz = sizeof(buf);
1121 	struct iwl_tof_range_req_ext_cmd *cmd;
1122 
1123 	cmd = &mvm->tof_data.range_req_ext;
1124 
1125 	mutex_lock(&mvm->mutex);
1126 
1127 	pos += scnprintf(buf + pos, bufsz - pos,
1128 			 "tsf_timer_offset_msec = %hd\n",
1129 			 cmd->tsf_timer_offset_msec);
1130 	pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n",
1131 			 cmd->min_delta_ftm);
1132 	pos += scnprintf(buf + pos, bufsz - pos,
1133 			 "ftm_format_and_bw20M = %hhd\n",
1134 			 cmd->ftm_format_and_bw20M);
1135 	pos += scnprintf(buf + pos, bufsz - pos,
1136 			 "ftm_format_and_bw40M = %hhd\n",
1137 			 cmd->ftm_format_and_bw40M);
1138 	pos += scnprintf(buf + pos, bufsz - pos,
1139 			 "ftm_format_and_bw80M = %hhd\n",
1140 			 cmd->ftm_format_and_bw80M);
1141 
1142 	mutex_unlock(&mvm->mutex);
1143 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1144 }
1145 
1146 static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif,
1147 					       char *buf,
1148 					       size_t count, loff_t *ppos)
1149 {
1150 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1151 	struct iwl_mvm *mvm = mvmvif->mvm;
1152 	u32 value;
1153 	int abort_id, ret = 0;
1154 	char *data;
1155 
1156 	mutex_lock(&mvm->mutex);
1157 
1158 	data = iwl_dbgfs_is_match("abort_id=", buf);
1159 	if (data) {
1160 		ret = kstrtou32(data, 10, &value);
1161 		if (ret == 0)
1162 			mvm->tof_data.last_abort_id = value;
1163 		goto out;
1164 	}
1165 
1166 	data = iwl_dbgfs_is_match("send_range_abort=", buf);
1167 	if (data) {
1168 		ret = kstrtou32(data, 10, &value);
1169 		if (ret == 0 && value) {
1170 			abort_id = mvm->tof_data.last_abort_id;
1171 			ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id);
1172 			goto out;
1173 		}
1174 	}
1175 
1176 out:
1177 	mutex_unlock(&mvm->mutex);
1178 	return ret ?: count;
1179 }
1180 
1181 static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file,
1182 					      char __user *user_buf,
1183 					      size_t count, loff_t *ppos)
1184 {
1185 	struct ieee80211_vif *vif = file->private_data;
1186 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1187 	struct iwl_mvm *mvm = mvmvif->mvm;
1188 	char buf[32];
1189 	int pos = 0;
1190 	const size_t bufsz = sizeof(buf);
1191 	int last_abort_id;
1192 
1193 	mutex_lock(&mvm->mutex);
1194 	last_abort_id = mvm->tof_data.last_abort_id;
1195 	mutex_unlock(&mvm->mutex);
1196 
1197 	pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n",
1198 			 last_abort_id);
1199 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1200 }
1201 
1202 static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file,
1203 						 char __user *user_buf,
1204 						 size_t count, loff_t *ppos)
1205 {
1206 	struct ieee80211_vif *vif = file->private_data;
1207 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1208 	struct iwl_mvm *mvm = mvmvif->mvm;
1209 	char *buf;
1210 	int pos = 0;
1211 	const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256;
1212 	struct iwl_tof_range_rsp_ntfy *cmd;
1213 	int i, ret;
1214 
1215 	buf = kzalloc(bufsz, GFP_KERNEL);
1216 	if (!buf)
1217 		return -ENOMEM;
1218 
1219 	mutex_lock(&mvm->mutex);
1220 	cmd = &mvm->tof_data.range_resp;
1221 
1222 	pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n",
1223 			 cmd->request_id);
1224 	pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n",
1225 			 cmd->request_status);
1226 	pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n",
1227 			 cmd->last_in_batch);
1228 	pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n",
1229 			 cmd->num_of_aps);
1230 	for (i = 0; i < cmd->num_of_aps; i++) {
1231 		struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i];
1232 
1233 		pos += scnprintf(buf + pos, bufsz - pos,
1234 				"ap %.2d: bssid=%pM status=%hhd bw=%hhd"
1235 				" rtt=%d rtt_var=%d rtt_spread=%d"
1236 				" rssi=%hhd  rssi_spread=%hhd"
1237 				" range=%d range_var=%d"
1238 				" time_stamp=%d\n",
1239 				i, ap->bssid, ap->measure_status,
1240 				ap->measure_bw,
1241 				ap->rtt, ap->rtt_variance, ap->rtt_spread,
1242 				ap->rssi, ap->rssi_spread, ap->range,
1243 				ap->range_variance, ap->timestamp);
1244 	}
1245 	mutex_unlock(&mvm->mutex);
1246 
1247 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1248 	kfree(buf);
1249 	return ret;
1250 }
1251 
1252 static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
1253 					   size_t count, loff_t *ppos)
1254 {
1255 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1256 	struct iwl_mvm *mvm = mvmvif->mvm;
1257 	bool prev;
1258 	u8 value;
1259 	int ret;
1260 
1261 	ret = kstrtou8(buf, 0, &value);
1262 	if (ret)
1263 		return ret;
1264 	if (value > 1)
1265 		return -EINVAL;
1266 
1267 	mutex_lock(&mvm->mutex);
1268 	prev = iwl_mvm_vif_low_latency(mvmvif);
1269 	mvmvif->low_latency_dbgfs = value;
1270 	iwl_mvm_update_low_latency(mvm, vif, prev);
1271 	mutex_unlock(&mvm->mutex);
1272 
1273 	return count;
1274 }
1275 
1276 static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
1277 					  char __user *user_buf,
1278 					  size_t count, loff_t *ppos)
1279 {
1280 	struct ieee80211_vif *vif = file->private_data;
1281 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1282 	char buf[30] = {};
1283 	int len;
1284 
1285 	len = snprintf(buf, sizeof(buf) - 1,
1286 		       "traffic=%d\ndbgfs=%d\nvcmd=%d\n",
1287 		       mvmvif->low_latency_traffic,
1288 		       mvmvif->low_latency_dbgfs,
1289 		       mvmvif->low_latency_vcmd);
1290 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1291 }
1292 
1293 static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
1294 						char __user *user_buf,
1295 						size_t count, loff_t *ppos)
1296 {
1297 	struct ieee80211_vif *vif = file->private_data;
1298 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1299 	char buf[20];
1300 	int len;
1301 
1302 	len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
1303 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1304 }
1305 
1306 static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
1307 						 char *buf, size_t count,
1308 						 loff_t *ppos)
1309 {
1310 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1311 	struct iwl_mvm *mvm = mvmvif->mvm;
1312 	bool ret;
1313 
1314 	mutex_lock(&mvm->mutex);
1315 	ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
1316 	mutex_unlock(&mvm->mutex);
1317 
1318 	return ret ? count : -EINVAL;
1319 }
1320 
1321 static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
1322 					  size_t count, loff_t *ppos)
1323 {
1324 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1325 	struct iwl_mvm *mvm = mvmvif->mvm;
1326 	struct ieee80211_chanctx_conf *chanctx_conf;
1327 	struct iwl_mvm_phy_ctxt *phy_ctxt;
1328 	u16 value;
1329 	int ret;
1330 
1331 	ret = kstrtou16(buf, 0, &value);
1332 	if (ret)
1333 		return ret;
1334 
1335 	mutex_lock(&mvm->mutex);
1336 	rcu_read_lock();
1337 
1338 	chanctx_conf = rcu_dereference(vif->chanctx_conf);
1339 	/* make sure the channel context is assigned */
1340 	if (!chanctx_conf) {
1341 		rcu_read_unlock();
1342 		mutex_unlock(&mvm->mutex);
1343 		return -EINVAL;
1344 	}
1345 
1346 	phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
1347 	rcu_read_unlock();
1348 
1349 	mvm->dbgfs_rx_phyinfo = value;
1350 
1351 	ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
1352 				       chanctx_conf->rx_chains_static,
1353 				       chanctx_conf->rx_chains_dynamic);
1354 	mutex_unlock(&mvm->mutex);
1355 
1356 	return ret ?: count;
1357 }
1358 
1359 static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
1360 					 char __user *user_buf,
1361 					 size_t count, loff_t *ppos)
1362 {
1363 	struct ieee80211_vif *vif = file->private_data;
1364 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1365 	char buf[8];
1366 
1367 	snprintf(buf, sizeof(buf), "0x%04x\n", mvmvif->mvm->dbgfs_rx_phyinfo);
1368 
1369 	return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
1370 }
1371 
1372 static void iwl_dbgfs_quota_check(void *data, u8 *mac,
1373 				  struct ieee80211_vif *vif)
1374 {
1375 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1376 	int *ret = data;
1377 
1378 	if (mvmvif->dbgfs_quota_min)
1379 		*ret = -EINVAL;
1380 }
1381 
1382 static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
1383 					 size_t count, loff_t *ppos)
1384 {
1385 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1386 	struct iwl_mvm *mvm = mvmvif->mvm;
1387 	u16 value;
1388 	int ret;
1389 
1390 	ret = kstrtou16(buf, 0, &value);
1391 	if (ret)
1392 		return ret;
1393 
1394 	if (value > 95)
1395 		return -EINVAL;
1396 
1397 	mutex_lock(&mvm->mutex);
1398 
1399 	mvmvif->dbgfs_quota_min = 0;
1400 	ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1401 				     iwl_dbgfs_quota_check, &ret);
1402 	if (ret == 0) {
1403 		mvmvif->dbgfs_quota_min = value;
1404 		iwl_mvm_update_quotas(mvm, false, NULL);
1405 	}
1406 	mutex_unlock(&mvm->mutex);
1407 
1408 	return ret ?: count;
1409 }
1410 
1411 static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
1412 					char __user *user_buf,
1413 					size_t count, loff_t *ppos)
1414 {
1415 	struct ieee80211_vif *vif = file->private_data;
1416 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1417 	char buf[10];
1418 	int len;
1419 
1420 	len = snprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
1421 
1422 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1423 }
1424 
1425 static const char * const chanwidths[] = {
1426 	[NL80211_CHAN_WIDTH_20_NOHT] = "noht",
1427 	[NL80211_CHAN_WIDTH_20] = "ht20",
1428 	[NL80211_CHAN_WIDTH_40] = "ht40",
1429 	[NL80211_CHAN_WIDTH_80] = "vht80",
1430 	[NL80211_CHAN_WIDTH_80P80] = "vht80p80",
1431 	[NL80211_CHAN_WIDTH_160] = "vht160",
1432 };
1433 
1434 static bool iwl_mvm_lqm_notif_wait(struct iwl_notif_wait_data *notif_wait,
1435 				   struct iwl_rx_packet *pkt, void *data)
1436 {
1437 	struct ieee80211_vif *vif = data;
1438 	struct iwl_mvm *mvm =
1439 		container_of(notif_wait, struct iwl_mvm, notif_wait);
1440 	struct iwl_link_qual_msrmnt_notif *report = (void *)pkt->data;
1441 	u32 num_of_stations = le32_to_cpu(report->number_of_stations);
1442 	int i;
1443 
1444 	IWL_INFO(mvm, "LQM report:\n");
1445 	IWL_INFO(mvm, "\tstatus: %d\n", report->status);
1446 	IWL_INFO(mvm, "\tmacID: %d\n", le32_to_cpu(report->mac_id));
1447 	IWL_INFO(mvm, "\ttx_frame_dropped: %d\n",
1448 		 le32_to_cpu(report->tx_frame_dropped));
1449 	IWL_INFO(mvm, "\ttime_in_measurement_window: %d us\n",
1450 		 le32_to_cpu(report->time_in_measurement_window));
1451 	IWL_INFO(mvm, "\ttotal_air_time_other_stations: %d\n",
1452 		 le32_to_cpu(report->total_air_time_other_stations));
1453 	IWL_INFO(mvm, "\tchannel_freq: %d\n",
1454 		 vif->bss_conf.chandef.center_freq1);
1455 	IWL_INFO(mvm, "\tchannel_width: %s\n",
1456 		 chanwidths[vif->bss_conf.chandef.width]);
1457 	IWL_INFO(mvm, "\tnumber_of_stations: %d\n", num_of_stations);
1458 	for (i = 0; i < num_of_stations; i++)
1459 		IWL_INFO(mvm, "\t\tsta[%d]: %d\n", i,
1460 			 report->frequent_stations_air_time[i]);
1461 
1462 	return true;
1463 }
1464 
1465 static ssize_t iwl_dbgfs_lqm_send_cmd_write(struct ieee80211_vif *vif,
1466 					    char *buf, size_t count,
1467 					    loff_t *ppos)
1468 {
1469 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1470 	struct iwl_mvm *mvm = mvmvif->mvm;
1471 	struct iwl_notification_wait wait_lqm_notif;
1472 	static u16 lqm_notif[] = {
1473 		WIDE_ID(MAC_CONF_GROUP,
1474 			LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF)
1475 	};
1476 	int err;
1477 	u32 duration;
1478 	u32 timeout;
1479 
1480 	if (sscanf(buf, "%d,%d", &duration, &timeout) != 2)
1481 		return -EINVAL;
1482 
1483 	iwl_init_notification_wait(&mvm->notif_wait, &wait_lqm_notif,
1484 				   lqm_notif, ARRAY_SIZE(lqm_notif),
1485 				   iwl_mvm_lqm_notif_wait, vif);
1486 	mutex_lock(&mvm->mutex);
1487 	err = iwl_mvm_send_lqm_cmd(vif, LQM_CMD_OPERATION_START_MEASUREMENT,
1488 				   duration, timeout);
1489 	mutex_unlock(&mvm->mutex);
1490 
1491 	if (err) {
1492 		IWL_ERR(mvm, "Failed to send lqm cmdf(err=%d)\n", err);
1493 		iwl_remove_notification(&mvm->notif_wait, &wait_lqm_notif);
1494 		return err;
1495 	}
1496 
1497 	/* wait for 2 * timeout (safety guard) and convert to jiffies*/
1498 	timeout = msecs_to_jiffies((timeout * 2) / 1000);
1499 
1500 	err = iwl_wait_notification(&mvm->notif_wait, &wait_lqm_notif,
1501 				    timeout);
1502 	if (err)
1503 		IWL_ERR(mvm, "Getting lqm notif timed out\n");
1504 
1505 	return count;
1506 }
1507 
1508 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1509 	_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1510 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1511 	_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1512 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {		\
1513 		if (!debugfs_create_file(#name, mode, parent, vif,	\
1514 					 &iwl_dbgfs_##name##_ops))	\
1515 			goto err;					\
1516 	} while (0)
1517 
1518 MVM_DEBUGFS_READ_FILE_OPS(mac_params);
1519 MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
1520 MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
1521 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
1522 MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
1523 MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
1524 MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
1525 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32);
1526 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512);
1527 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
1528 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
1529 MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
1530 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
1531 MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
1532 MVM_DEBUGFS_WRITE_FILE_OPS(lqm_send_cmd, 64);
1533 
1534 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1535 {
1536 	struct dentry *dbgfs_dir = vif->debugfs_dir;
1537 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1538 	char buf[100];
1539 
1540 	/*
1541 	 * Check if debugfs directory already exist before creating it.
1542 	 * This may happen when, for example, resetting hw or suspend-resume
1543 	 */
1544 	if (!dbgfs_dir || mvmvif->dbgfs_dir)
1545 		return;
1546 
1547 	mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
1548 
1549 	if (!mvmvif->dbgfs_dir) {
1550 		IWL_ERR(mvm, "Failed to create debugfs directory under %s\n",
1551 			dbgfs_dir->d_name.name);
1552 		return;
1553 	}
1554 
1555 	if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
1556 	    ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
1557 	     (vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
1558 	      mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)))
1559 		MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
1560 					 S_IRUSR);
1561 
1562 	MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR);
1563 	MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR);
1564 	MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir,
1565 				 S_IRUSR | S_IWUSR);
1566 	MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir,
1567 				 S_IRUSR | S_IWUSR);
1568 	MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir,
1569 				 S_IRUSR | S_IWUSR);
1570 	MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
1571 				 S_IRUSR | S_IWUSR);
1572 	MVM_DEBUGFS_ADD_FILE_VIF(lqm_send_cmd, mvmvif->dbgfs_dir, S_IWUSR);
1573 
1574 	if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
1575 	    mvmvif == mvm->bf_allowed_vif)
1576 		MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
1577 					 S_IRUSR | S_IWUSR);
1578 
1579 	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) &&
1580 	    !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) {
1581 		if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP)
1582 			MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params,
1583 						 mvmvif->dbgfs_dir,
1584 						 S_IRUSR | S_IWUSR);
1585 
1586 		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir,
1587 					 S_IRUSR | S_IWUSR);
1588 		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir,
1589 					 S_IRUSR | S_IWUSR);
1590 		MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir,
1591 					 S_IRUSR | S_IWUSR);
1592 		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir,
1593 					 S_IRUSR | S_IWUSR);
1594 		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir,
1595 					 S_IRUSR);
1596 	}
1597 
1598 	/*
1599 	 * Create symlink for convenience pointing to interface specific
1600 	 * debugfs entries for the driver. For example, under
1601 	 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
1602 	 * find
1603 	 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
1604 	 */
1605 	snprintf(buf, 100, "../../../%s/%s/%s/%s",
1606 		 dbgfs_dir->d_parent->d_parent->d_name.name,
1607 		 dbgfs_dir->d_parent->d_name.name,
1608 		 dbgfs_dir->d_name.name,
1609 		 mvmvif->dbgfs_dir->d_name.name);
1610 
1611 	mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
1612 						     mvm->debugfs_dir, buf);
1613 	if (!mvmvif->dbgfs_slink)
1614 		IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n",
1615 			dbgfs_dir->d_name.name);
1616 	return;
1617 err:
1618 	IWL_ERR(mvm, "Can't create debugfs entity\n");
1619 }
1620 
1621 void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1622 {
1623 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1624 
1625 	debugfs_remove(mvmvif->dbgfs_slink);
1626 	mvmvif->dbgfs_slink = NULL;
1627 
1628 	debugfs_remove_recursive(mvmvif->dbgfs_dir);
1629 	mvmvif->dbgfs_dir = NULL;
1630 }
1631