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  * 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 - 2017 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_INVALID_STA) {
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_os_device_timediff_read(struct file *file,
508 						 char __user *user_buf,
509 						 size_t count, loff_t *ppos)
510 {
511 	struct ieee80211_vif *vif = file->private_data;
512 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
513 	struct iwl_mvm *mvm = mvmvif->mvm;
514 	u32 curr_gp2;
515 	u64 curr_os;
516 	s64 diff;
517 	char buf[64];
518 	const size_t bufsz = sizeof(buf);
519 	int pos = 0;
520 
521 	iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os);
522 	do_div(curr_os, NSEC_PER_USEC);
523 	diff = curr_os - curr_gp2;
524 	pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff);
525 
526 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
527 }
528 
529 static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
530 					  char *buf,
531 					  size_t count, loff_t *ppos)
532 {
533 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
534 	struct iwl_mvm *mvm = mvmvif->mvm;
535 	u32 value;
536 	int ret = -EINVAL;
537 	char *data;
538 
539 	mutex_lock(&mvm->mutex);
540 
541 	data = iwl_dbgfs_is_match("tof_disabled=", buf);
542 	if (data) {
543 		ret = kstrtou32(data, 10, &value);
544 		if (ret == 0)
545 			mvm->tof_data.tof_cfg.tof_disabled = value;
546 		goto out;
547 	}
548 
549 	data = iwl_dbgfs_is_match("one_sided_disabled=", buf);
550 	if (data) {
551 		ret = kstrtou32(data, 10, &value);
552 		if (ret == 0)
553 			mvm->tof_data.tof_cfg.one_sided_disabled = value;
554 		goto out;
555 	}
556 
557 	data = iwl_dbgfs_is_match("is_debug_mode=", buf);
558 	if (data) {
559 		ret = kstrtou32(data, 10, &value);
560 		if (ret == 0)
561 			mvm->tof_data.tof_cfg.is_debug_mode = value;
562 		goto out;
563 	}
564 
565 	data = iwl_dbgfs_is_match("is_buf=", buf);
566 	if (data) {
567 		ret = kstrtou32(data, 10, &value);
568 		if (ret == 0)
569 			mvm->tof_data.tof_cfg.is_buf_required = value;
570 		goto out;
571 	}
572 
573 	data = iwl_dbgfs_is_match("send_tof_cfg=", buf);
574 	if (data) {
575 		ret = kstrtou32(data, 10, &value);
576 		if (ret == 0 && value) {
577 			ret = iwl_mvm_tof_config_cmd(mvm);
578 			goto out;
579 		}
580 	}
581 
582 out:
583 	mutex_unlock(&mvm->mutex);
584 
585 	return ret ?: count;
586 }
587 
588 static ssize_t iwl_dbgfs_tof_enable_read(struct file *file,
589 					 char __user *user_buf,
590 					 size_t count, loff_t *ppos)
591 {
592 	struct ieee80211_vif *vif = file->private_data;
593 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
594 	struct iwl_mvm *mvm = mvmvif->mvm;
595 	char buf[256];
596 	int pos = 0;
597 	const size_t bufsz = sizeof(buf);
598 	struct iwl_tof_config_cmd *cmd;
599 
600 	cmd = &mvm->tof_data.tof_cfg;
601 
602 	mutex_lock(&mvm->mutex);
603 
604 	pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n",
605 			 cmd->tof_disabled);
606 	pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n",
607 			 cmd->one_sided_disabled);
608 	pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n",
609 			 cmd->is_debug_mode);
610 	pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n",
611 			 cmd->is_buf_required);
612 
613 	mutex_unlock(&mvm->mutex);
614 
615 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
616 }
617 
618 static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
619 						    char *buf,
620 						    size_t count, loff_t *ppos)
621 {
622 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
623 	struct iwl_mvm *mvm = mvmvif->mvm;
624 	u32 value;
625 	int ret = 0;
626 	char *data;
627 
628 	mutex_lock(&mvm->mutex);
629 
630 	data = iwl_dbgfs_is_match("burst_period=", buf);
631 	if (data) {
632 		ret = kstrtou32(data, 10, &value);
633 		if (!ret)
634 			mvm->tof_data.responder_cfg.burst_period =
635 							cpu_to_le16(value);
636 		goto out;
637 	}
638 
639 	data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
640 	if (data) {
641 		ret = kstrtou32(data, 10, &value);
642 		if (ret == 0)
643 			mvm->tof_data.responder_cfg.min_delta_ftm = value;
644 		goto out;
645 	}
646 
647 	data = iwl_dbgfs_is_match("burst_duration=", buf);
648 	if (data) {
649 		ret = kstrtou32(data, 10, &value);
650 		if (ret == 0)
651 			mvm->tof_data.responder_cfg.burst_duration = value;
652 		goto out;
653 	}
654 
655 	data = iwl_dbgfs_is_match("num_of_burst_exp=", buf);
656 	if (data) {
657 		ret = kstrtou32(data, 10, &value);
658 		if (ret == 0)
659 			mvm->tof_data.responder_cfg.num_of_burst_exp = value;
660 		goto out;
661 	}
662 
663 	data = iwl_dbgfs_is_match("abort_responder=", buf);
664 	if (data) {
665 		ret = kstrtou32(data, 10, &value);
666 		if (ret == 0)
667 			mvm->tof_data.responder_cfg.abort_responder = value;
668 		goto out;
669 	}
670 
671 	data = iwl_dbgfs_is_match("get_ch_est=", buf);
672 	if (data) {
673 		ret = kstrtou32(data, 10, &value);
674 		if (ret == 0)
675 			mvm->tof_data.responder_cfg.get_ch_est = value;
676 		goto out;
677 	}
678 
679 	data = iwl_dbgfs_is_match("recv_sta_req_params=", buf);
680 	if (data) {
681 		ret = kstrtou32(data, 10, &value);
682 		if (ret == 0)
683 			mvm->tof_data.responder_cfg.recv_sta_req_params = value;
684 		goto out;
685 	}
686 
687 	data = iwl_dbgfs_is_match("channel_num=", buf);
688 	if (data) {
689 		ret = kstrtou32(data, 10, &value);
690 		if (ret == 0)
691 			mvm->tof_data.responder_cfg.channel_num = value;
692 		goto out;
693 	}
694 
695 	data = iwl_dbgfs_is_match("bandwidth=", buf);
696 	if (data) {
697 		ret = kstrtou32(data, 10, &value);
698 		if (ret == 0)
699 			mvm->tof_data.responder_cfg.bandwidth = value;
700 		goto out;
701 	}
702 
703 	data = iwl_dbgfs_is_match("rate=", buf);
704 	if (data) {
705 		ret = kstrtou32(data, 10, &value);
706 		if (ret == 0)
707 			mvm->tof_data.responder_cfg.rate = value;
708 		goto out;
709 	}
710 
711 	data = iwl_dbgfs_is_match("bssid=", buf);
712 	if (data) {
713 		u8 *mac = mvm->tof_data.responder_cfg.bssid;
714 
715 		if (!mac_pton(data, mac)) {
716 			ret = -EINVAL;
717 			goto out;
718 		}
719 	}
720 
721 	data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf);
722 	if (data) {
723 		ret = kstrtou32(data, 10, &value);
724 		if (ret == 0)
725 			mvm->tof_data.responder_cfg.tsf_timer_offset_msecs =
726 							cpu_to_le16(value);
727 		goto out;
728 	}
729 
730 	data = iwl_dbgfs_is_match("toa_offset=", buf);
731 	if (data) {
732 		ret = kstrtou32(data, 10, &value);
733 		if (ret == 0)
734 			mvm->tof_data.responder_cfg.toa_offset =
735 							cpu_to_le16(value);
736 		goto out;
737 	}
738 
739 	data = iwl_dbgfs_is_match("center_freq=", buf);
740 	if (data) {
741 		struct iwl_tof_responder_config_cmd *cmd =
742 			&mvm->tof_data.responder_cfg;
743 
744 		ret = kstrtou32(data, 10, &value);
745 		if (ret == 0 && value) {
746 			enum nl80211_band band = (cmd->channel_num <= 14) ?
747 						   NL80211_BAND_2GHZ :
748 						   NL80211_BAND_5GHZ;
749 			struct ieee80211_channel chn = {
750 				.band = band,
751 				.center_freq = ieee80211_channel_to_frequency(
752 					cmd->channel_num, band),
753 				};
754 			struct cfg80211_chan_def chandef = {
755 				.chan =  &chn,
756 				.center_freq1 =
757 					ieee80211_channel_to_frequency(value,
758 								       band),
759 			};
760 
761 			cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef);
762 		}
763 		goto out;
764 	}
765 
766 	data = iwl_dbgfs_is_match("ftm_per_burst=", buf);
767 	if (data) {
768 		ret = kstrtou32(data, 10, &value);
769 		if (ret == 0)
770 			mvm->tof_data.responder_cfg.ftm_per_burst = value;
771 		goto out;
772 	}
773 
774 	data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf);
775 	if (data) {
776 		ret = kstrtou32(data, 10, &value);
777 		if (ret == 0)
778 			mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value;
779 		goto out;
780 	}
781 
782 	data = iwl_dbgfs_is_match("asap_mode=", buf);
783 	if (data) {
784 		ret = kstrtou32(data, 10, &value);
785 		if (ret == 0)
786 			mvm->tof_data.responder_cfg.asap_mode = value;
787 		goto out;
788 	}
789 
790 	data = iwl_dbgfs_is_match("send_responder_cfg=", buf);
791 	if (data) {
792 		ret = kstrtou32(data, 10, &value);
793 		if (ret == 0 && value) {
794 			ret = iwl_mvm_tof_responder_cmd(mvm, vif);
795 			goto out;
796 		}
797 	}
798 
799 out:
800 	mutex_unlock(&mvm->mutex);
801 
802 	return ret ?: count;
803 }
804 
805 static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file,
806 						   char __user *user_buf,
807 						   size_t count, loff_t *ppos)
808 {
809 	struct ieee80211_vif *vif = file->private_data;
810 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
811 	struct iwl_mvm *mvm = mvmvif->mvm;
812 	char buf[256];
813 	int pos = 0;
814 	const size_t bufsz = sizeof(buf);
815 	struct iwl_tof_responder_config_cmd *cmd;
816 
817 	cmd = &mvm->tof_data.responder_cfg;
818 
819 	mutex_lock(&mvm->mutex);
820 
821 	pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n",
822 			 le16_to_cpu(cmd->burst_period));
823 	pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n",
824 			 cmd->burst_duration);
825 	pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n",
826 			 cmd->bandwidth);
827 	pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n",
828 			 cmd->channel_num);
829 	pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n",
830 			 cmd->ctrl_ch_position);
831 	pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n",
832 			 cmd->bssid);
833 	pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n",
834 			 cmd->min_delta_ftm);
835 	pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n",
836 			 cmd->num_of_burst_exp);
837 	pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate);
838 	pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n",
839 			 cmd->abort_responder);
840 	pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n",
841 			 cmd->get_ch_est);
842 	pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n",
843 			 cmd->recv_sta_req_params);
844 	pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n",
845 			 cmd->ftm_per_burst);
846 	pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n",
847 			 cmd->ftm_resp_ts_avail);
848 	pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n",
849 			 cmd->asap_mode);
850 	pos += scnprintf(buf + pos, bufsz - pos,
851 			 "tsf_timer_offset_msecs = %d\n",
852 			 le16_to_cpu(cmd->tsf_timer_offset_msecs));
853 	pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n",
854 			 le16_to_cpu(cmd->toa_offset));
855 
856 	mutex_unlock(&mvm->mutex);
857 
858 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
859 }
860 
861 static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
862 						 char *buf, size_t count,
863 						 loff_t *ppos)
864 {
865 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
866 	struct iwl_mvm *mvm = mvmvif->mvm;
867 	u32 value;
868 	int ret = 0;
869 	char *data;
870 
871 	mutex_lock(&mvm->mutex);
872 
873 	data = iwl_dbgfs_is_match("request_id=", buf);
874 	if (data) {
875 		ret = kstrtou32(data, 10, &value);
876 		if (ret == 0)
877 			mvm->tof_data.range_req.request_id = value;
878 		goto out;
879 	}
880 
881 	data = iwl_dbgfs_is_match("initiator=", buf);
882 	if (data) {
883 		ret = kstrtou32(data, 10, &value);
884 		if (ret == 0)
885 			mvm->tof_data.range_req.initiator = value;
886 		goto out;
887 	}
888 
889 	data = iwl_dbgfs_is_match("one_sided_los_disable=", buf);
890 	if (data) {
891 		ret = kstrtou32(data, 10, &value);
892 		if (ret == 0)
893 			mvm->tof_data.range_req.one_sided_los_disable = value;
894 		goto out;
895 	}
896 
897 	data = iwl_dbgfs_is_match("req_timeout=", buf);
898 	if (data) {
899 		ret = kstrtou32(data, 10, &value);
900 		if (ret == 0)
901 			mvm->tof_data.range_req.req_timeout = value;
902 		goto out;
903 	}
904 
905 	data = iwl_dbgfs_is_match("report_policy=", buf);
906 	if (data) {
907 		ret = kstrtou32(data, 10, &value);
908 		if (ret == 0)
909 			mvm->tof_data.range_req.report_policy = value;
910 		goto out;
911 	}
912 
913 	data = iwl_dbgfs_is_match("macaddr_random=", buf);
914 	if (data) {
915 		ret = kstrtou32(data, 10, &value);
916 		if (ret == 0)
917 			mvm->tof_data.range_req.macaddr_random = value;
918 		goto out;
919 	}
920 
921 	data = iwl_dbgfs_is_match("num_of_ap=", buf);
922 	if (data) {
923 		ret = kstrtou32(data, 10, &value);
924 		if (ret == 0)
925 			mvm->tof_data.range_req.num_of_ap = value;
926 		goto out;
927 	}
928 
929 	data = iwl_dbgfs_is_match("macaddr_template=", buf);
930 	if (data) {
931 		u8 mac[ETH_ALEN];
932 
933 		if (!mac_pton(data, mac)) {
934 			ret = -EINVAL;
935 			goto out;
936 		}
937 		memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN);
938 		goto out;
939 	}
940 
941 	data = iwl_dbgfs_is_match("macaddr_mask=", buf);
942 	if (data) {
943 		u8 mac[ETH_ALEN];
944 
945 		if (!mac_pton(data, mac)) {
946 			ret = -EINVAL;
947 			goto out;
948 		}
949 		memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN);
950 		goto out;
951 	}
952 
953 	data = iwl_dbgfs_is_match("ap=", buf);
954 	if (data) {
955 		struct iwl_tof_range_req_ap_entry ap = {};
956 		int size = sizeof(struct iwl_tof_range_req_ap_entry);
957 		u16 burst_period;
958 		u8 *mac = ap.bssid;
959 		unsigned int i;
960 
961 		if (sscanf(data, "%u %hhd %hhd %hhd"
962 			   "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"
963 			   "%hhd %hhd %hd"
964 			   "%hhd %hhd %d"
965 			   "%hhx %hhd %hhd %hhd",
966 			   &i, &ap.channel_num, &ap.bandwidth,
967 			   &ap.ctrl_ch_position,
968 			   mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
969 			   &ap.measure_type, &ap.num_of_bursts,
970 			   &burst_period,
971 			   &ap.samples_per_burst, &ap.retries_per_sample,
972 			   &ap.tsf_delta, &ap.location_req, &ap.asap_mode,
973 			   &ap.enable_dyn_ack, &ap.rssi) != 20) {
974 			ret = -EINVAL;
975 			goto out;
976 		}
977 		if (i >= IWL_MVM_TOF_MAX_APS) {
978 			IWL_ERR(mvm, "Invalid AP index %d\n", i);
979 			ret = -EINVAL;
980 			goto out;
981 		}
982 
983 		ap.burst_period = cpu_to_le16(burst_period);
984 
985 		memcpy(&mvm->tof_data.range_req.ap[i], &ap, size);
986 		goto out;
987 	}
988 
989 	data = iwl_dbgfs_is_match("send_range_request=", buf);
990 	if (data) {
991 		ret = kstrtou32(data, 10, &value);
992 		if (ret == 0 && value)
993 			ret = iwl_mvm_tof_range_request_cmd(mvm, vif);
994 		goto out;
995 	}
996 
997 	ret = -EINVAL;
998 out:
999 	mutex_unlock(&mvm->mutex);
1000 	return ret ?: count;
1001 }
1002 
1003 static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file,
1004 						char __user *user_buf,
1005 						size_t count, loff_t *ppos)
1006 {
1007 	struct ieee80211_vif *vif = file->private_data;
1008 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1009 	struct iwl_mvm *mvm = mvmvif->mvm;
1010 	char buf[512];
1011 	int pos = 0;
1012 	const size_t bufsz = sizeof(buf);
1013 	struct iwl_tof_range_req_cmd *cmd;
1014 	int i;
1015 
1016 	cmd = &mvm->tof_data.range_req;
1017 
1018 	mutex_lock(&mvm->mutex);
1019 
1020 	pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n",
1021 			 cmd->request_id);
1022 	pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n",
1023 			 cmd->initiator);
1024 	pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n",
1025 			 cmd->one_sided_los_disable);
1026 	pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n",
1027 			 cmd->req_timeout);
1028 	pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n",
1029 			 cmd->report_policy);
1030 	pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n",
1031 			 cmd->macaddr_random);
1032 	pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n",
1033 			 cmd->macaddr_template);
1034 	pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n",
1035 			 cmd->macaddr_mask);
1036 	pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n",
1037 			 cmd->num_of_ap);
1038 	for (i = 0; i < cmd->num_of_ap; i++) {
1039 		struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i];
1040 
1041 		pos += scnprintf(buf + pos, bufsz - pos,
1042 				"ap %.2d: channel_num=%hhd bw=%hhd"
1043 				" control=%hhd bssid=%pM type=%hhd"
1044 				" num_of_bursts=%hhd burst_period=%hd ftm=%hhd"
1045 				" retries=%hhd tsf_delta=%d"
1046 				" tsf_delta_direction=%hhd location_req=0x%hhx "
1047 				" asap=%hhd enable=%hhd rssi=%hhd\n",
1048 				i, ap->channel_num, ap->bandwidth,
1049 				ap->ctrl_ch_position, ap->bssid,
1050 				ap->measure_type, ap->num_of_bursts,
1051 				ap->burst_period, ap->samples_per_burst,
1052 				ap->retries_per_sample, ap->tsf_delta,
1053 				ap->tsf_delta_direction,
1054 				ap->location_req, ap->asap_mode,
1055 				ap->enable_dyn_ack, ap->rssi);
1056 	}
1057 
1058 	mutex_unlock(&mvm->mutex);
1059 
1060 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1061 }
1062 
1063 static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
1064 						 char *buf,
1065 						 size_t count, loff_t *ppos)
1066 {
1067 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1068 	struct iwl_mvm *mvm = mvmvif->mvm;
1069 	u32 value;
1070 	int ret = 0;
1071 	char *data;
1072 
1073 	mutex_lock(&mvm->mutex);
1074 
1075 	data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf);
1076 	if (data) {
1077 		ret = kstrtou32(data, 10, &value);
1078 		if (ret == 0)
1079 			mvm->tof_data.range_req_ext.tsf_timer_offset_msec =
1080 							cpu_to_le16(value);
1081 		goto out;
1082 	}
1083 
1084 	data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
1085 	if (data) {
1086 		ret = kstrtou32(data, 10, &value);
1087 		if (ret == 0)
1088 			mvm->tof_data.range_req_ext.min_delta_ftm = value;
1089 		goto out;
1090 	}
1091 
1092 	data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf);
1093 	if (data) {
1094 		ret = kstrtou32(data, 10, &value);
1095 		if (ret == 0)
1096 			mvm->tof_data.range_req_ext.ftm_format_and_bw20M =
1097 									value;
1098 		goto out;
1099 	}
1100 
1101 	data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf);
1102 	if (data) {
1103 		ret = kstrtou32(data, 10, &value);
1104 		if (ret == 0)
1105 			mvm->tof_data.range_req_ext.ftm_format_and_bw40M =
1106 									value;
1107 		goto out;
1108 	}
1109 
1110 	data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf);
1111 	if (data) {
1112 		ret = kstrtou32(data, 10, &value);
1113 		if (ret == 0)
1114 			mvm->tof_data.range_req_ext.ftm_format_and_bw80M =
1115 									value;
1116 		goto out;
1117 	}
1118 
1119 	data = iwl_dbgfs_is_match("send_range_req_ext=", buf);
1120 	if (data) {
1121 		ret = kstrtou32(data, 10, &value);
1122 		if (ret == 0 && value)
1123 			ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif);
1124 		goto out;
1125 	}
1126 
1127 	ret = -EINVAL;
1128 out:
1129 	mutex_unlock(&mvm->mutex);
1130 	return ret ?: count;
1131 }
1132 
1133 static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file,
1134 						char __user *user_buf,
1135 						size_t count, loff_t *ppos)
1136 {
1137 	struct ieee80211_vif *vif = file->private_data;
1138 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1139 	struct iwl_mvm *mvm = mvmvif->mvm;
1140 	char buf[256];
1141 	int pos = 0;
1142 	const size_t bufsz = sizeof(buf);
1143 	struct iwl_tof_range_req_ext_cmd *cmd;
1144 
1145 	cmd = &mvm->tof_data.range_req_ext;
1146 
1147 	mutex_lock(&mvm->mutex);
1148 
1149 	pos += scnprintf(buf + pos, bufsz - pos,
1150 			 "tsf_timer_offset_msec = %hd\n",
1151 			 cmd->tsf_timer_offset_msec);
1152 	pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n",
1153 			 cmd->min_delta_ftm);
1154 	pos += scnprintf(buf + pos, bufsz - pos,
1155 			 "ftm_format_and_bw20M = %hhd\n",
1156 			 cmd->ftm_format_and_bw20M);
1157 	pos += scnprintf(buf + pos, bufsz - pos,
1158 			 "ftm_format_and_bw40M = %hhd\n",
1159 			 cmd->ftm_format_and_bw40M);
1160 	pos += scnprintf(buf + pos, bufsz - pos,
1161 			 "ftm_format_and_bw80M = %hhd\n",
1162 			 cmd->ftm_format_and_bw80M);
1163 
1164 	mutex_unlock(&mvm->mutex);
1165 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1166 }
1167 
1168 static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif,
1169 					       char *buf,
1170 					       size_t count, loff_t *ppos)
1171 {
1172 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1173 	struct iwl_mvm *mvm = mvmvif->mvm;
1174 	u32 value;
1175 	int abort_id, ret = 0;
1176 	char *data;
1177 
1178 	mutex_lock(&mvm->mutex);
1179 
1180 	data = iwl_dbgfs_is_match("abort_id=", buf);
1181 	if (data) {
1182 		ret = kstrtou32(data, 10, &value);
1183 		if (ret == 0)
1184 			mvm->tof_data.last_abort_id = value;
1185 		goto out;
1186 	}
1187 
1188 	data = iwl_dbgfs_is_match("send_range_abort=", buf);
1189 	if (data) {
1190 		ret = kstrtou32(data, 10, &value);
1191 		if (ret == 0 && value) {
1192 			abort_id = mvm->tof_data.last_abort_id;
1193 			ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id);
1194 			goto out;
1195 		}
1196 	}
1197 
1198 out:
1199 	mutex_unlock(&mvm->mutex);
1200 	return ret ?: count;
1201 }
1202 
1203 static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file,
1204 					      char __user *user_buf,
1205 					      size_t count, loff_t *ppos)
1206 {
1207 	struct ieee80211_vif *vif = file->private_data;
1208 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1209 	struct iwl_mvm *mvm = mvmvif->mvm;
1210 	char buf[32];
1211 	int pos = 0;
1212 	const size_t bufsz = sizeof(buf);
1213 	int last_abort_id;
1214 
1215 	mutex_lock(&mvm->mutex);
1216 	last_abort_id = mvm->tof_data.last_abort_id;
1217 	mutex_unlock(&mvm->mutex);
1218 
1219 	pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n",
1220 			 last_abort_id);
1221 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1222 }
1223 
1224 static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file,
1225 						 char __user *user_buf,
1226 						 size_t count, loff_t *ppos)
1227 {
1228 	struct ieee80211_vif *vif = file->private_data;
1229 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1230 	struct iwl_mvm *mvm = mvmvif->mvm;
1231 	char *buf;
1232 	int pos = 0;
1233 	const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256;
1234 	struct iwl_tof_range_rsp_ntfy *cmd;
1235 	int i, ret;
1236 
1237 	buf = kzalloc(bufsz, GFP_KERNEL);
1238 	if (!buf)
1239 		return -ENOMEM;
1240 
1241 	mutex_lock(&mvm->mutex);
1242 	cmd = &mvm->tof_data.range_resp;
1243 
1244 	pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n",
1245 			 cmd->request_id);
1246 	pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n",
1247 			 cmd->request_status);
1248 	pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n",
1249 			 cmd->last_in_batch);
1250 	pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n",
1251 			 cmd->num_of_aps);
1252 	for (i = 0; i < cmd->num_of_aps; i++) {
1253 		struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i];
1254 
1255 		pos += scnprintf(buf + pos, bufsz - pos,
1256 				"ap %.2d: bssid=%pM status=%hhd bw=%hhd"
1257 				" rtt=%d rtt_var=%d rtt_spread=%d"
1258 				" rssi=%hhd  rssi_spread=%hhd"
1259 				" range=%d range_var=%d"
1260 				" time_stamp=%d\n",
1261 				i, ap->bssid, ap->measure_status,
1262 				ap->measure_bw,
1263 				ap->rtt, ap->rtt_variance, ap->rtt_spread,
1264 				ap->rssi, ap->rssi_spread, ap->range,
1265 				ap->range_variance, ap->timestamp);
1266 	}
1267 	mutex_unlock(&mvm->mutex);
1268 
1269 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1270 	kfree(buf);
1271 	return ret;
1272 }
1273 
1274 static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
1275 					   size_t count, loff_t *ppos)
1276 {
1277 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1278 	struct iwl_mvm *mvm = mvmvif->mvm;
1279 	bool prev;
1280 	u8 value;
1281 	int ret;
1282 
1283 	ret = kstrtou8(buf, 0, &value);
1284 	if (ret)
1285 		return ret;
1286 	if (value > 1)
1287 		return -EINVAL;
1288 
1289 	mutex_lock(&mvm->mutex);
1290 	prev = iwl_mvm_vif_low_latency(mvmvif);
1291 	mvmvif->low_latency_dbgfs = value;
1292 	iwl_mvm_update_low_latency(mvm, vif, prev);
1293 	mutex_unlock(&mvm->mutex);
1294 
1295 	return count;
1296 }
1297 
1298 static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
1299 					  char __user *user_buf,
1300 					  size_t count, loff_t *ppos)
1301 {
1302 	struct ieee80211_vif *vif = file->private_data;
1303 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1304 	char buf[30] = {};
1305 	int len;
1306 
1307 	len = scnprintf(buf, sizeof(buf) - 1,
1308 			"traffic=%d\ndbgfs=%d\nvcmd=%d\n",
1309 			mvmvif->low_latency_traffic,
1310 			mvmvif->low_latency_dbgfs,
1311 			mvmvif->low_latency_vcmd);
1312 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1313 }
1314 
1315 static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
1316 						char __user *user_buf,
1317 						size_t count, loff_t *ppos)
1318 {
1319 	struct ieee80211_vif *vif = file->private_data;
1320 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1321 	char buf[20];
1322 	int len;
1323 
1324 	len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
1325 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1326 }
1327 
1328 static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
1329 						 char *buf, size_t count,
1330 						 loff_t *ppos)
1331 {
1332 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1333 	struct iwl_mvm *mvm = mvmvif->mvm;
1334 	bool ret;
1335 
1336 	mutex_lock(&mvm->mutex);
1337 	ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
1338 	mutex_unlock(&mvm->mutex);
1339 
1340 	return ret ? count : -EINVAL;
1341 }
1342 
1343 static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
1344 					  size_t count, loff_t *ppos)
1345 {
1346 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1347 	struct iwl_mvm *mvm = mvmvif->mvm;
1348 	struct ieee80211_chanctx_conf *chanctx_conf;
1349 	struct iwl_mvm_phy_ctxt *phy_ctxt;
1350 	u16 value;
1351 	int ret;
1352 
1353 	ret = kstrtou16(buf, 0, &value);
1354 	if (ret)
1355 		return ret;
1356 
1357 	mutex_lock(&mvm->mutex);
1358 	rcu_read_lock();
1359 
1360 	chanctx_conf = rcu_dereference(vif->chanctx_conf);
1361 	/* make sure the channel context is assigned */
1362 	if (!chanctx_conf) {
1363 		rcu_read_unlock();
1364 		mutex_unlock(&mvm->mutex);
1365 		return -EINVAL;
1366 	}
1367 
1368 	phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
1369 	rcu_read_unlock();
1370 
1371 	mvm->dbgfs_rx_phyinfo = value;
1372 
1373 	ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
1374 				       chanctx_conf->rx_chains_static,
1375 				       chanctx_conf->rx_chains_dynamic);
1376 	mutex_unlock(&mvm->mutex);
1377 
1378 	return ret ?: count;
1379 }
1380 
1381 static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
1382 					 char __user *user_buf,
1383 					 size_t count, loff_t *ppos)
1384 {
1385 	struct ieee80211_vif *vif = file->private_data;
1386 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1387 	char buf[8];
1388 	int len;
1389 
1390 	len = scnprintf(buf, sizeof(buf), "0x%04x\n",
1391 			mvmvif->mvm->dbgfs_rx_phyinfo);
1392 
1393 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1394 }
1395 
1396 static void iwl_dbgfs_quota_check(void *data, u8 *mac,
1397 				  struct ieee80211_vif *vif)
1398 {
1399 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1400 	int *ret = data;
1401 
1402 	if (mvmvif->dbgfs_quota_min)
1403 		*ret = -EINVAL;
1404 }
1405 
1406 static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
1407 					 size_t count, loff_t *ppos)
1408 {
1409 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1410 	struct iwl_mvm *mvm = mvmvif->mvm;
1411 	u16 value;
1412 	int ret;
1413 
1414 	ret = kstrtou16(buf, 0, &value);
1415 	if (ret)
1416 		return ret;
1417 
1418 	if (value > 95)
1419 		return -EINVAL;
1420 
1421 	mutex_lock(&mvm->mutex);
1422 
1423 	mvmvif->dbgfs_quota_min = 0;
1424 	ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1425 				     iwl_dbgfs_quota_check, &ret);
1426 	if (ret == 0) {
1427 		mvmvif->dbgfs_quota_min = value;
1428 		iwl_mvm_update_quotas(mvm, false, NULL);
1429 	}
1430 	mutex_unlock(&mvm->mutex);
1431 
1432 	return ret ?: count;
1433 }
1434 
1435 static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
1436 					char __user *user_buf,
1437 					size_t count, loff_t *ppos)
1438 {
1439 	struct ieee80211_vif *vif = file->private_data;
1440 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1441 	char buf[10];
1442 	int len;
1443 
1444 	len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
1445 
1446 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1447 }
1448 
1449 static const char * const chanwidths[] = {
1450 	[NL80211_CHAN_WIDTH_20_NOHT] = "noht",
1451 	[NL80211_CHAN_WIDTH_20] = "ht20",
1452 	[NL80211_CHAN_WIDTH_40] = "ht40",
1453 	[NL80211_CHAN_WIDTH_80] = "vht80",
1454 	[NL80211_CHAN_WIDTH_80P80] = "vht80p80",
1455 	[NL80211_CHAN_WIDTH_160] = "vht160",
1456 };
1457 
1458 static bool iwl_mvm_lqm_notif_wait(struct iwl_notif_wait_data *notif_wait,
1459 				   struct iwl_rx_packet *pkt, void *data)
1460 {
1461 	struct ieee80211_vif *vif = data;
1462 	struct iwl_mvm *mvm =
1463 		container_of(notif_wait, struct iwl_mvm, notif_wait);
1464 	struct iwl_link_qual_msrmnt_notif *report = (void *)pkt->data;
1465 	u32 num_of_stations = le32_to_cpu(report->number_of_stations);
1466 	int i;
1467 
1468 	IWL_INFO(mvm, "LQM report:\n");
1469 	IWL_INFO(mvm, "\tstatus: %d\n", report->status);
1470 	IWL_INFO(mvm, "\tmacID: %d\n", le32_to_cpu(report->mac_id));
1471 	IWL_INFO(mvm, "\ttx_frame_dropped: %d\n",
1472 		 le32_to_cpu(report->tx_frame_dropped));
1473 	IWL_INFO(mvm, "\ttime_in_measurement_window: %d us\n",
1474 		 le32_to_cpu(report->time_in_measurement_window));
1475 	IWL_INFO(mvm, "\ttotal_air_time_other_stations: %d\n",
1476 		 le32_to_cpu(report->total_air_time_other_stations));
1477 	IWL_INFO(mvm, "\tchannel_freq: %d\n",
1478 		 vif->bss_conf.chandef.center_freq1);
1479 	IWL_INFO(mvm, "\tchannel_width: %s\n",
1480 		 chanwidths[vif->bss_conf.chandef.width]);
1481 	IWL_INFO(mvm, "\tnumber_of_stations: %d\n", num_of_stations);
1482 	for (i = 0; i < num_of_stations; i++)
1483 		IWL_INFO(mvm, "\t\tsta[%d]: %d\n", i,
1484 			 report->frequent_stations_air_time[i]);
1485 
1486 	return true;
1487 }
1488 
1489 static ssize_t iwl_dbgfs_lqm_send_cmd_write(struct ieee80211_vif *vif,
1490 					    char *buf, size_t count,
1491 					    loff_t *ppos)
1492 {
1493 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1494 	struct iwl_mvm *mvm = mvmvif->mvm;
1495 	struct iwl_notification_wait wait_lqm_notif;
1496 	static u16 lqm_notif[] = {
1497 		WIDE_ID(MAC_CONF_GROUP,
1498 			LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF)
1499 	};
1500 	int err;
1501 	u32 duration;
1502 	u32 timeout;
1503 
1504 	if (sscanf(buf, "%d,%d", &duration, &timeout) != 2)
1505 		return -EINVAL;
1506 
1507 	iwl_init_notification_wait(&mvm->notif_wait, &wait_lqm_notif,
1508 				   lqm_notif, ARRAY_SIZE(lqm_notif),
1509 				   iwl_mvm_lqm_notif_wait, vif);
1510 	mutex_lock(&mvm->mutex);
1511 	err = iwl_mvm_send_lqm_cmd(vif, LQM_CMD_OPERATION_START_MEASUREMENT,
1512 				   duration, timeout);
1513 	mutex_unlock(&mvm->mutex);
1514 
1515 	if (err) {
1516 		IWL_ERR(mvm, "Failed to send lqm cmdf(err=%d)\n", err);
1517 		iwl_remove_notification(&mvm->notif_wait, &wait_lqm_notif);
1518 		return err;
1519 	}
1520 
1521 	/* wait for 2 * timeout (safety guard) and convert to jiffies*/
1522 	timeout = msecs_to_jiffies((timeout * 2) / 1000);
1523 
1524 	err = iwl_wait_notification(&mvm->notif_wait, &wait_lqm_notif,
1525 				    timeout);
1526 	if (err)
1527 		IWL_ERR(mvm, "Getting lqm notif timed out\n");
1528 
1529 	return count;
1530 }
1531 
1532 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1533 	_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1534 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1535 	_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1536 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {		\
1537 		if (!debugfs_create_file(#name, mode, parent, vif,	\
1538 					 &iwl_dbgfs_##name##_ops))	\
1539 			goto err;					\
1540 	} while (0)
1541 
1542 MVM_DEBUGFS_READ_FILE_OPS(mac_params);
1543 MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
1544 MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
1545 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
1546 MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
1547 MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
1548 MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
1549 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32);
1550 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512);
1551 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
1552 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
1553 MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
1554 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
1555 MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
1556 MVM_DEBUGFS_WRITE_FILE_OPS(lqm_send_cmd, 64);
1557 MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
1558 
1559 
1560 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1561 {
1562 	struct dentry *dbgfs_dir = vif->debugfs_dir;
1563 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1564 	char buf[100];
1565 
1566 	/*
1567 	 * Check if debugfs directory already exist before creating it.
1568 	 * This may happen when, for example, resetting hw or suspend-resume
1569 	 */
1570 	if (!dbgfs_dir || mvmvif->dbgfs_dir)
1571 		return;
1572 
1573 	mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
1574 
1575 	if (!mvmvif->dbgfs_dir) {
1576 		IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
1577 			dbgfs_dir);
1578 		return;
1579 	}
1580 
1581 	if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
1582 	    ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
1583 	     (vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
1584 		MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
1585 					 S_IRUSR);
1586 
1587 	MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR);
1588 	MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR);
1589 	MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir,
1590 				 S_IRUSR | S_IWUSR);
1591 	MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir,
1592 				 S_IRUSR | S_IWUSR);
1593 	MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir,
1594 				 S_IRUSR | S_IWUSR);
1595 	MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
1596 				 S_IRUSR | S_IWUSR);
1597 	MVM_DEBUGFS_ADD_FILE_VIF(lqm_send_cmd, mvmvif->dbgfs_dir, S_IWUSR);
1598 	MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff,
1599 				 mvmvif->dbgfs_dir, S_IRUSR);
1600 
1601 	if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
1602 	    mvmvif == mvm->bf_allowed_vif)
1603 		MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
1604 					 S_IRUSR | S_IWUSR);
1605 
1606 	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) &&
1607 	    !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) {
1608 		if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP)
1609 			MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params,
1610 						 mvmvif->dbgfs_dir,
1611 						 S_IRUSR | S_IWUSR);
1612 
1613 		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir,
1614 					 S_IRUSR | S_IWUSR);
1615 		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir,
1616 					 S_IRUSR | S_IWUSR);
1617 		MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir,
1618 					 S_IRUSR | S_IWUSR);
1619 		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir,
1620 					 S_IRUSR | S_IWUSR);
1621 		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir,
1622 					 S_IRUSR);
1623 	}
1624 
1625 	/*
1626 	 * Create symlink for convenience pointing to interface specific
1627 	 * debugfs entries for the driver. For example, under
1628 	 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
1629 	 * find
1630 	 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
1631 	 */
1632 	snprintf(buf, 100, "../../../%pd3/%pd",
1633 		 dbgfs_dir,
1634 		 mvmvif->dbgfs_dir);
1635 
1636 	mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
1637 						     mvm->debugfs_dir, buf);
1638 	if (!mvmvif->dbgfs_slink)
1639 		IWL_ERR(mvm, "Can't create debugfs symbolic link under %pd\n",
1640 			dbgfs_dir);
1641 	return;
1642 err:
1643 	IWL_ERR(mvm, "Can't create debugfs entity\n");
1644 }
1645 
1646 void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1647 {
1648 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1649 
1650 	debugfs_remove(mvmvif->dbgfs_slink);
1651 	mvmvif->dbgfs_slink = NULL;
1652 
1653 	debugfs_remove_recursive(mvmvif->dbgfs_dir);
1654 	mvmvif->dbgfs_dir = NULL;
1655 }
1656