1 /******************************************************************************
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.
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
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.
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.
21 * The full GNU General Public License is included in this distribution
22 * in the file called COPYING.
24 * Contact Information:
26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
31 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
32 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
33 * All rights reserved.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
39 * * Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * * Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in
43 * the documentation and/or other materials provided with the
45 * * Neither the name Intel Corporation nor the names of its
46 * contributors may be used to endorse or promote products derived
47 * from this software without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 *****************************************************************************/
63 #include "fw/api/tof.h"
66 static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
67 struct ieee80211_vif *vif,
68 enum iwl_dbgfs_pm_mask param, int val)
70 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
71 struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
73 dbgfs_pm->mask |= param;
76 case MVM_DEBUGFS_PM_KEEP_ALIVE: {
77 int dtimper = vif->bss_conf.dtim_period ?: 1;
78 int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
80 IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
81 if (val * MSEC_PER_SEC < 3 * dtimper_msec)
83 "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
84 val * MSEC_PER_SEC, 3 * dtimper_msec);
85 dbgfs_pm->keep_alive_seconds = val;
88 case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
89 IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
90 val ? "enabled" : "disabled");
91 dbgfs_pm->skip_over_dtim = val;
93 case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
94 IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
95 dbgfs_pm->skip_dtim_periods = val;
97 case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
98 IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
99 dbgfs_pm->rx_data_timeout = val;
101 case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
102 IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
103 dbgfs_pm->tx_data_timeout = val;
105 case MVM_DEBUGFS_PM_LPRX_ENA:
106 IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
107 dbgfs_pm->lprx_ena = val;
109 case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
110 IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
111 dbgfs_pm->lprx_rssi_threshold = val;
113 case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
114 IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
115 dbgfs_pm->snooze_ena = val;
117 case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
118 IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
119 dbgfs_pm->uapsd_misbehaving = val;
121 case MVM_DEBUGFS_PM_USE_PS_POLL:
122 IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val);
123 dbgfs_pm->use_ps_poll = val;
128 static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
129 size_t count, loff_t *ppos)
131 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
132 struct iwl_mvm *mvm = mvmvif->mvm;
133 enum iwl_dbgfs_pm_mask param;
136 if (!strncmp("keep_alive=", buf, 11)) {
137 if (sscanf(buf + 11, "%d", &val) != 1)
139 param = MVM_DEBUGFS_PM_KEEP_ALIVE;
140 } else if (!strncmp("skip_over_dtim=", buf, 15)) {
141 if (sscanf(buf + 15, "%d", &val) != 1)
143 param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
144 } else if (!strncmp("skip_dtim_periods=", buf, 18)) {
145 if (sscanf(buf + 18, "%d", &val) != 1)
147 param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
148 } else if (!strncmp("rx_data_timeout=", buf, 16)) {
149 if (sscanf(buf + 16, "%d", &val) != 1)
151 param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
152 } else if (!strncmp("tx_data_timeout=", buf, 16)) {
153 if (sscanf(buf + 16, "%d", &val) != 1)
155 param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
156 } else if (!strncmp("lprx=", buf, 5)) {
157 if (sscanf(buf + 5, "%d", &val) != 1)
159 param = MVM_DEBUGFS_PM_LPRX_ENA;
160 } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
161 if (sscanf(buf + 20, "%d", &val) != 1)
163 if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
164 POWER_LPRX_RSSI_THRESHOLD_MIN)
166 param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
167 } else if (!strncmp("snooze_enable=", buf, 14)) {
168 if (sscanf(buf + 14, "%d", &val) != 1)
170 param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
171 } else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
172 if (sscanf(buf + 18, "%d", &val) != 1)
174 param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
175 } else if (!strncmp("use_ps_poll=", buf, 12)) {
176 if (sscanf(buf + 12, "%d", &val) != 1)
178 param = MVM_DEBUGFS_PM_USE_PS_POLL;
183 mutex_lock(&mvm->mutex);
184 iwl_dbgfs_update_pm(mvm, vif, param, val);
185 ret = iwl_mvm_power_update_mac(mvm);
186 mutex_unlock(&mvm->mutex);
191 static ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file,
192 char __user *user_buf,
193 size_t count, loff_t *ppos)
195 struct ieee80211_vif *vif = file->private_data;
197 int bufsz = sizeof(buf);
200 pos = scnprintf(buf, bufsz, "bss limit = %d\n",
201 vif->bss_conf.txpower);
203 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
206 static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
207 char __user *user_buf,
208 size_t count, loff_t *ppos)
210 struct ieee80211_vif *vif = file->private_data;
211 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
212 struct iwl_mvm *mvm = mvmvif->mvm;
214 int bufsz = sizeof(buf);
217 pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz);
219 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
222 static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
223 char __user *user_buf,
224 size_t count, loff_t *ppos)
226 struct ieee80211_vif *vif = file->private_data;
227 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
228 struct iwl_mvm *mvm = mvmvif->mvm;
230 struct ieee80211_chanctx_conf *chanctx_conf;
232 int bufsz = sizeof(buf);
236 mutex_lock(&mvm->mutex);
238 ap_sta_id = mvmvif->ap_sta_id;
240 switch (ieee80211_vif_type_p2p(vif)) {
241 case NL80211_IFTYPE_ADHOC:
242 pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n");
244 case NL80211_IFTYPE_STATION:
245 pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n");
247 case NL80211_IFTYPE_AP:
248 pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n");
250 case NL80211_IFTYPE_P2P_CLIENT:
251 pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n");
253 case NL80211_IFTYPE_P2P_GO:
254 pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n");
256 case NL80211_IFTYPE_P2P_DEVICE:
257 pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n");
263 pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
264 mvmvif->id, mvmvif->color);
265 pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
266 vif->bss_conf.bssid);
267 pos += scnprintf(buf+pos, bufsz-pos, "Load: %d\n",
268 mvm->tcm.result.load[mvmvif->id]);
269 pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
270 for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++)
271 pos += scnprintf(buf+pos, bufsz-pos,
272 "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
273 i, mvmvif->queue_params[i].txop,
274 mvmvif->queue_params[i].cw_min,
275 mvmvif->queue_params[i].cw_max,
276 mvmvif->queue_params[i].aifs,
277 mvmvif->queue_params[i].uapsd);
279 if (vif->type == NL80211_IFTYPE_STATION &&
280 ap_sta_id != IWL_MVM_INVALID_STA) {
281 struct iwl_mvm_sta *mvm_sta;
283 mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id);
285 pos += scnprintf(buf+pos, bufsz-pos,
286 "ap_sta_id %d - reduced Tx power %d\n",
288 mvm_sta->bt_reduced_txpower);
293 chanctx_conf = rcu_dereference(vif->chanctx_conf);
295 pos += scnprintf(buf+pos, bufsz-pos,
296 "idle rx chains %d, active rx chains: %d\n",
297 chanctx_conf->rx_chains_static,
298 chanctx_conf->rx_chains_dynamic);
301 mutex_unlock(&mvm->mutex);
303 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
306 static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
307 enum iwl_dbgfs_bf_mask param, int value)
309 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
310 struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
312 dbgfs_bf->mask |= param;
315 case MVM_DEBUGFS_BF_ENERGY_DELTA:
316 dbgfs_bf->bf_energy_delta = value;
318 case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
319 dbgfs_bf->bf_roaming_energy_delta = value;
321 case MVM_DEBUGFS_BF_ROAMING_STATE:
322 dbgfs_bf->bf_roaming_state = value;
324 case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
325 dbgfs_bf->bf_temp_threshold = value;
327 case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
328 dbgfs_bf->bf_temp_fast_filter = value;
330 case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
331 dbgfs_bf->bf_temp_slow_filter = value;
333 case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
334 dbgfs_bf->bf_enable_beacon_filter = value;
336 case MVM_DEBUGFS_BF_DEBUG_FLAG:
337 dbgfs_bf->bf_debug_flag = value;
339 case MVM_DEBUGFS_BF_ESCAPE_TIMER:
340 dbgfs_bf->bf_escape_timer = value;
342 case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
343 dbgfs_bf->ba_enable_beacon_abort = value;
345 case MVM_DEBUGFS_BA_ESCAPE_TIMER:
346 dbgfs_bf->ba_escape_timer = value;
351 static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
352 size_t count, loff_t *ppos)
354 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
355 struct iwl_mvm *mvm = mvmvif->mvm;
356 enum iwl_dbgfs_bf_mask param;
359 if (!strncmp("bf_energy_delta=", buf, 16)) {
360 if (sscanf(buf+16, "%d", &value) != 1)
362 if (value < IWL_BF_ENERGY_DELTA_MIN ||
363 value > IWL_BF_ENERGY_DELTA_MAX)
365 param = MVM_DEBUGFS_BF_ENERGY_DELTA;
366 } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
367 if (sscanf(buf+24, "%d", &value) != 1)
369 if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
370 value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
372 param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
373 } else if (!strncmp("bf_roaming_state=", buf, 17)) {
374 if (sscanf(buf+17, "%d", &value) != 1)
376 if (value < IWL_BF_ROAMING_STATE_MIN ||
377 value > IWL_BF_ROAMING_STATE_MAX)
379 param = MVM_DEBUGFS_BF_ROAMING_STATE;
380 } else if (!strncmp("bf_temp_threshold=", buf, 18)) {
381 if (sscanf(buf+18, "%d", &value) != 1)
383 if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
384 value > IWL_BF_TEMP_THRESHOLD_MAX)
386 param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
387 } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
388 if (sscanf(buf+20, "%d", &value) != 1)
390 if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
391 value > IWL_BF_TEMP_FAST_FILTER_MAX)
393 param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
394 } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
395 if (sscanf(buf+20, "%d", &value) != 1)
397 if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
398 value > IWL_BF_TEMP_SLOW_FILTER_MAX)
400 param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
401 } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
402 if (sscanf(buf+24, "%d", &value) != 1)
404 if (value < 0 || value > 1)
406 param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
407 } else if (!strncmp("bf_debug_flag=", buf, 14)) {
408 if (sscanf(buf+14, "%d", &value) != 1)
410 if (value < 0 || value > 1)
412 param = MVM_DEBUGFS_BF_DEBUG_FLAG;
413 } else if (!strncmp("bf_escape_timer=", buf, 16)) {
414 if (sscanf(buf+16, "%d", &value) != 1)
416 if (value < IWL_BF_ESCAPE_TIMER_MIN ||
417 value > IWL_BF_ESCAPE_TIMER_MAX)
419 param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
420 } else if (!strncmp("ba_escape_timer=", buf, 16)) {
421 if (sscanf(buf+16, "%d", &value) != 1)
423 if (value < IWL_BA_ESCAPE_TIMER_MIN ||
424 value > IWL_BA_ESCAPE_TIMER_MAX)
426 param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
427 } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
428 if (sscanf(buf+23, "%d", &value) != 1)
430 if (value < 0 || value > 1)
432 param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
437 mutex_lock(&mvm->mutex);
438 iwl_dbgfs_update_bf(vif, param, value);
439 if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
440 ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
442 ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0);
443 mutex_unlock(&mvm->mutex);
448 static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
449 char __user *user_buf,
450 size_t count, loff_t *ppos)
452 struct ieee80211_vif *vif = file->private_data;
453 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
456 const size_t bufsz = sizeof(buf);
457 struct iwl_beacon_filter_cmd cmd = {
458 IWL_BF_CMD_CONFIG_DEFAULTS,
459 .bf_enable_beacon_filter =
460 cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
461 .ba_enable_beacon_abort =
462 cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
465 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
466 if (mvmvif->bf_data.bf_enabled)
467 cmd.bf_enable_beacon_filter = cpu_to_le32(1);
469 cmd.bf_enable_beacon_filter = 0;
471 pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
472 le32_to_cpu(cmd.bf_energy_delta));
473 pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
474 le32_to_cpu(cmd.bf_roaming_energy_delta));
475 pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
476 le32_to_cpu(cmd.bf_roaming_state));
477 pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
478 le32_to_cpu(cmd.bf_temp_threshold));
479 pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
480 le32_to_cpu(cmd.bf_temp_fast_filter));
481 pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
482 le32_to_cpu(cmd.bf_temp_slow_filter));
483 pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
484 le32_to_cpu(cmd.bf_enable_beacon_filter));
485 pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
486 le32_to_cpu(cmd.bf_debug_flag));
487 pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
488 le32_to_cpu(cmd.bf_escape_timer));
489 pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
490 le32_to_cpu(cmd.ba_escape_timer));
491 pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
492 le32_to_cpu(cmd.ba_enable_beacon_abort));
494 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
497 static inline char *iwl_dbgfs_is_match(char *name, char *buf)
499 int len = strlen(name);
501 return !strncmp(name, buf, len) ? buf + len : NULL;
504 static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,
505 char __user *user_buf,
506 size_t count, loff_t *ppos)
508 struct ieee80211_vif *vif = file->private_data;
509 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
510 struct iwl_mvm *mvm = mvmvif->mvm;
515 const size_t bufsz = sizeof(buf);
518 iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os);
519 do_div(curr_os, NSEC_PER_USEC);
520 diff = curr_os - curr_gp2;
521 pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff);
523 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
526 static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
528 size_t count, loff_t *ppos)
530 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
531 struct iwl_mvm *mvm = mvmvif->mvm;
536 mutex_lock(&mvm->mutex);
538 data = iwl_dbgfs_is_match("tof_disabled=", buf);
540 ret = kstrtou32(data, 10, &value);
542 mvm->tof_data.tof_cfg.tof_disabled = value;
546 data = iwl_dbgfs_is_match("one_sided_disabled=", buf);
548 ret = kstrtou32(data, 10, &value);
550 mvm->tof_data.tof_cfg.one_sided_disabled = value;
554 data = iwl_dbgfs_is_match("is_debug_mode=", buf);
556 ret = kstrtou32(data, 10, &value);
558 mvm->tof_data.tof_cfg.is_debug_mode = value;
562 data = iwl_dbgfs_is_match("is_buf=", buf);
564 ret = kstrtou32(data, 10, &value);
566 mvm->tof_data.tof_cfg.is_buf_required = value;
570 data = iwl_dbgfs_is_match("send_tof_cfg=", buf);
572 ret = kstrtou32(data, 10, &value);
573 if (ret == 0 && value) {
574 ret = iwl_mvm_tof_config_cmd(mvm);
580 mutex_unlock(&mvm->mutex);
585 static ssize_t iwl_dbgfs_tof_enable_read(struct file *file,
586 char __user *user_buf,
587 size_t count, loff_t *ppos)
589 struct ieee80211_vif *vif = file->private_data;
590 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
591 struct iwl_mvm *mvm = mvmvif->mvm;
594 const size_t bufsz = sizeof(buf);
595 struct iwl_tof_config_cmd *cmd;
597 cmd = &mvm->tof_data.tof_cfg;
599 mutex_lock(&mvm->mutex);
601 pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n",
603 pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n",
604 cmd->one_sided_disabled);
605 pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n",
607 pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n",
608 cmd->is_buf_required);
610 mutex_unlock(&mvm->mutex);
612 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
615 static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
617 size_t count, loff_t *ppos)
619 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
620 struct iwl_mvm *mvm = mvmvif->mvm;
625 mutex_lock(&mvm->mutex);
627 data = iwl_dbgfs_is_match("burst_period=", buf);
629 ret = kstrtou32(data, 10, &value);
631 mvm->tof_data.responder_cfg.burst_period =
636 data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
638 ret = kstrtou32(data, 10, &value);
640 mvm->tof_data.responder_cfg.min_delta_ftm = value;
644 data = iwl_dbgfs_is_match("burst_duration=", buf);
646 ret = kstrtou32(data, 10, &value);
648 mvm->tof_data.responder_cfg.burst_duration = value;
652 data = iwl_dbgfs_is_match("num_of_burst_exp=", buf);
654 ret = kstrtou32(data, 10, &value);
656 mvm->tof_data.responder_cfg.num_of_burst_exp = value;
660 data = iwl_dbgfs_is_match("abort_responder=", buf);
662 ret = kstrtou32(data, 10, &value);
664 mvm->tof_data.responder_cfg.abort_responder = value;
668 data = iwl_dbgfs_is_match("get_ch_est=", buf);
670 ret = kstrtou32(data, 10, &value);
672 mvm->tof_data.responder_cfg.get_ch_est = value;
676 data = iwl_dbgfs_is_match("recv_sta_req_params=", buf);
678 ret = kstrtou32(data, 10, &value);
680 mvm->tof_data.responder_cfg.recv_sta_req_params = value;
684 data = iwl_dbgfs_is_match("channel_num=", buf);
686 ret = kstrtou32(data, 10, &value);
688 mvm->tof_data.responder_cfg.channel_num = value;
692 data = iwl_dbgfs_is_match("bandwidth=", buf);
694 ret = kstrtou32(data, 10, &value);
696 mvm->tof_data.responder_cfg.bandwidth = value;
700 data = iwl_dbgfs_is_match("rate=", buf);
702 ret = kstrtou32(data, 10, &value);
704 mvm->tof_data.responder_cfg.rate = value;
708 data = iwl_dbgfs_is_match("bssid=", buf);
710 u8 *mac = mvm->tof_data.responder_cfg.bssid;
712 if (!mac_pton(data, mac)) {
718 data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf);
720 ret = kstrtou32(data, 10, &value);
722 mvm->tof_data.responder_cfg.tsf_timer_offset_msecs =
727 data = iwl_dbgfs_is_match("toa_offset=", buf);
729 ret = kstrtou32(data, 10, &value);
731 mvm->tof_data.responder_cfg.toa_offset =
736 data = iwl_dbgfs_is_match("center_freq=", buf);
738 struct iwl_tof_responder_config_cmd *cmd =
739 &mvm->tof_data.responder_cfg;
741 ret = kstrtou32(data, 10, &value);
742 if (ret == 0 && value) {
743 enum nl80211_band band = (cmd->channel_num <= 14) ?
746 struct ieee80211_channel chn = {
748 .center_freq = ieee80211_channel_to_frequency(
749 cmd->channel_num, band),
751 struct cfg80211_chan_def chandef = {
754 ieee80211_channel_to_frequency(value,
758 cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef);
763 data = iwl_dbgfs_is_match("ftm_per_burst=", buf);
765 ret = kstrtou32(data, 10, &value);
767 mvm->tof_data.responder_cfg.ftm_per_burst = value;
771 data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf);
773 ret = kstrtou32(data, 10, &value);
775 mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value;
779 data = iwl_dbgfs_is_match("asap_mode=", buf);
781 ret = kstrtou32(data, 10, &value);
783 mvm->tof_data.responder_cfg.asap_mode = value;
787 data = iwl_dbgfs_is_match("send_responder_cfg=", buf);
789 ret = kstrtou32(data, 10, &value);
790 if (ret == 0 && value) {
791 ret = iwl_mvm_tof_responder_cmd(mvm, vif);
797 mutex_unlock(&mvm->mutex);
802 static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file,
803 char __user *user_buf,
804 size_t count, loff_t *ppos)
806 struct ieee80211_vif *vif = file->private_data;
807 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
808 struct iwl_mvm *mvm = mvmvif->mvm;
811 const size_t bufsz = sizeof(buf);
812 struct iwl_tof_responder_config_cmd *cmd;
814 cmd = &mvm->tof_data.responder_cfg;
816 mutex_lock(&mvm->mutex);
818 pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n",
819 le16_to_cpu(cmd->burst_period));
820 pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n",
821 cmd->burst_duration);
822 pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n",
824 pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n",
826 pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n",
827 cmd->ctrl_ch_position);
828 pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n",
830 pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n",
832 pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n",
833 cmd->num_of_burst_exp);
834 pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate);
835 pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n",
836 cmd->abort_responder);
837 pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n",
839 pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n",
840 cmd->recv_sta_req_params);
841 pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n",
843 pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n",
844 cmd->ftm_resp_ts_avail);
845 pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n",
847 pos += scnprintf(buf + pos, bufsz - pos,
848 "tsf_timer_offset_msecs = %d\n",
849 le16_to_cpu(cmd->tsf_timer_offset_msecs));
850 pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n",
851 le16_to_cpu(cmd->toa_offset));
853 mutex_unlock(&mvm->mutex);
855 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
858 static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
859 char *buf, size_t count,
862 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
863 struct iwl_mvm *mvm = mvmvif->mvm;
868 mutex_lock(&mvm->mutex);
870 data = iwl_dbgfs_is_match("request_id=", buf);
872 ret = kstrtou32(data, 10, &value);
874 mvm->tof_data.range_req.request_id = value;
878 data = iwl_dbgfs_is_match("initiator=", buf);
880 ret = kstrtou32(data, 10, &value);
882 mvm->tof_data.range_req.initiator = value;
886 data = iwl_dbgfs_is_match("one_sided_los_disable=", buf);
888 ret = kstrtou32(data, 10, &value);
890 mvm->tof_data.range_req.one_sided_los_disable = value;
894 data = iwl_dbgfs_is_match("req_timeout=", buf);
896 ret = kstrtou32(data, 10, &value);
898 mvm->tof_data.range_req.req_timeout = value;
902 data = iwl_dbgfs_is_match("report_policy=", buf);
904 ret = kstrtou32(data, 10, &value);
906 mvm->tof_data.range_req.report_policy = value;
910 data = iwl_dbgfs_is_match("macaddr_random=", buf);
912 ret = kstrtou32(data, 10, &value);
914 mvm->tof_data.range_req.macaddr_random = value;
918 data = iwl_dbgfs_is_match("num_of_ap=", buf);
920 ret = kstrtou32(data, 10, &value);
922 mvm->tof_data.range_req.num_of_ap = value;
926 data = iwl_dbgfs_is_match("macaddr_template=", buf);
930 if (!mac_pton(data, mac)) {
934 memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN);
938 data = iwl_dbgfs_is_match("macaddr_mask=", buf);
942 if (!mac_pton(data, mac)) {
946 memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN);
950 data = iwl_dbgfs_is_match("ap=", buf);
952 struct iwl_tof_range_req_ap_entry ap = {};
953 int size = sizeof(struct iwl_tof_range_req_ap_entry);
958 if (sscanf(data, "%u %hhd %hhd %hhd"
959 "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"
962 "%hhx %hhd %hhd %hhd",
963 &i, &ap.channel_num, &ap.bandwidth,
964 &ap.ctrl_ch_position,
965 mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
966 &ap.measure_type, &ap.num_of_bursts,
968 &ap.samples_per_burst, &ap.retries_per_sample,
969 &ap.tsf_delta, &ap.location_req, &ap.asap_mode,
970 &ap.enable_dyn_ack, &ap.rssi) != 20) {
974 if (i >= IWL_MVM_TOF_MAX_APS) {
975 IWL_ERR(mvm, "Invalid AP index %d\n", i);
980 ap.burst_period = cpu_to_le16(burst_period);
982 memcpy(&mvm->tof_data.range_req.ap[i], &ap, size);
986 data = iwl_dbgfs_is_match("send_range_request=", buf);
988 ret = kstrtou32(data, 10, &value);
989 if (ret == 0 && value)
990 ret = iwl_mvm_tof_range_request_cmd(mvm, vif);
996 mutex_unlock(&mvm->mutex);
1000 static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file,
1001 char __user *user_buf,
1002 size_t count, loff_t *ppos)
1004 struct ieee80211_vif *vif = file->private_data;
1005 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1006 struct iwl_mvm *mvm = mvmvif->mvm;
1009 const size_t bufsz = sizeof(buf);
1010 struct iwl_tof_range_req_cmd *cmd;
1013 cmd = &mvm->tof_data.range_req;
1015 mutex_lock(&mvm->mutex);
1017 pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n",
1019 pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n",
1021 pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n",
1022 cmd->one_sided_los_disable);
1023 pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n",
1025 pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n",
1026 cmd->report_policy);
1027 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n",
1028 cmd->macaddr_random);
1029 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n",
1030 cmd->macaddr_template);
1031 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n",
1033 pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n",
1035 for (i = 0; i < cmd->num_of_ap; i++) {
1036 struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i];
1038 pos += scnprintf(buf + pos, bufsz - pos,
1039 "ap %.2d: channel_num=%hhd bw=%hhd"
1040 " control=%hhd bssid=%pM type=%hhd"
1041 " num_of_bursts=%hhd burst_period=%hd ftm=%hhd"
1042 " retries=%hhd tsf_delta=%d"
1043 " tsf_delta_direction=%hhd location_req=0x%hhx "
1044 " asap=%hhd enable=%hhd rssi=%hhd\n",
1045 i, ap->channel_num, ap->bandwidth,
1046 ap->ctrl_ch_position, ap->bssid,
1047 ap->measure_type, ap->num_of_bursts,
1048 ap->burst_period, ap->samples_per_burst,
1049 ap->retries_per_sample, ap->tsf_delta,
1050 ap->tsf_delta_direction,
1051 ap->location_req, ap->asap_mode,
1052 ap->enable_dyn_ack, ap->rssi);
1055 mutex_unlock(&mvm->mutex);
1057 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1060 static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
1062 size_t count, loff_t *ppos)
1064 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1065 struct iwl_mvm *mvm = mvmvif->mvm;
1070 mutex_lock(&mvm->mutex);
1072 data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf);
1074 ret = kstrtou32(data, 10, &value);
1076 mvm->tof_data.range_req_ext.tsf_timer_offset_msec =
1081 data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
1083 ret = kstrtou32(data, 10, &value);
1085 mvm->tof_data.range_req_ext.min_delta_ftm = value;
1089 data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf);
1091 ret = kstrtou32(data, 10, &value);
1093 mvm->tof_data.range_req_ext.ftm_format_and_bw20M =
1098 data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf);
1100 ret = kstrtou32(data, 10, &value);
1102 mvm->tof_data.range_req_ext.ftm_format_and_bw40M =
1107 data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf);
1109 ret = kstrtou32(data, 10, &value);
1111 mvm->tof_data.range_req_ext.ftm_format_and_bw80M =
1116 data = iwl_dbgfs_is_match("send_range_req_ext=", buf);
1118 ret = kstrtou32(data, 10, &value);
1119 if (ret == 0 && value)
1120 ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif);
1126 mutex_unlock(&mvm->mutex);
1127 return ret ?: count;
1130 static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file,
1131 char __user *user_buf,
1132 size_t count, loff_t *ppos)
1134 struct ieee80211_vif *vif = file->private_data;
1135 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1136 struct iwl_mvm *mvm = mvmvif->mvm;
1139 const size_t bufsz = sizeof(buf);
1140 struct iwl_tof_range_req_ext_cmd *cmd;
1142 cmd = &mvm->tof_data.range_req_ext;
1144 mutex_lock(&mvm->mutex);
1146 pos += scnprintf(buf + pos, bufsz - pos,
1147 "tsf_timer_offset_msec = %hd\n",
1148 cmd->tsf_timer_offset_msec);
1149 pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n",
1150 cmd->min_delta_ftm);
1151 pos += scnprintf(buf + pos, bufsz - pos,
1152 "ftm_format_and_bw20M = %hhd\n",
1153 cmd->ftm_format_and_bw20M);
1154 pos += scnprintf(buf + pos, bufsz - pos,
1155 "ftm_format_and_bw40M = %hhd\n",
1156 cmd->ftm_format_and_bw40M);
1157 pos += scnprintf(buf + pos, bufsz - pos,
1158 "ftm_format_and_bw80M = %hhd\n",
1159 cmd->ftm_format_and_bw80M);
1161 mutex_unlock(&mvm->mutex);
1162 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1165 static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif,
1167 size_t count, loff_t *ppos)
1169 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1170 struct iwl_mvm *mvm = mvmvif->mvm;
1172 int abort_id, ret = 0;
1175 mutex_lock(&mvm->mutex);
1177 data = iwl_dbgfs_is_match("abort_id=", buf);
1179 ret = kstrtou32(data, 10, &value);
1181 mvm->tof_data.last_abort_id = value;
1185 data = iwl_dbgfs_is_match("send_range_abort=", buf);
1187 ret = kstrtou32(data, 10, &value);
1188 if (ret == 0 && value) {
1189 abort_id = mvm->tof_data.last_abort_id;
1190 ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id);
1196 mutex_unlock(&mvm->mutex);
1197 return ret ?: count;
1200 static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file,
1201 char __user *user_buf,
1202 size_t count, loff_t *ppos)
1204 struct ieee80211_vif *vif = file->private_data;
1205 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1206 struct iwl_mvm *mvm = mvmvif->mvm;
1209 const size_t bufsz = sizeof(buf);
1212 mutex_lock(&mvm->mutex);
1213 last_abort_id = mvm->tof_data.last_abort_id;
1214 mutex_unlock(&mvm->mutex);
1216 pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n",
1218 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1221 static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file,
1222 char __user *user_buf,
1223 size_t count, loff_t *ppos)
1225 struct ieee80211_vif *vif = file->private_data;
1226 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1227 struct iwl_mvm *mvm = mvmvif->mvm;
1230 const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256;
1231 struct iwl_tof_range_rsp_ntfy *cmd;
1234 buf = kzalloc(bufsz, GFP_KERNEL);
1238 mutex_lock(&mvm->mutex);
1239 cmd = &mvm->tof_data.range_resp;
1241 pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n",
1243 pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n",
1244 cmd->request_status);
1245 pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n",
1246 cmd->last_in_batch);
1247 pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n",
1249 for (i = 0; i < cmd->num_of_aps; i++) {
1250 struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i];
1252 pos += scnprintf(buf + pos, bufsz - pos,
1253 "ap %.2d: bssid=%pM status=%hhd bw=%hhd"
1254 " rtt=%d rtt_var=%d rtt_spread=%d"
1255 " rssi=%hhd rssi_spread=%hhd"
1256 " range=%d range_var=%d"
1258 i, ap->bssid, ap->measure_status,
1260 ap->rtt, ap->rtt_variance, ap->rtt_spread,
1261 ap->rssi, ap->rssi_spread, ap->range,
1262 ap->range_variance, ap->timestamp);
1264 mutex_unlock(&mvm->mutex);
1266 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1271 static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
1272 size_t count, loff_t *ppos)
1274 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1275 struct iwl_mvm *mvm = mvmvif->mvm;
1279 ret = kstrtou8(buf, 0, &value);
1285 mutex_lock(&mvm->mutex);
1286 iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS);
1287 mutex_unlock(&mvm->mutex);
1292 static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
1293 char __user *user_buf,
1294 size_t count, loff_t *ppos)
1296 struct ieee80211_vif *vif = file->private_data;
1297 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1301 len = scnprintf(buf, sizeof(buf) - 1,
1302 "traffic=%d\ndbgfs=%d\nvcmd=%d\nvif_type=%d\n",
1303 !!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC),
1304 !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS),
1305 !!(mvmvif->low_latency & LOW_LATENCY_VCMD),
1306 !!(mvmvif->low_latency & LOW_LATENCY_VIF_TYPE));
1307 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1310 static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
1311 char __user *user_buf,
1312 size_t count, loff_t *ppos)
1314 struct ieee80211_vif *vif = file->private_data;
1315 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1319 len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
1320 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1323 static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
1324 char *buf, size_t count,
1327 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1328 struct iwl_mvm *mvm = mvmvif->mvm;
1331 mutex_lock(&mvm->mutex);
1332 ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
1333 mutex_unlock(&mvm->mutex);
1335 return ret ? count : -EINVAL;
1338 static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
1339 size_t count, loff_t *ppos)
1341 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1342 struct iwl_mvm *mvm = mvmvif->mvm;
1343 struct ieee80211_chanctx_conf *chanctx_conf;
1344 struct iwl_mvm_phy_ctxt *phy_ctxt;
1348 ret = kstrtou16(buf, 0, &value);
1352 mutex_lock(&mvm->mutex);
1355 chanctx_conf = rcu_dereference(vif->chanctx_conf);
1356 /* make sure the channel context is assigned */
1357 if (!chanctx_conf) {
1359 mutex_unlock(&mvm->mutex);
1363 phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
1366 mvm->dbgfs_rx_phyinfo = value;
1368 ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
1369 chanctx_conf->rx_chains_static,
1370 chanctx_conf->rx_chains_dynamic);
1371 mutex_unlock(&mvm->mutex);
1373 return ret ?: count;
1376 static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
1377 char __user *user_buf,
1378 size_t count, loff_t *ppos)
1380 struct ieee80211_vif *vif = file->private_data;
1381 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1385 len = scnprintf(buf, sizeof(buf), "0x%04x\n",
1386 mvmvif->mvm->dbgfs_rx_phyinfo);
1388 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1391 static void iwl_dbgfs_quota_check(void *data, u8 *mac,
1392 struct ieee80211_vif *vif)
1394 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1397 if (mvmvif->dbgfs_quota_min)
1401 static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
1402 size_t count, loff_t *ppos)
1404 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1405 struct iwl_mvm *mvm = mvmvif->mvm;
1409 ret = kstrtou16(buf, 0, &value);
1416 mutex_lock(&mvm->mutex);
1418 mvmvif->dbgfs_quota_min = 0;
1419 ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1420 iwl_dbgfs_quota_check, &ret);
1422 mvmvif->dbgfs_quota_min = value;
1423 iwl_mvm_update_quotas(mvm, false, NULL);
1425 mutex_unlock(&mvm->mutex);
1427 return ret ?: count;
1430 static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
1431 char __user *user_buf,
1432 size_t count, loff_t *ppos)
1434 struct ieee80211_vif *vif = file->private_data;
1435 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1439 len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
1441 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1444 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1445 _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1446 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1447 _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1448 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
1449 if (!debugfs_create_file(#name, mode, parent, vif, \
1450 &iwl_dbgfs_##name##_ops)) \
1454 MVM_DEBUGFS_READ_FILE_OPS(mac_params);
1455 MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
1456 MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
1457 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
1458 MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
1459 MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
1460 MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
1461 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32);
1462 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512);
1463 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
1464 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
1465 MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
1466 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
1467 MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
1468 MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
1471 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1473 struct dentry *dbgfs_dir = vif->debugfs_dir;
1474 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1478 * Check if debugfs directory already exist before creating it.
1479 * This may happen when, for example, resetting hw or suspend-resume
1481 if (!dbgfs_dir || mvmvif->dbgfs_dir)
1484 mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
1486 if (!mvmvif->dbgfs_dir) {
1487 IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
1492 if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
1493 ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
1494 (vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
1495 MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600);
1497 MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400);
1498 MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400);
1499 MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600);
1500 MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600);
1501 MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600);
1502 MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600);
1503 MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400);
1505 if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
1506 mvmvif == mvm->bf_allowed_vif)
1507 MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600);
1509 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) &&
1510 !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) {
1511 if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP)
1512 MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params,
1513 mvmvif->dbgfs_dir, 0600);
1515 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir,
1517 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir,
1519 MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir,
1521 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir,
1523 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir,
1528 * Create symlink for convenience pointing to interface specific
1529 * debugfs entries for the driver. For example, under
1530 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
1532 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
1534 snprintf(buf, 100, "../../../%pd3/%pd",
1538 mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
1539 mvm->debugfs_dir, buf);
1540 if (!mvmvif->dbgfs_slink)
1541 IWL_ERR(mvm, "Can't create debugfs symbolic link under %pd\n",
1545 IWL_ERR(mvm, "Can't create debugfs entity\n");
1548 void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1550 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1552 debugfs_remove(mvmvif->dbgfs_slink);
1553 mvmvif->dbgfs_slink = NULL;
1555 debugfs_remove_recursive(mvmvif->dbgfs_dir);
1556 mvmvif->dbgfs_dir = NULL;