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