blob: 398bef6f4f6147c66b1b35bedbf02af4a3d4219f [file] [log] [blame]
Johannes Berg820a1a52013-11-12 16:58:41 +01001/******************************************************************************
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 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +02008 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
Matti Gottlieb25870cb2015-05-04 09:34:37 +03009 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
Johannes Berg820a1a52013-11-12 16:58:41 +010010 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
23 * USA
24 *
25 * The full GNU General Public License is included in this distribution
26 * in the file called COPYING.
27 *
28 * Contact Information:
29 * Intel Linux Wireless <ilw@linux.intel.com>
30 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
31 *
32 * BSD LICENSE
33 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +020034 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
Matti Gottlieb25870cb2015-05-04 09:34:37 +030035 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
Johannes Berg820a1a52013-11-12 16:58:41 +010036 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 *
42 * * Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * * Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in
46 * the documentation and/or other materials provided with the
47 * distribution.
48 * * Neither the name Intel Corporation nor the names of its
49 * contributors may be used to endorse or promote products derived
50 * from this software without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
53 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
54 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
55 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
56 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
57 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
58 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
62 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 *
64 *****************************************************************************/
65#include "mvm.h"
Gregory Greenmance792912015-06-02 18:06:16 +030066#include "fw-api-tof.h"
Johannes Berg820a1a52013-11-12 16:58:41 +010067#include "debugfs.h"
68
Alexander Bondare45a9412013-12-04 10:13:24 +020069static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
70 struct ieee80211_vif *vif,
71 enum iwl_dbgfs_pm_mask param, int val)
72{
73 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
74 struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
75
76 dbgfs_pm->mask |= param;
77
78 switch (param) {
79 case MVM_DEBUGFS_PM_KEEP_ALIVE: {
Emmanuel Grumbach717e2392014-07-31 14:39:40 +030080 int dtimper = vif->bss_conf.dtim_period ?: 1;
Alexander Bondare45a9412013-12-04 10:13:24 +020081 int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
82
83 IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
84 if (val * MSEC_PER_SEC < 3 * dtimper_msec)
85 IWL_WARN(mvm,
86 "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
87 val * MSEC_PER_SEC, 3 * dtimper_msec);
88 dbgfs_pm->keep_alive_seconds = val;
89 break;
90 }
91 case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
92 IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
93 val ? "enabled" : "disabled");
94 dbgfs_pm->skip_over_dtim = val;
95 break;
96 case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
97 IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
98 dbgfs_pm->skip_dtim_periods = val;
99 break;
100 case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
101 IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
102 dbgfs_pm->rx_data_timeout = val;
103 break;
104 case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
105 IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
106 dbgfs_pm->tx_data_timeout = val;
107 break;
Alexander Bondare45a9412013-12-04 10:13:24 +0200108 case MVM_DEBUGFS_PM_LPRX_ENA:
109 IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
110 dbgfs_pm->lprx_ena = val;
111 break;
112 case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
113 IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
114 dbgfs_pm->lprx_rssi_threshold = val;
115 break;
116 case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
117 IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
118 dbgfs_pm->snooze_ena = val;
119 break;
120 case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
121 IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
122 dbgfs_pm->uapsd_misbehaving = val;
123 break;
Eliad Peller84fd7602014-07-30 15:42:19 +0300124 case MVM_DEBUGFS_PM_USE_PS_POLL:
125 IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val);
126 dbgfs_pm->use_ps_poll = val;
127 break;
Alexander Bondare45a9412013-12-04 10:13:24 +0200128 }
129}
130
131static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
132 size_t count, loff_t *ppos)
133{
134 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
135 struct iwl_mvm *mvm = mvmvif->mvm;
136 enum iwl_dbgfs_pm_mask param;
137 int val, ret;
138
139 if (!strncmp("keep_alive=", buf, 11)) {
140 if (sscanf(buf + 11, "%d", &val) != 1)
141 return -EINVAL;
142 param = MVM_DEBUGFS_PM_KEEP_ALIVE;
143 } else if (!strncmp("skip_over_dtim=", buf, 15)) {
144 if (sscanf(buf + 15, "%d", &val) != 1)
145 return -EINVAL;
146 param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
147 } else if (!strncmp("skip_dtim_periods=", buf, 18)) {
148 if (sscanf(buf + 18, "%d", &val) != 1)
149 return -EINVAL;
150 param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
151 } else if (!strncmp("rx_data_timeout=", buf, 16)) {
152 if (sscanf(buf + 16, "%d", &val) != 1)
153 return -EINVAL;
154 param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
155 } else if (!strncmp("tx_data_timeout=", buf, 16)) {
156 if (sscanf(buf + 16, "%d", &val) != 1)
157 return -EINVAL;
158 param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
Alexander Bondare45a9412013-12-04 10:13:24 +0200159 } else if (!strncmp("lprx=", buf, 5)) {
160 if (sscanf(buf + 5, "%d", &val) != 1)
161 return -EINVAL;
162 param = MVM_DEBUGFS_PM_LPRX_ENA;
163 } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
164 if (sscanf(buf + 20, "%d", &val) != 1)
165 return -EINVAL;
166 if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
167 POWER_LPRX_RSSI_THRESHOLD_MIN)
168 return -EINVAL;
169 param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
170 } else if (!strncmp("snooze_enable=", buf, 14)) {
171 if (sscanf(buf + 14, "%d", &val) != 1)
172 return -EINVAL;
173 param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
174 } else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
175 if (sscanf(buf + 18, "%d", &val) != 1)
176 return -EINVAL;
177 param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
Eliad Peller84fd7602014-07-30 15:42:19 +0300178 } else if (!strncmp("use_ps_poll=", buf, 12)) {
179 if (sscanf(buf + 12, "%d", &val) != 1)
180 return -EINVAL;
181 param = MVM_DEBUGFS_PM_USE_PS_POLL;
Alexander Bondare45a9412013-12-04 10:13:24 +0200182 } else {
183 return -EINVAL;
184 }
185
186 mutex_lock(&mvm->mutex);
187 iwl_dbgfs_update_pm(mvm, vif, param, val);
Arik Nemtsov999609f2014-05-15 17:31:51 +0300188 ret = iwl_mvm_power_update_mac(mvm);
Alexander Bondare45a9412013-12-04 10:13:24 +0200189 mutex_unlock(&mvm->mutex);
190
191 return ret ?: count;
192}
193
Matti Gottlieb25870cb2015-05-04 09:34:37 +0300194static ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file,
195 char __user *user_buf,
196 size_t count, loff_t *ppos)
197{
198 struct ieee80211_vif *vif = file->private_data;
199 char buf[64];
200 int bufsz = sizeof(buf);
201 int pos;
202
203 pos = scnprintf(buf, bufsz, "bss limit = %d\n",
204 vif->bss_conf.txpower);
205
206 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
207}
208
Alexander Bondare45a9412013-12-04 10:13:24 +0200209static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
210 char __user *user_buf,
211 size_t count, loff_t *ppos)
212{
213 struct ieee80211_vif *vif = file->private_data;
214 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
215 struct iwl_mvm *mvm = mvmvif->mvm;
216 char buf[512];
217 int bufsz = sizeof(buf);
218 int pos;
219
Emmanuel Grumbachc1cb92f2014-01-28 10:17:18 +0200220 pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz);
Alexander Bondare45a9412013-12-04 10:13:24 +0200221
222 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
223}
224
Johannes Berg820a1a52013-11-12 16:58:41 +0100225static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
226 char __user *user_buf,
227 size_t count, loff_t *ppos)
228{
229 struct ieee80211_vif *vif = file->private_data;
230 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
Johannes Berg7f09d702013-11-12 17:16:38 +0100231 struct iwl_mvm *mvm = mvmvif->mvm;
Johannes Berg820a1a52013-11-12 16:58:41 +0100232 u8 ap_sta_id;
233 struct ieee80211_chanctx_conf *chanctx_conf;
234 char buf[512];
235 int bufsz = sizeof(buf);
236 int pos = 0;
237 int i;
238
239 mutex_lock(&mvm->mutex);
240
241 ap_sta_id = mvmvif->ap_sta_id;
242
Emmanuel Grumbach2284b952014-01-15 16:57:03 +0200243 switch (ieee80211_vif_type_p2p(vif)) {
244 case NL80211_IFTYPE_ADHOC:
245 pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n");
246 break;
247 case NL80211_IFTYPE_STATION:
248 pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n");
249 break;
250 case NL80211_IFTYPE_AP:
251 pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n");
252 break;
253 case NL80211_IFTYPE_P2P_CLIENT:
254 pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n");
255 break;
256 case NL80211_IFTYPE_P2P_GO:
257 pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n");
258 break;
259 case NL80211_IFTYPE_P2P_DEVICE:
260 pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n");
261 break;
262 default:
263 break;
264 }
265
Johannes Berg820a1a52013-11-12 16:58:41 +0100266 pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
267 mvmvif->id, mvmvif->color);
268 pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
269 vif->bss_conf.bssid);
270 pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
271 for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++)
272 pos += scnprintf(buf+pos, bufsz-pos,
273 "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
274 i, mvmvif->queue_params[i].txop,
275 mvmvif->queue_params[i].cw_min,
276 mvmvif->queue_params[i].cw_max,
277 mvmvif->queue_params[i].aifs,
278 mvmvif->queue_params[i].uapsd);
279
280 if (vif->type == NL80211_IFTYPE_STATION &&
281 ap_sta_id != IWL_MVM_STATION_COUNT) {
282 struct ieee80211_sta *sta;
Johannes Berg820a1a52013-11-12 16:58:41 +0100283
284 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
285 lockdep_is_held(&mvm->mutex));
Johannes Berg1ddbbb02013-12-04 22:39:17 +0100286 if (!IS_ERR_OR_NULL(sta)) {
Johannes Berg9d8ce6a2014-12-23 16:02:40 +0100287 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
Johannes Berg1ddbbb02013-12-04 22:39:17 +0100288
289 pos += scnprintf(buf+pos, bufsz-pos,
Emmanuel Grumbach1fa477c2014-05-20 13:54:27 +0300290 "ap_sta_id %d - reduced Tx power %d\n",
Johannes Berg1ddbbb02013-12-04 22:39:17 +0100291 ap_sta_id,
Emmanuel Grumbach1fa477c2014-05-20 13:54:27 +0300292 mvm_sta->bt_reduced_txpower);
Johannes Berg1ddbbb02013-12-04 22:39:17 +0100293 }
Johannes Berg820a1a52013-11-12 16:58:41 +0100294 }
295
296 rcu_read_lock();
297 chanctx_conf = rcu_dereference(vif->chanctx_conf);
298 if (chanctx_conf)
299 pos += scnprintf(buf+pos, bufsz-pos,
300 "idle rx chains %d, active rx chains: %d\n",
301 chanctx_conf->rx_chains_static,
302 chanctx_conf->rx_chains_dynamic);
303 rcu_read_unlock();
304
305 mutex_unlock(&mvm->mutex);
306
307 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
308}
309
Alexander Bondare45a9412013-12-04 10:13:24 +0200310static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
311 enum iwl_dbgfs_bf_mask param, int value)
312{
313 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
314 struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
315
316 dbgfs_bf->mask |= param;
317
318 switch (param) {
319 case MVM_DEBUGFS_BF_ENERGY_DELTA:
320 dbgfs_bf->bf_energy_delta = value;
321 break;
322 case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
323 dbgfs_bf->bf_roaming_energy_delta = value;
324 break;
325 case MVM_DEBUGFS_BF_ROAMING_STATE:
326 dbgfs_bf->bf_roaming_state = value;
327 break;
328 case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
329 dbgfs_bf->bf_temp_threshold = value;
330 break;
331 case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
332 dbgfs_bf->bf_temp_fast_filter = value;
333 break;
334 case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
335 dbgfs_bf->bf_temp_slow_filter = value;
336 break;
337 case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
338 dbgfs_bf->bf_enable_beacon_filter = value;
339 break;
340 case MVM_DEBUGFS_BF_DEBUG_FLAG:
341 dbgfs_bf->bf_debug_flag = value;
342 break;
343 case MVM_DEBUGFS_BF_ESCAPE_TIMER:
344 dbgfs_bf->bf_escape_timer = value;
345 break;
346 case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
347 dbgfs_bf->ba_enable_beacon_abort = value;
348 break;
349 case MVM_DEBUGFS_BA_ESCAPE_TIMER:
350 dbgfs_bf->ba_escape_timer = value;
351 break;
352 }
353}
354
355static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
356 size_t count, loff_t *ppos)
357{
358 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
359 struct iwl_mvm *mvm = mvmvif->mvm;
360 enum iwl_dbgfs_bf_mask param;
361 int value, ret = 0;
362
363 if (!strncmp("bf_energy_delta=", buf, 16)) {
364 if (sscanf(buf+16, "%d", &value) != 1)
365 return -EINVAL;
366 if (value < IWL_BF_ENERGY_DELTA_MIN ||
367 value > IWL_BF_ENERGY_DELTA_MAX)
368 return -EINVAL;
369 param = MVM_DEBUGFS_BF_ENERGY_DELTA;
370 } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
371 if (sscanf(buf+24, "%d", &value) != 1)
372 return -EINVAL;
373 if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
374 value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
375 return -EINVAL;
376 param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
377 } else if (!strncmp("bf_roaming_state=", buf, 17)) {
378 if (sscanf(buf+17, "%d", &value) != 1)
379 return -EINVAL;
380 if (value < IWL_BF_ROAMING_STATE_MIN ||
381 value > IWL_BF_ROAMING_STATE_MAX)
382 return -EINVAL;
383 param = MVM_DEBUGFS_BF_ROAMING_STATE;
384 } else if (!strncmp("bf_temp_threshold=", buf, 18)) {
385 if (sscanf(buf+18, "%d", &value) != 1)
386 return -EINVAL;
387 if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
388 value > IWL_BF_TEMP_THRESHOLD_MAX)
389 return -EINVAL;
390 param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
391 } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
392 if (sscanf(buf+20, "%d", &value) != 1)
393 return -EINVAL;
394 if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
395 value > IWL_BF_TEMP_FAST_FILTER_MAX)
396 return -EINVAL;
397 param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
398 } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
399 if (sscanf(buf+20, "%d", &value) != 1)
400 return -EINVAL;
401 if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
402 value > IWL_BF_TEMP_SLOW_FILTER_MAX)
403 return -EINVAL;
404 param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
405 } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
406 if (sscanf(buf+24, "%d", &value) != 1)
407 return -EINVAL;
408 if (value < 0 || value > 1)
409 return -EINVAL;
410 param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
411 } else if (!strncmp("bf_debug_flag=", buf, 14)) {
412 if (sscanf(buf+14, "%d", &value) != 1)
413 return -EINVAL;
414 if (value < 0 || value > 1)
415 return -EINVAL;
416 param = MVM_DEBUGFS_BF_DEBUG_FLAG;
417 } else if (!strncmp("bf_escape_timer=", buf, 16)) {
418 if (sscanf(buf+16, "%d", &value) != 1)
419 return -EINVAL;
420 if (value < IWL_BF_ESCAPE_TIMER_MIN ||
421 value > IWL_BF_ESCAPE_TIMER_MAX)
422 return -EINVAL;
423 param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
424 } else if (!strncmp("ba_escape_timer=", buf, 16)) {
425 if (sscanf(buf+16, "%d", &value) != 1)
426 return -EINVAL;
427 if (value < IWL_BA_ESCAPE_TIMER_MIN ||
428 value > IWL_BA_ESCAPE_TIMER_MAX)
429 return -EINVAL;
430 param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
431 } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
432 if (sscanf(buf+23, "%d", &value) != 1)
433 return -EINVAL;
434 if (value < 0 || value > 1)
435 return -EINVAL;
436 param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
437 } else {
438 return -EINVAL;
439 }
440
441 mutex_lock(&mvm->mutex);
442 iwl_dbgfs_update_bf(vif, param, value);
443 if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
Emmanuel Grumbacha1022922014-05-12 11:36:41 +0300444 ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
Alexander Bondare45a9412013-12-04 10:13:24 +0200445 else
Emmanuel Grumbacha1022922014-05-12 11:36:41 +0300446 ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0);
Alexander Bondare45a9412013-12-04 10:13:24 +0200447 mutex_unlock(&mvm->mutex);
448
449 return ret ?: count;
450}
451
452static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
453 char __user *user_buf,
454 size_t count, loff_t *ppos)
455{
456 struct ieee80211_vif *vif = file->private_data;
457 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
458 char buf[256];
459 int pos = 0;
460 const size_t bufsz = sizeof(buf);
461 struct iwl_beacon_filter_cmd cmd = {
462 IWL_BF_CMD_CONFIG_DEFAULTS,
463 .bf_enable_beacon_filter =
464 cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
465 .ba_enable_beacon_abort =
466 cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
467 };
468
469 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
470 if (mvmvif->bf_data.bf_enabled)
471 cmd.bf_enable_beacon_filter = cpu_to_le32(1);
472 else
473 cmd.bf_enable_beacon_filter = 0;
474
475 pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
476 le32_to_cpu(cmd.bf_energy_delta));
477 pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
478 le32_to_cpu(cmd.bf_roaming_energy_delta));
479 pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
480 le32_to_cpu(cmd.bf_roaming_state));
481 pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
482 le32_to_cpu(cmd.bf_temp_threshold));
483 pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
484 le32_to_cpu(cmd.bf_temp_fast_filter));
485 pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
486 le32_to_cpu(cmd.bf_temp_slow_filter));
487 pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
488 le32_to_cpu(cmd.bf_enable_beacon_filter));
489 pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
490 le32_to_cpu(cmd.bf_debug_flag));
491 pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
492 le32_to_cpu(cmd.bf_escape_timer));
493 pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
494 le32_to_cpu(cmd.ba_escape_timer));
495 pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
496 le32_to_cpu(cmd.ba_enable_beacon_abort));
497
498 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
499}
500
Gregory Greenmance792912015-06-02 18:06:16 +0300501static inline char *iwl_dbgfs_is_match(char *name, char *buf)
502{
503 int len = strlen(name);
504
505 return !strncmp(name, buf, len) ? buf + len : NULL;
506}
507
508static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
509 char *buf,
510 size_t count, loff_t *ppos)
511{
512 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
513 struct iwl_mvm *mvm = mvmvif->mvm;
Johannes Berge6c21be2015-09-24 22:15:02 +0200514 u32 value;
515 int ret = -EINVAL;
Gregory Greenmance792912015-06-02 18:06:16 +0300516 char *data;
517
518 mutex_lock(&mvm->mutex);
519
520 data = iwl_dbgfs_is_match("tof_disabled=", buf);
521 if (data) {
522 ret = kstrtou32(data, 10, &value);
523 if (ret == 0)
524 mvm->tof_data.tof_cfg.tof_disabled = value;
525 goto out;
526 }
527
528 data = iwl_dbgfs_is_match("one_sided_disabled=", buf);
529 if (data) {
530 ret = kstrtou32(data, 10, &value);
531 if (ret == 0)
532 mvm->tof_data.tof_cfg.one_sided_disabled = value;
533 goto out;
534 }
535
536 data = iwl_dbgfs_is_match("is_debug_mode=", buf);
537 if (data) {
538 ret = kstrtou32(data, 10, &value);
539 if (ret == 0)
540 mvm->tof_data.tof_cfg.is_debug_mode = value;
541 goto out;
542 }
543
544 data = iwl_dbgfs_is_match("is_buf=", buf);
545 if (data) {
546 ret = kstrtou32(data, 10, &value);
547 if (ret == 0)
548 mvm->tof_data.tof_cfg.is_buf_required = value;
549 goto out;
550 }
551
552 data = iwl_dbgfs_is_match("send_tof_cfg=", buf);
553 if (data) {
554 ret = kstrtou32(data, 10, &value);
555 if (ret == 0 && value) {
556 ret = iwl_mvm_tof_config_cmd(mvm);
557 goto out;
558 }
559 }
560
561out:
562 mutex_unlock(&mvm->mutex);
563
564 return ret ?: count;
565}
566
567static ssize_t iwl_dbgfs_tof_enable_read(struct file *file,
568 char __user *user_buf,
569 size_t count, loff_t *ppos)
570{
571 struct ieee80211_vif *vif = file->private_data;
572 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
573 struct iwl_mvm *mvm = mvmvif->mvm;
574 char buf[256];
575 int pos = 0;
576 const size_t bufsz = sizeof(buf);
577 struct iwl_tof_config_cmd *cmd;
578
579 cmd = &mvm->tof_data.tof_cfg;
580
581 mutex_lock(&mvm->mutex);
582
583 pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n",
584 cmd->tof_disabled);
585 pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n",
586 cmd->one_sided_disabled);
587 pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n",
588 cmd->is_debug_mode);
589 pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n",
590 cmd->is_buf_required);
591
592 mutex_unlock(&mvm->mutex);
593
594 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
595}
596
597static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
598 char *buf,
599 size_t count, loff_t *ppos)
600{
601 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
602 struct iwl_mvm *mvm = mvmvif->mvm;
Johannes Berge6c21be2015-09-24 22:15:02 +0200603 u32 value;
604 int ret = 0;
Gregory Greenmance792912015-06-02 18:06:16 +0300605 char *data;
606
607 mutex_lock(&mvm->mutex);
608
609 data = iwl_dbgfs_is_match("burst_period=", buf);
610 if (data) {
611 ret = kstrtou32(data, 10, &value);
612 if (!ret)
613 mvm->tof_data.responder_cfg.burst_period =
614 cpu_to_le16(value);
615 goto out;
616 }
617
618 data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
619 if (data) {
620 ret = kstrtou32(data, 10, &value);
621 if (ret == 0)
622 mvm->tof_data.responder_cfg.min_delta_ftm = value;
623 goto out;
624 }
625
626 data = iwl_dbgfs_is_match("burst_duration=", buf);
627 if (data) {
628 ret = kstrtou32(data, 10, &value);
629 if (ret == 0)
630 mvm->tof_data.responder_cfg.burst_duration = value;
631 goto out;
632 }
633
634 data = iwl_dbgfs_is_match("num_of_burst_exp=", buf);
635 if (data) {
636 ret = kstrtou32(data, 10, &value);
637 if (ret == 0)
638 mvm->tof_data.responder_cfg.num_of_burst_exp = value;
639 goto out;
640 }
641
642 data = iwl_dbgfs_is_match("abort_responder=", buf);
643 if (data) {
644 ret = kstrtou32(data, 10, &value);
645 if (ret == 0)
646 mvm->tof_data.responder_cfg.abort_responder = value;
647 goto out;
648 }
649
650 data = iwl_dbgfs_is_match("get_ch_est=", buf);
651 if (data) {
652 ret = kstrtou32(data, 10, &value);
653 if (ret == 0)
654 mvm->tof_data.responder_cfg.get_ch_est = value;
655 goto out;
656 }
657
658 data = iwl_dbgfs_is_match("recv_sta_req_params=", buf);
659 if (data) {
660 ret = kstrtou32(data, 10, &value);
661 if (ret == 0)
662 mvm->tof_data.responder_cfg.recv_sta_req_params = value;
663 goto out;
664 }
665
666 data = iwl_dbgfs_is_match("channel_num=", buf);
667 if (data) {
668 ret = kstrtou32(data, 10, &value);
669 if (ret == 0)
670 mvm->tof_data.responder_cfg.channel_num = value;
671 goto out;
672 }
673
674 data = iwl_dbgfs_is_match("bandwidth=", buf);
675 if (data) {
676 ret = kstrtou32(data, 10, &value);
677 if (ret == 0)
678 mvm->tof_data.responder_cfg.bandwidth = value;
679 goto out;
680 }
681
682 data = iwl_dbgfs_is_match("rate=", buf);
683 if (data) {
684 ret = kstrtou32(data, 10, &value);
685 if (ret == 0)
686 mvm->tof_data.responder_cfg.rate = value;
687 goto out;
688 }
689
690 data = iwl_dbgfs_is_match("bssid=", buf);
691 if (data) {
692 u8 *mac = mvm->tof_data.responder_cfg.bssid;
693
694 if (!mac_pton(data, mac)) {
695 ret = -EINVAL;
696 goto out;
697 }
698 }
699
700 data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf);
701 if (data) {
702 ret = kstrtou32(data, 10, &value);
703 if (ret == 0)
704 mvm->tof_data.responder_cfg.tsf_timer_offset_msecs =
705 cpu_to_le16(value);
706 goto out;
707 }
708
709 data = iwl_dbgfs_is_match("toa_offset=", buf);
710 if (data) {
711 ret = kstrtou32(data, 10, &value);
712 if (ret == 0)
713 mvm->tof_data.responder_cfg.toa_offset =
714 cpu_to_le16(value);
715 goto out;
716 }
717
718 data = iwl_dbgfs_is_match("ctrl_ch_position=", buf);
719 if (data) {
720 ret = kstrtou32(data, 10, &value);
721 if (ret == 0)
722 mvm->tof_data.responder_cfg.ctrl_ch_position = value;
723 goto out;
724 }
725
726 data = iwl_dbgfs_is_match("ftm_per_burst=", buf);
727 if (data) {
728 ret = kstrtou32(data, 10, &value);
729 if (ret == 0)
730 mvm->tof_data.responder_cfg.ftm_per_burst = value;
731 goto out;
732 }
733
734 data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf);
735 if (data) {
736 ret = kstrtou32(data, 10, &value);
737 if (ret == 0)
738 mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value;
739 goto out;
740 }
741
742 data = iwl_dbgfs_is_match("asap_mode=", buf);
743 if (data) {
744 ret = kstrtou32(data, 10, &value);
745 if (ret == 0)
746 mvm->tof_data.responder_cfg.asap_mode = value;
747 goto out;
748 }
749
750 data = iwl_dbgfs_is_match("send_responder_cfg=", buf);
751 if (data) {
752 ret = kstrtou32(data, 10, &value);
753 if (ret == 0 && value) {
754 ret = iwl_mvm_tof_responder_cmd(mvm, vif);
755 goto out;
756 }
757 }
758
759out:
760 mutex_unlock(&mvm->mutex);
761
762 return ret ?: count;
763}
764
765static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file,
766 char __user *user_buf,
767 size_t count, loff_t *ppos)
768{
769 struct ieee80211_vif *vif = file->private_data;
770 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
771 struct iwl_mvm *mvm = mvmvif->mvm;
772 char buf[256];
773 int pos = 0;
774 const size_t bufsz = sizeof(buf);
775 struct iwl_tof_responder_config_cmd *cmd;
776
777 cmd = &mvm->tof_data.responder_cfg;
778
779 mutex_lock(&mvm->mutex);
780
781 pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n",
782 le16_to_cpu(cmd->burst_period));
783 pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n",
784 cmd->burst_duration);
785 pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n",
786 cmd->bandwidth);
787 pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n",
788 cmd->channel_num);
789 pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n",
790 cmd->ctrl_ch_position);
791 pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n",
792 cmd->bssid);
793 pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n",
794 cmd->min_delta_ftm);
795 pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n",
796 cmd->num_of_burst_exp);
797 pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate);
798 pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n",
799 cmd->abort_responder);
800 pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n",
801 cmd->get_ch_est);
802 pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n",
803 cmd->recv_sta_req_params);
804 pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n",
805 cmd->ftm_per_burst);
806 pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n",
807 cmd->ftm_resp_ts_avail);
808 pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n",
809 cmd->asap_mode);
810 pos += scnprintf(buf + pos, bufsz - pos,
811 "tsf_timer_offset_msecs = %d\n",
812 le16_to_cpu(cmd->tsf_timer_offset_msecs));
813 pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n",
814 le16_to_cpu(cmd->toa_offset));
815
816 mutex_unlock(&mvm->mutex);
817
818 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
819}
820
821static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
822 char *buf, size_t count,
823 loff_t *ppos)
824{
825 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
826 struct iwl_mvm *mvm = mvmvif->mvm;
Johannes Berge6c21be2015-09-24 22:15:02 +0200827 u32 value;
828 int ret = 0;
Gregory Greenmance792912015-06-02 18:06:16 +0300829 char *data;
830
831 mutex_lock(&mvm->mutex);
832
833 data = iwl_dbgfs_is_match("request_id=", buf);
834 if (data) {
835 ret = kstrtou32(data, 10, &value);
836 if (ret == 0)
837 mvm->tof_data.range_req.request_id = value;
838 goto out;
839 }
840
841 data = iwl_dbgfs_is_match("initiator=", buf);
842 if (data) {
843 ret = kstrtou32(data, 10, &value);
844 if (ret == 0)
845 mvm->tof_data.range_req.initiator = value;
846 goto out;
847 }
848
849 data = iwl_dbgfs_is_match("one_sided_los_disable=", buf);
850 if (data) {
851 ret = kstrtou32(data, 10, &value);
852 if (ret == 0)
853 mvm->tof_data.range_req.one_sided_los_disable = value;
854 goto out;
855 }
856
857 data = iwl_dbgfs_is_match("req_timeout=", buf);
858 if (data) {
859 ret = kstrtou32(data, 10, &value);
860 if (ret == 0)
861 mvm->tof_data.range_req.req_timeout = value;
862 goto out;
863 }
864
865 data = iwl_dbgfs_is_match("report_policy=", buf);
866 if (data) {
867 ret = kstrtou32(data, 10, &value);
868 if (ret == 0)
869 mvm->tof_data.range_req.report_policy = value;
870 goto out;
871 }
872
873 data = iwl_dbgfs_is_match("macaddr_random=", buf);
874 if (data) {
875 ret = kstrtou32(data, 10, &value);
876 if (ret == 0)
877 mvm->tof_data.range_req.macaddr_random = value;
878 goto out;
879 }
880
881 data = iwl_dbgfs_is_match("num_of_ap=", buf);
882 if (data) {
883 ret = kstrtou32(data, 10, &value);
884 if (ret == 0)
885 mvm->tof_data.range_req.num_of_ap = value;
886 goto out;
887 }
888
889 data = iwl_dbgfs_is_match("macaddr_template=", buf);
890 if (data) {
891 u8 mac[ETH_ALEN];
892
893 if (!mac_pton(data, mac)) {
894 ret = -EINVAL;
895 goto out;
896 }
897 memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN);
Assaf Krauss5ac15be2015-09-16 11:47:14 +0300898 goto out;
Gregory Greenmance792912015-06-02 18:06:16 +0300899 }
900
901 data = iwl_dbgfs_is_match("macaddr_mask=", buf);
902 if (data) {
903 u8 mac[ETH_ALEN];
904
905 if (!mac_pton(data, mac)) {
906 ret = -EINVAL;
907 goto out;
908 }
909 memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN);
Assaf Krauss5ac15be2015-09-16 11:47:14 +0300910 goto out;
Gregory Greenmance792912015-06-02 18:06:16 +0300911 }
912
913 data = iwl_dbgfs_is_match("ap=", buf);
914 if (data) {
Assaf Krauss5ac15be2015-09-16 11:47:14 +0300915 struct iwl_tof_range_req_ap_entry ap = {};
Gregory Greenmance792912015-06-02 18:06:16 +0300916 int size = sizeof(struct iwl_tof_range_req_ap_entry);
917 u16 burst_period;
918 u8 *mac = ap.bssid;
Dan Carpenter5b9d47c2015-08-11 00:45:03 +0300919 unsigned int i;
Gregory Greenmance792912015-06-02 18:06:16 +0300920
Assaf Krauss3e0fa502015-09-16 11:44:55 +0300921 if (sscanf(data, "%u %hhd %hhd %hhd"
Gregory Greenmance792912015-06-02 18:06:16 +0300922 "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"
Assaf Krauss3e0fa502015-09-16 11:44:55 +0300923 "%hhd %hhd %hd"
924 "%hhd %hhd %d"
925 "%hhx %hhd %hhd %hhd",
Gregory Greenmance792912015-06-02 18:06:16 +0300926 &i, &ap.channel_num, &ap.bandwidth,
927 &ap.ctrl_ch_position,
928 mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
929 &ap.measure_type, &ap.num_of_bursts,
930 &burst_period,
931 &ap.samples_per_burst, &ap.retries_per_sample,
932 &ap.tsf_delta, &ap.location_req, &ap.asap_mode,
933 &ap.enable_dyn_ack, &ap.rssi) != 20) {
934 ret = -EINVAL;
935 goto out;
936 }
Dan Carpenter5b9d47c2015-08-11 00:45:03 +0300937 if (i >= IWL_MVM_TOF_MAX_APS) {
Gregory Greenmance792912015-06-02 18:06:16 +0300938 IWL_ERR(mvm, "Invalid AP index %d\n", i);
939 ret = -EINVAL;
940 goto out;
941 }
942
943 ap.burst_period = cpu_to_le16(burst_period);
944
945 memcpy(&mvm->tof_data.range_req.ap[i], &ap, size);
946 goto out;
947 }
948
949 data = iwl_dbgfs_is_match("send_range_request=", buf);
950 if (data) {
951 ret = kstrtou32(data, 10, &value);
Assaf Krauss5ac15be2015-09-16 11:47:14 +0300952 if (ret == 0 && value)
Gregory Greenmance792912015-06-02 18:06:16 +0300953 ret = iwl_mvm_tof_range_request_cmd(mvm, vif);
Assaf Krauss5ac15be2015-09-16 11:47:14 +0300954 goto out;
Gregory Greenmance792912015-06-02 18:06:16 +0300955 }
956
Assaf Krauss5ac15be2015-09-16 11:47:14 +0300957 ret = -EINVAL;
Gregory Greenmance792912015-06-02 18:06:16 +0300958out:
959 mutex_unlock(&mvm->mutex);
960 return ret ?: count;
961}
962
963static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file,
964 char __user *user_buf,
965 size_t count, loff_t *ppos)
966{
967 struct ieee80211_vif *vif = file->private_data;
968 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
969 struct iwl_mvm *mvm = mvmvif->mvm;
970 char buf[512];
971 int pos = 0;
972 const size_t bufsz = sizeof(buf);
973 struct iwl_tof_range_req_cmd *cmd;
974 int i;
975
976 cmd = &mvm->tof_data.range_req;
977
978 mutex_lock(&mvm->mutex);
979
980 pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n",
981 cmd->request_id);
982 pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n",
983 cmd->initiator);
984 pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n",
985 cmd->one_sided_los_disable);
986 pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n",
987 cmd->req_timeout);
988 pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n",
989 cmd->report_policy);
990 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n",
991 cmd->macaddr_random);
992 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n",
993 cmd->macaddr_template);
994 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n",
995 cmd->macaddr_mask);
996 pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n",
997 cmd->num_of_ap);
998 for (i = 0; i < cmd->num_of_ap; i++) {
999 struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i];
1000
1001 pos += scnprintf(buf + pos, bufsz - pos,
Assaf Krauss3e0fa502015-09-16 11:44:55 +03001002 "ap %.2d: channel_num=%hhd bw=%hhd"
1003 " control=%hhd bssid=%pM type=%hhd"
1004 " num_of_bursts=%hhd burst_period=%hd ftm=%hhd"
1005 " retries=%hhd tsf_delta=%d"
1006 " tsf_delta_direction=%hhd location_req=0x%hhx "
1007 " asap=%hhd enable=%hhd rssi=%hhd\n",
Gregory Greenmance792912015-06-02 18:06:16 +03001008 i, ap->channel_num, ap->bandwidth,
1009 ap->ctrl_ch_position, ap->bssid,
1010 ap->measure_type, ap->num_of_bursts,
1011 ap->burst_period, ap->samples_per_burst,
1012 ap->retries_per_sample, ap->tsf_delta,
Assaf Krauss3e0fa502015-09-16 11:44:55 +03001013 ap->tsf_delta_direction,
Gregory Greenmance792912015-06-02 18:06:16 +03001014 ap->location_req, ap->asap_mode,
1015 ap->enable_dyn_ack, ap->rssi);
1016 }
1017
1018 mutex_unlock(&mvm->mutex);
1019
1020 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1021}
1022
1023static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
1024 char *buf,
1025 size_t count, loff_t *ppos)
1026{
1027 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1028 struct iwl_mvm *mvm = mvmvif->mvm;
Johannes Berge6c21be2015-09-24 22:15:02 +02001029 u32 value;
1030 int ret = 0;
Gregory Greenmance792912015-06-02 18:06:16 +03001031 char *data;
1032
1033 mutex_lock(&mvm->mutex);
1034
1035 data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf);
1036 if (data) {
1037 ret = kstrtou32(data, 10, &value);
1038 if (ret == 0)
1039 mvm->tof_data.range_req_ext.tsf_timer_offset_msec =
1040 cpu_to_le16(value);
1041 goto out;
1042 }
1043
1044 data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
1045 if (data) {
1046 ret = kstrtou32(data, 10, &value);
1047 if (ret == 0)
1048 mvm->tof_data.range_req_ext.min_delta_ftm = value;
1049 goto out;
1050 }
1051
1052 data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf);
1053 if (data) {
1054 ret = kstrtou32(data, 10, &value);
1055 if (ret == 0)
1056 mvm->tof_data.range_req_ext.ftm_format_and_bw20M =
1057 value;
1058 goto out;
1059 }
1060
1061 data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf);
1062 if (data) {
1063 ret = kstrtou32(data, 10, &value);
1064 if (ret == 0)
1065 mvm->tof_data.range_req_ext.ftm_format_and_bw40M =
1066 value;
1067 goto out;
1068 }
1069
1070 data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf);
1071 if (data) {
1072 ret = kstrtou32(data, 10, &value);
1073 if (ret == 0)
1074 mvm->tof_data.range_req_ext.ftm_format_and_bw80M =
1075 value;
1076 goto out;
1077 }
1078
1079 data = iwl_dbgfs_is_match("send_range_req_ext=", buf);
1080 if (data) {
1081 ret = kstrtou32(data, 10, &value);
Assaf Krauss5ac15be2015-09-16 11:47:14 +03001082 if (ret == 0 && value)
Gregory Greenmance792912015-06-02 18:06:16 +03001083 ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif);
Assaf Krauss5ac15be2015-09-16 11:47:14 +03001084 goto out;
Gregory Greenmance792912015-06-02 18:06:16 +03001085 }
1086
Assaf Krauss5ac15be2015-09-16 11:47:14 +03001087 ret = -EINVAL;
Gregory Greenmance792912015-06-02 18:06:16 +03001088out:
1089 mutex_unlock(&mvm->mutex);
1090 return ret ?: count;
1091}
1092
1093static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file,
1094 char __user *user_buf,
1095 size_t count, loff_t *ppos)
1096{
1097 struct ieee80211_vif *vif = file->private_data;
1098 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1099 struct iwl_mvm *mvm = mvmvif->mvm;
1100 char buf[256];
1101 int pos = 0;
1102 const size_t bufsz = sizeof(buf);
1103 struct iwl_tof_range_req_ext_cmd *cmd;
1104
1105 cmd = &mvm->tof_data.range_req_ext;
1106
1107 mutex_lock(&mvm->mutex);
1108
1109 pos += scnprintf(buf + pos, bufsz - pos,
Assaf Krauss3e0fa502015-09-16 11:44:55 +03001110 "tsf_timer_offset_msec = %hd\n",
Gregory Greenmance792912015-06-02 18:06:16 +03001111 cmd->tsf_timer_offset_msec);
Assaf Krauss3e0fa502015-09-16 11:44:55 +03001112 pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n",
Gregory Greenmance792912015-06-02 18:06:16 +03001113 cmd->min_delta_ftm);
1114 pos += scnprintf(buf + pos, bufsz - pos,
Assaf Krauss3e0fa502015-09-16 11:44:55 +03001115 "ftm_format_and_bw20M = %hhd\n",
Gregory Greenmance792912015-06-02 18:06:16 +03001116 cmd->ftm_format_and_bw20M);
1117 pos += scnprintf(buf + pos, bufsz - pos,
Assaf Krauss3e0fa502015-09-16 11:44:55 +03001118 "ftm_format_and_bw40M = %hhd\n",
Gregory Greenmance792912015-06-02 18:06:16 +03001119 cmd->ftm_format_and_bw40M);
1120 pos += scnprintf(buf + pos, bufsz - pos,
Assaf Krauss3e0fa502015-09-16 11:44:55 +03001121 "ftm_format_and_bw80M = %hhd\n",
Gregory Greenmance792912015-06-02 18:06:16 +03001122 cmd->ftm_format_and_bw80M);
1123
1124 mutex_unlock(&mvm->mutex);
1125 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1126}
1127
1128static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif,
1129 char *buf,
1130 size_t count, loff_t *ppos)
1131{
1132 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1133 struct iwl_mvm *mvm = mvmvif->mvm;
Johannes Berge6c21be2015-09-24 22:15:02 +02001134 u32 value;
1135 int abort_id, ret = 0;
Gregory Greenmance792912015-06-02 18:06:16 +03001136 char *data;
1137
1138 mutex_lock(&mvm->mutex);
1139
1140 data = iwl_dbgfs_is_match("abort_id=", buf);
1141 if (data) {
1142 ret = kstrtou32(data, 10, &value);
1143 if (ret == 0)
1144 mvm->tof_data.last_abort_id = value;
1145 goto out;
1146 }
1147
1148 data = iwl_dbgfs_is_match("send_range_abort=", buf);
1149 if (data) {
1150 ret = kstrtou32(data, 10, &value);
1151 if (ret == 0 && value) {
1152 abort_id = mvm->tof_data.last_abort_id;
1153 ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id);
1154 goto out;
1155 }
1156 }
1157
1158out:
1159 mutex_unlock(&mvm->mutex);
1160 return ret ?: count;
1161}
1162
1163static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file,
1164 char __user *user_buf,
1165 size_t count, loff_t *ppos)
1166{
1167 struct ieee80211_vif *vif = file->private_data;
1168 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1169 struct iwl_mvm *mvm = mvmvif->mvm;
1170 char buf[32];
1171 int pos = 0;
1172 const size_t bufsz = sizeof(buf);
1173 int last_abort_id;
1174
1175 mutex_lock(&mvm->mutex);
1176 last_abort_id = mvm->tof_data.last_abort_id;
1177 mutex_unlock(&mvm->mutex);
1178
1179 pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n",
1180 last_abort_id);
1181 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1182}
1183
1184static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file,
1185 char __user *user_buf,
1186 size_t count, loff_t *ppos)
1187{
1188 struct ieee80211_vif *vif = file->private_data;
1189 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1190 struct iwl_mvm *mvm = mvmvif->mvm;
1191 char *buf;
1192 int pos = 0;
1193 const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256;
1194 struct iwl_tof_range_rsp_ntfy *cmd;
1195 int i, ret;
1196
1197 buf = kzalloc(bufsz, GFP_KERNEL);
1198 if (!buf)
1199 return -ENOMEM;
1200
1201 mutex_lock(&mvm->mutex);
1202 cmd = &mvm->tof_data.range_resp;
1203
1204 pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n",
1205 cmd->request_id);
1206 pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n",
1207 cmd->request_status);
1208 pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n",
1209 cmd->last_in_batch);
1210 pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n",
1211 cmd->num_of_aps);
1212 for (i = 0; i < cmd->num_of_aps; i++) {
1213 struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i];
1214
1215 pos += scnprintf(buf + pos, bufsz - pos,
Assaf Krauss3e0fa502015-09-16 11:44:55 +03001216 "ap %.2d: bssid=%pM status=%hhd bw=%hhd"
1217 " rtt=%d rtt_var=%d rtt_spread=%d"
1218 " rssi=%hhd rssi_spread=%hhd"
1219 " range=%d range_var=%d"
1220 " time_stamp=%d\n",
Gregory Greenmance792912015-06-02 18:06:16 +03001221 i, ap->bssid, ap->measure_status,
1222 ap->measure_bw,
1223 ap->rtt, ap->rtt_variance, ap->rtt_spread,
1224 ap->rssi, ap->rssi_spread, ap->range,
1225 ap->range_variance, ap->timestamp);
1226 }
1227 mutex_unlock(&mvm->mutex);
1228
1229 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1230 kfree(buf);
1231 return ret;
1232}
1233
Johannes Berga21d7bc2013-11-12 17:30:52 +01001234static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
1235 size_t count, loff_t *ppos)
1236{
1237 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1238 struct iwl_mvm *mvm = mvmvif->mvm;
1239 u8 value;
1240 int ret;
1241
1242 ret = kstrtou8(buf, 0, &value);
1243 if (ret)
1244 return ret;
1245 if (value > 1)
1246 return -EINVAL;
1247
1248 mutex_lock(&mvm->mutex);
1249 iwl_mvm_update_low_latency(mvm, vif, value);
1250 mutex_unlock(&mvm->mutex);
1251
1252 return count;
1253}
1254
1255static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
1256 char __user *user_buf,
1257 size_t count, loff_t *ppos)
1258{
1259 struct ieee80211_vif *vif = file->private_data;
1260 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
Johannes Bergcfe417b2015-08-26 12:22:12 +02001261 char buf[2];
Johannes Berga21d7bc2013-11-12 17:30:52 +01001262
1263 buf[0] = mvmvif->low_latency ? '1' : '0';
1264 buf[1] = '\n';
Johannes Berga21d7bc2013-11-12 17:30:52 +01001265 return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
1266}
1267
Johannes Berge39c1b52015-01-09 14:15:32 +01001268static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
1269 char __user *user_buf,
1270 size_t count, loff_t *ppos)
1271{
1272 struct ieee80211_vif *vif = file->private_data;
1273 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1274 char buf[20];
1275 int len;
1276
1277 len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
1278 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1279}
1280
1281static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
1282 char *buf, size_t count,
1283 loff_t *ppos)
1284{
1285 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1286 struct iwl_mvm *mvm = mvmvif->mvm;
1287 bool ret;
1288
1289 mutex_lock(&mvm->mutex);
1290 ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
1291 mutex_unlock(&mvm->mutex);
1292
1293 return ret ? count : -EINVAL;
1294}
1295
Emmanuel Grumbachddf89ab2015-02-08 10:56:43 +02001296static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
1297 size_t count, loff_t *ppos)
1298{
1299 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1300 struct iwl_mvm *mvm = mvmvif->mvm;
1301 struct ieee80211_chanctx_conf *chanctx_conf;
1302 struct iwl_mvm_phy_ctxt *phy_ctxt;
1303 u16 value;
1304 int ret;
1305
1306 ret = kstrtou16(buf, 0, &value);
1307 if (ret)
1308 return ret;
1309
1310 mutex_lock(&mvm->mutex);
1311 rcu_read_lock();
1312
1313 chanctx_conf = rcu_dereference(vif->chanctx_conf);
1314 /* make sure the channel context is assigned */
1315 if (!chanctx_conf) {
1316 rcu_read_unlock();
1317 mutex_unlock(&mvm->mutex);
1318 return -EINVAL;
1319 }
1320
1321 phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
1322 rcu_read_unlock();
1323
1324 mvm->dbgfs_rx_phyinfo = value;
1325
1326 ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
1327 chanctx_conf->rx_chains_static,
1328 chanctx_conf->rx_chains_dynamic);
1329 mutex_unlock(&mvm->mutex);
1330
1331 return ret ?: count;
1332}
1333
1334static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
1335 char __user *user_buf,
1336 size_t count, loff_t *ppos)
1337{
1338 struct ieee80211_vif *vif = file->private_data;
1339 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1340 char buf[8];
1341
1342 snprintf(buf, sizeof(buf), "0x%04x\n", mvmvif->mvm->dbgfs_rx_phyinfo);
1343
1344 return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
1345}
1346
Alexander Bondare45a9412013-12-04 10:13:24 +02001347#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1348 _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1349#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1350 _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
Johannes Berg820a1a52013-11-12 16:58:41 +01001351#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
1352 if (!debugfs_create_file(#name, mode, parent, vif, \
1353 &iwl_dbgfs_##name##_ops)) \
1354 goto err; \
1355 } while (0)
1356
1357MVM_DEBUGFS_READ_FILE_OPS(mac_params);
Matti Gottlieb25870cb2015-05-04 09:34:37 +03001358MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
Alexander Bondare45a9412013-12-04 10:13:24 +02001359MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
1360MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
Johannes Berga21d7bc2013-11-12 17:30:52 +01001361MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
Johannes Berge39c1b52015-01-09 14:15:32 +01001362MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
Emmanuel Grumbachddf89ab2015-02-08 10:56:43 +02001363MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
Gregory Greenmance792912015-06-02 18:06:16 +03001364MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32);
1365MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512);
1366MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
1367MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
1368MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
1369MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
Johannes Berg820a1a52013-11-12 16:58:41 +01001370
1371void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1372{
1373 struct dentry *dbgfs_dir = vif->debugfs_dir;
1374 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1375 char buf[100];
1376
1377 /*
1378 * Check if debugfs directory already exist before creating it.
1379 * This may happen when, for example, resetting hw or suspend-resume
1380 */
1381 if (!dbgfs_dir || mvmvif->dbgfs_dir)
1382 return;
1383
1384 mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
Johannes Berg820a1a52013-11-12 16:58:41 +01001385
1386 if (!mvmvif->dbgfs_dir) {
1387 IWL_ERR(mvm, "Failed to create debugfs directory under %s\n",
1388 dbgfs_dir->d_name.name);
1389 return;
1390 }
1391
Emmanuel Grumbachad2549d2014-03-30 09:50:54 +03001392 if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
Alexander Bondare45a9412013-12-04 10:13:24 +02001393 ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
1394 (vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
Alexander Bondar7303dd7f2014-02-03 21:57:28 +02001395 mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)))
Alexander Bondare45a9412013-12-04 10:13:24 +02001396 MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
1397 S_IRUSR);
1398
Matti Gottlieb25870cb2015-05-04 09:34:37 +03001399 MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR);
Emmanuel Grumbach32a65c32014-01-12 11:19:13 +02001400 MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR);
Johannes Berga21d7bc2013-11-12 17:30:52 +01001401 MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir,
1402 S_IRUSR | S_IWUSR);
Johannes Berge39c1b52015-01-09 14:15:32 +01001403 MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir,
1404 S_IRUSR | S_IWUSR);
Emmanuel Grumbachddf89ab2015-02-08 10:56:43 +02001405 MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir,
1406 S_IRUSR | S_IWUSR);
Johannes Berg820a1a52013-11-12 16:58:41 +01001407
Alexander Bondare45a9412013-12-04 10:13:24 +02001408 if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
1409 mvmvif == mvm->bf_allowed_vif)
1410 MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
1411 S_IRUSR | S_IWUSR);
1412
Gregory Greenmance792912015-06-02 18:06:16 +03001413 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) &&
1414 !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) {
1415 if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP)
1416 MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params,
1417 mvmvif->dbgfs_dir,
1418 S_IRUSR | S_IWUSR);
1419
1420 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir,
1421 S_IRUSR | S_IWUSR);
1422 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir,
1423 S_IRUSR | S_IWUSR);
1424 MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir,
1425 S_IRUSR | S_IWUSR);
1426 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir,
1427 S_IRUSR | S_IWUSR);
1428 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir,
1429 S_IRUSR);
1430 }
1431
Johannes Berg820a1a52013-11-12 16:58:41 +01001432 /*
1433 * Create symlink for convenience pointing to interface specific
1434 * debugfs entries for the driver. For example, under
1435 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
1436 * find
1437 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
1438 */
1439 snprintf(buf, 100, "../../../%s/%s/%s/%s",
1440 dbgfs_dir->d_parent->d_parent->d_name.name,
1441 dbgfs_dir->d_parent->d_name.name,
1442 dbgfs_dir->d_name.name,
1443 mvmvif->dbgfs_dir->d_name.name);
1444
1445 mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
1446 mvm->debugfs_dir, buf);
1447 if (!mvmvif->dbgfs_slink)
1448 IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n",
1449 dbgfs_dir->d_name.name);
1450 return;
1451err:
1452 IWL_ERR(mvm, "Can't create debugfs entity\n");
1453}
1454
1455void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1456{
1457 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1458
1459 debugfs_remove(mvmvif->dbgfs_slink);
1460 mvmvif->dbgfs_slink = NULL;
1461
1462 debugfs_remove_recursive(mvmvif->dbgfs_dir);
1463 mvmvif->dbgfs_dir = NULL;
1464}