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