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 * 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 <linuxwifi@intel.com> 30 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 31 * 32 * BSD LICENSE 33 * 34 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 35 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 36 * 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" 66 #include "fw-api-tof.h" 67 #include "debugfs.h" 68 69 static 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: { 80 int dtimper = vif->bss_conf.dtim_period ?: 1; 81 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; 108 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; 124 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; 128 } 129 } 130 131 static 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; 159 } 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; 178 } 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; 182 } else { 183 return -EINVAL; 184 } 185 186 mutex_lock(&mvm->mutex); 187 iwl_dbgfs_update_pm(mvm, vif, param, val); 188 ret = iwl_mvm_power_update_mac(mvm); 189 mutex_unlock(&mvm->mutex); 190 191 return ret ?: count; 192 } 193 194 static 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 209 static 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 220 pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz); 221 222 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 223 } 224 225 static 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); 231 struct iwl_mvm *mvm = mvmvif->mvm; 232 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 243 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 266 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; 283 284 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id], 285 lockdep_is_held(&mvm->mutex)); 286 if (!IS_ERR_OR_NULL(sta)) { 287 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); 288 289 pos += scnprintf(buf+pos, bufsz-pos, 290 "ap_sta_id %d - reduced Tx power %d\n", 291 ap_sta_id, 292 mvm_sta->bt_reduced_txpower); 293 } 294 } 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 310 static 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 355 static 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) 444 ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); 445 else 446 ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); 447 mutex_unlock(&mvm->mutex); 448 449 return ret ?: count; 450 } 451 452 static 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 501 static 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 508 static 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; 514 u32 value; 515 int ret = -EINVAL; 516 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 561 out: 562 mutex_unlock(&mvm->mutex); 563 564 return ret ?: count; 565 } 566 567 static 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 597 static 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; 603 u32 value; 604 int ret = 0; 605 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("center_freq=", buf); 719 if (data) { 720 struct iwl_tof_responder_config_cmd *cmd = 721 &mvm->tof_data.responder_cfg; 722 723 ret = kstrtou32(data, 10, &value); 724 if (ret == 0 && value) { 725 enum ieee80211_band band = (cmd->channel_num <= 14) ? 726 IEEE80211_BAND_2GHZ : 727 IEEE80211_BAND_5GHZ; 728 struct ieee80211_channel chn = { 729 .band = band, 730 .center_freq = ieee80211_channel_to_frequency( 731 cmd->channel_num, band), 732 }; 733 struct cfg80211_chan_def chandef = { 734 .chan = &chn, 735 .center_freq1 = 736 ieee80211_channel_to_frequency(value, 737 band), 738 }; 739 740 cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef); 741 } 742 goto out; 743 } 744 745 data = iwl_dbgfs_is_match("ftm_per_burst=", buf); 746 if (data) { 747 ret = kstrtou32(data, 10, &value); 748 if (ret == 0) 749 mvm->tof_data.responder_cfg.ftm_per_burst = value; 750 goto out; 751 } 752 753 data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf); 754 if (data) { 755 ret = kstrtou32(data, 10, &value); 756 if (ret == 0) 757 mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value; 758 goto out; 759 } 760 761 data = iwl_dbgfs_is_match("asap_mode=", buf); 762 if (data) { 763 ret = kstrtou32(data, 10, &value); 764 if (ret == 0) 765 mvm->tof_data.responder_cfg.asap_mode = value; 766 goto out; 767 } 768 769 data = iwl_dbgfs_is_match("send_responder_cfg=", buf); 770 if (data) { 771 ret = kstrtou32(data, 10, &value); 772 if (ret == 0 && value) { 773 ret = iwl_mvm_tof_responder_cmd(mvm, vif); 774 goto out; 775 } 776 } 777 778 out: 779 mutex_unlock(&mvm->mutex); 780 781 return ret ?: count; 782 } 783 784 static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file, 785 char __user *user_buf, 786 size_t count, loff_t *ppos) 787 { 788 struct ieee80211_vif *vif = file->private_data; 789 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 790 struct iwl_mvm *mvm = mvmvif->mvm; 791 char buf[256]; 792 int pos = 0; 793 const size_t bufsz = sizeof(buf); 794 struct iwl_tof_responder_config_cmd *cmd; 795 796 cmd = &mvm->tof_data.responder_cfg; 797 798 mutex_lock(&mvm->mutex); 799 800 pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n", 801 le16_to_cpu(cmd->burst_period)); 802 pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n", 803 cmd->burst_duration); 804 pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n", 805 cmd->bandwidth); 806 pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n", 807 cmd->channel_num); 808 pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n", 809 cmd->ctrl_ch_position); 810 pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n", 811 cmd->bssid); 812 pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n", 813 cmd->min_delta_ftm); 814 pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n", 815 cmd->num_of_burst_exp); 816 pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate); 817 pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n", 818 cmd->abort_responder); 819 pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n", 820 cmd->get_ch_est); 821 pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n", 822 cmd->recv_sta_req_params); 823 pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n", 824 cmd->ftm_per_burst); 825 pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n", 826 cmd->ftm_resp_ts_avail); 827 pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n", 828 cmd->asap_mode); 829 pos += scnprintf(buf + pos, bufsz - pos, 830 "tsf_timer_offset_msecs = %d\n", 831 le16_to_cpu(cmd->tsf_timer_offset_msecs)); 832 pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n", 833 le16_to_cpu(cmd->toa_offset)); 834 835 mutex_unlock(&mvm->mutex); 836 837 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 838 } 839 840 static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif, 841 char *buf, size_t count, 842 loff_t *ppos) 843 { 844 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 845 struct iwl_mvm *mvm = mvmvif->mvm; 846 u32 value; 847 int ret = 0; 848 char *data; 849 850 mutex_lock(&mvm->mutex); 851 852 data = iwl_dbgfs_is_match("request_id=", buf); 853 if (data) { 854 ret = kstrtou32(data, 10, &value); 855 if (ret == 0) 856 mvm->tof_data.range_req.request_id = value; 857 goto out; 858 } 859 860 data = iwl_dbgfs_is_match("initiator=", buf); 861 if (data) { 862 ret = kstrtou32(data, 10, &value); 863 if (ret == 0) 864 mvm->tof_data.range_req.initiator = value; 865 goto out; 866 } 867 868 data = iwl_dbgfs_is_match("one_sided_los_disable=", buf); 869 if (data) { 870 ret = kstrtou32(data, 10, &value); 871 if (ret == 0) 872 mvm->tof_data.range_req.one_sided_los_disable = value; 873 goto out; 874 } 875 876 data = iwl_dbgfs_is_match("req_timeout=", buf); 877 if (data) { 878 ret = kstrtou32(data, 10, &value); 879 if (ret == 0) 880 mvm->tof_data.range_req.req_timeout = value; 881 goto out; 882 } 883 884 data = iwl_dbgfs_is_match("report_policy=", buf); 885 if (data) { 886 ret = kstrtou32(data, 10, &value); 887 if (ret == 0) 888 mvm->tof_data.range_req.report_policy = value; 889 goto out; 890 } 891 892 data = iwl_dbgfs_is_match("macaddr_random=", buf); 893 if (data) { 894 ret = kstrtou32(data, 10, &value); 895 if (ret == 0) 896 mvm->tof_data.range_req.macaddr_random = value; 897 goto out; 898 } 899 900 data = iwl_dbgfs_is_match("num_of_ap=", buf); 901 if (data) { 902 ret = kstrtou32(data, 10, &value); 903 if (ret == 0) 904 mvm->tof_data.range_req.num_of_ap = value; 905 goto out; 906 } 907 908 data = iwl_dbgfs_is_match("macaddr_template=", buf); 909 if (data) { 910 u8 mac[ETH_ALEN]; 911 912 if (!mac_pton(data, mac)) { 913 ret = -EINVAL; 914 goto out; 915 } 916 memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN); 917 goto out; 918 } 919 920 data = iwl_dbgfs_is_match("macaddr_mask=", buf); 921 if (data) { 922 u8 mac[ETH_ALEN]; 923 924 if (!mac_pton(data, mac)) { 925 ret = -EINVAL; 926 goto out; 927 } 928 memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN); 929 goto out; 930 } 931 932 data = iwl_dbgfs_is_match("ap=", buf); 933 if (data) { 934 struct iwl_tof_range_req_ap_entry ap = {}; 935 int size = sizeof(struct iwl_tof_range_req_ap_entry); 936 u16 burst_period; 937 u8 *mac = ap.bssid; 938 unsigned int i; 939 940 if (sscanf(data, "%u %hhd %hhd %hhd" 941 "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" 942 "%hhd %hhd %hd" 943 "%hhd %hhd %d" 944 "%hhx %hhd %hhd %hhd", 945 &i, &ap.channel_num, &ap.bandwidth, 946 &ap.ctrl_ch_position, 947 mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5, 948 &ap.measure_type, &ap.num_of_bursts, 949 &burst_period, 950 &ap.samples_per_burst, &ap.retries_per_sample, 951 &ap.tsf_delta, &ap.location_req, &ap.asap_mode, 952 &ap.enable_dyn_ack, &ap.rssi) != 20) { 953 ret = -EINVAL; 954 goto out; 955 } 956 if (i >= IWL_MVM_TOF_MAX_APS) { 957 IWL_ERR(mvm, "Invalid AP index %d\n", i); 958 ret = -EINVAL; 959 goto out; 960 } 961 962 ap.burst_period = cpu_to_le16(burst_period); 963 964 memcpy(&mvm->tof_data.range_req.ap[i], &ap, size); 965 goto out; 966 } 967 968 data = iwl_dbgfs_is_match("send_range_request=", buf); 969 if (data) { 970 ret = kstrtou32(data, 10, &value); 971 if (ret == 0 && value) 972 ret = iwl_mvm_tof_range_request_cmd(mvm, vif); 973 goto out; 974 } 975 976 ret = -EINVAL; 977 out: 978 mutex_unlock(&mvm->mutex); 979 return ret ?: count; 980 } 981 982 static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file, 983 char __user *user_buf, 984 size_t count, loff_t *ppos) 985 { 986 struct ieee80211_vif *vif = file->private_data; 987 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 988 struct iwl_mvm *mvm = mvmvif->mvm; 989 char buf[512]; 990 int pos = 0; 991 const size_t bufsz = sizeof(buf); 992 struct iwl_tof_range_req_cmd *cmd; 993 int i; 994 995 cmd = &mvm->tof_data.range_req; 996 997 mutex_lock(&mvm->mutex); 998 999 pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n", 1000 cmd->request_id); 1001 pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n", 1002 cmd->initiator); 1003 pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n", 1004 cmd->one_sided_los_disable); 1005 pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n", 1006 cmd->req_timeout); 1007 pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n", 1008 cmd->report_policy); 1009 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n", 1010 cmd->macaddr_random); 1011 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n", 1012 cmd->macaddr_template); 1013 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n", 1014 cmd->macaddr_mask); 1015 pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n", 1016 cmd->num_of_ap); 1017 for (i = 0; i < cmd->num_of_ap; i++) { 1018 struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i]; 1019 1020 pos += scnprintf(buf + pos, bufsz - pos, 1021 "ap %.2d: channel_num=%hhd bw=%hhd" 1022 " control=%hhd bssid=%pM type=%hhd" 1023 " num_of_bursts=%hhd burst_period=%hd ftm=%hhd" 1024 " retries=%hhd tsf_delta=%d" 1025 " tsf_delta_direction=%hhd location_req=0x%hhx " 1026 " asap=%hhd enable=%hhd rssi=%hhd\n", 1027 i, ap->channel_num, ap->bandwidth, 1028 ap->ctrl_ch_position, ap->bssid, 1029 ap->measure_type, ap->num_of_bursts, 1030 ap->burst_period, ap->samples_per_burst, 1031 ap->retries_per_sample, ap->tsf_delta, 1032 ap->tsf_delta_direction, 1033 ap->location_req, ap->asap_mode, 1034 ap->enable_dyn_ack, ap->rssi); 1035 } 1036 1037 mutex_unlock(&mvm->mutex); 1038 1039 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1040 } 1041 1042 static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif, 1043 char *buf, 1044 size_t count, loff_t *ppos) 1045 { 1046 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1047 struct iwl_mvm *mvm = mvmvif->mvm; 1048 u32 value; 1049 int ret = 0; 1050 char *data; 1051 1052 mutex_lock(&mvm->mutex); 1053 1054 data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf); 1055 if (data) { 1056 ret = kstrtou32(data, 10, &value); 1057 if (ret == 0) 1058 mvm->tof_data.range_req_ext.tsf_timer_offset_msec = 1059 cpu_to_le16(value); 1060 goto out; 1061 } 1062 1063 data = iwl_dbgfs_is_match("min_delta_ftm=", buf); 1064 if (data) { 1065 ret = kstrtou32(data, 10, &value); 1066 if (ret == 0) 1067 mvm->tof_data.range_req_ext.min_delta_ftm = value; 1068 goto out; 1069 } 1070 1071 data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf); 1072 if (data) { 1073 ret = kstrtou32(data, 10, &value); 1074 if (ret == 0) 1075 mvm->tof_data.range_req_ext.ftm_format_and_bw20M = 1076 value; 1077 goto out; 1078 } 1079 1080 data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf); 1081 if (data) { 1082 ret = kstrtou32(data, 10, &value); 1083 if (ret == 0) 1084 mvm->tof_data.range_req_ext.ftm_format_and_bw40M = 1085 value; 1086 goto out; 1087 } 1088 1089 data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf); 1090 if (data) { 1091 ret = kstrtou32(data, 10, &value); 1092 if (ret == 0) 1093 mvm->tof_data.range_req_ext.ftm_format_and_bw80M = 1094 value; 1095 goto out; 1096 } 1097 1098 data = iwl_dbgfs_is_match("send_range_req_ext=", buf); 1099 if (data) { 1100 ret = kstrtou32(data, 10, &value); 1101 if (ret == 0 && value) 1102 ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif); 1103 goto out; 1104 } 1105 1106 ret = -EINVAL; 1107 out: 1108 mutex_unlock(&mvm->mutex); 1109 return ret ?: count; 1110 } 1111 1112 static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file, 1113 char __user *user_buf, 1114 size_t count, loff_t *ppos) 1115 { 1116 struct ieee80211_vif *vif = file->private_data; 1117 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1118 struct iwl_mvm *mvm = mvmvif->mvm; 1119 char buf[256]; 1120 int pos = 0; 1121 const size_t bufsz = sizeof(buf); 1122 struct iwl_tof_range_req_ext_cmd *cmd; 1123 1124 cmd = &mvm->tof_data.range_req_ext; 1125 1126 mutex_lock(&mvm->mutex); 1127 1128 pos += scnprintf(buf + pos, bufsz - pos, 1129 "tsf_timer_offset_msec = %hd\n", 1130 cmd->tsf_timer_offset_msec); 1131 pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n", 1132 cmd->min_delta_ftm); 1133 pos += scnprintf(buf + pos, bufsz - pos, 1134 "ftm_format_and_bw20M = %hhd\n", 1135 cmd->ftm_format_and_bw20M); 1136 pos += scnprintf(buf + pos, bufsz - pos, 1137 "ftm_format_and_bw40M = %hhd\n", 1138 cmd->ftm_format_and_bw40M); 1139 pos += scnprintf(buf + pos, bufsz - pos, 1140 "ftm_format_and_bw80M = %hhd\n", 1141 cmd->ftm_format_and_bw80M); 1142 1143 mutex_unlock(&mvm->mutex); 1144 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1145 } 1146 1147 static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif, 1148 char *buf, 1149 size_t count, loff_t *ppos) 1150 { 1151 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1152 struct iwl_mvm *mvm = mvmvif->mvm; 1153 u32 value; 1154 int abort_id, ret = 0; 1155 char *data; 1156 1157 mutex_lock(&mvm->mutex); 1158 1159 data = iwl_dbgfs_is_match("abort_id=", buf); 1160 if (data) { 1161 ret = kstrtou32(data, 10, &value); 1162 if (ret == 0) 1163 mvm->tof_data.last_abort_id = value; 1164 goto out; 1165 } 1166 1167 data = iwl_dbgfs_is_match("send_range_abort=", buf); 1168 if (data) { 1169 ret = kstrtou32(data, 10, &value); 1170 if (ret == 0 && value) { 1171 abort_id = mvm->tof_data.last_abort_id; 1172 ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id); 1173 goto out; 1174 } 1175 } 1176 1177 out: 1178 mutex_unlock(&mvm->mutex); 1179 return ret ?: count; 1180 } 1181 1182 static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file, 1183 char __user *user_buf, 1184 size_t count, loff_t *ppos) 1185 { 1186 struct ieee80211_vif *vif = file->private_data; 1187 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1188 struct iwl_mvm *mvm = mvmvif->mvm; 1189 char buf[32]; 1190 int pos = 0; 1191 const size_t bufsz = sizeof(buf); 1192 int last_abort_id; 1193 1194 mutex_lock(&mvm->mutex); 1195 last_abort_id = mvm->tof_data.last_abort_id; 1196 mutex_unlock(&mvm->mutex); 1197 1198 pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n", 1199 last_abort_id); 1200 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1201 } 1202 1203 static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file, 1204 char __user *user_buf, 1205 size_t count, loff_t *ppos) 1206 { 1207 struct ieee80211_vif *vif = file->private_data; 1208 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1209 struct iwl_mvm *mvm = mvmvif->mvm; 1210 char *buf; 1211 int pos = 0; 1212 const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256; 1213 struct iwl_tof_range_rsp_ntfy *cmd; 1214 int i, ret; 1215 1216 buf = kzalloc(bufsz, GFP_KERNEL); 1217 if (!buf) 1218 return -ENOMEM; 1219 1220 mutex_lock(&mvm->mutex); 1221 cmd = &mvm->tof_data.range_resp; 1222 1223 pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n", 1224 cmd->request_id); 1225 pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n", 1226 cmd->request_status); 1227 pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n", 1228 cmd->last_in_batch); 1229 pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n", 1230 cmd->num_of_aps); 1231 for (i = 0; i < cmd->num_of_aps; i++) { 1232 struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i]; 1233 1234 pos += scnprintf(buf + pos, bufsz - pos, 1235 "ap %.2d: bssid=%pM status=%hhd bw=%hhd" 1236 " rtt=%d rtt_var=%d rtt_spread=%d" 1237 " rssi=%hhd rssi_spread=%hhd" 1238 " range=%d range_var=%d" 1239 " time_stamp=%d\n", 1240 i, ap->bssid, ap->measure_status, 1241 ap->measure_bw, 1242 ap->rtt, ap->rtt_variance, ap->rtt_spread, 1243 ap->rssi, ap->rssi_spread, ap->range, 1244 ap->range_variance, ap->timestamp); 1245 } 1246 mutex_unlock(&mvm->mutex); 1247 1248 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1249 kfree(buf); 1250 return ret; 1251 } 1252 1253 static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, 1254 size_t count, loff_t *ppos) 1255 { 1256 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1257 struct iwl_mvm *mvm = mvmvif->mvm; 1258 u8 value; 1259 int ret; 1260 1261 ret = kstrtou8(buf, 0, &value); 1262 if (ret) 1263 return ret; 1264 if (value > 1) 1265 return -EINVAL; 1266 1267 mutex_lock(&mvm->mutex); 1268 iwl_mvm_update_low_latency(mvm, vif, value); 1269 mutex_unlock(&mvm->mutex); 1270 1271 return count; 1272 } 1273 1274 static ssize_t iwl_dbgfs_low_latency_read(struct file *file, 1275 char __user *user_buf, 1276 size_t count, loff_t *ppos) 1277 { 1278 struct ieee80211_vif *vif = file->private_data; 1279 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1280 char buf[2]; 1281 1282 buf[0] = mvmvif->low_latency ? '1' : '0'; 1283 buf[1] = '\n'; 1284 return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); 1285 } 1286 1287 static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file, 1288 char __user *user_buf, 1289 size_t count, loff_t *ppos) 1290 { 1291 struct ieee80211_vif *vif = file->private_data; 1292 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1293 char buf[20]; 1294 int len; 1295 1296 len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid); 1297 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1298 } 1299 1300 static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif, 1301 char *buf, size_t count, 1302 loff_t *ppos) 1303 { 1304 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1305 struct iwl_mvm *mvm = mvmvif->mvm; 1306 bool ret; 1307 1308 mutex_lock(&mvm->mutex); 1309 ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid); 1310 mutex_unlock(&mvm->mutex); 1311 1312 return ret ? count : -EINVAL; 1313 } 1314 1315 static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, 1316 size_t count, loff_t *ppos) 1317 { 1318 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1319 struct iwl_mvm *mvm = mvmvif->mvm; 1320 struct ieee80211_chanctx_conf *chanctx_conf; 1321 struct iwl_mvm_phy_ctxt *phy_ctxt; 1322 u16 value; 1323 int ret; 1324 1325 ret = kstrtou16(buf, 0, &value); 1326 if (ret) 1327 return ret; 1328 1329 mutex_lock(&mvm->mutex); 1330 rcu_read_lock(); 1331 1332 chanctx_conf = rcu_dereference(vif->chanctx_conf); 1333 /* make sure the channel context is assigned */ 1334 if (!chanctx_conf) { 1335 rcu_read_unlock(); 1336 mutex_unlock(&mvm->mutex); 1337 return -EINVAL; 1338 } 1339 1340 phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv]; 1341 rcu_read_unlock(); 1342 1343 mvm->dbgfs_rx_phyinfo = value; 1344 1345 ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def, 1346 chanctx_conf->rx_chains_static, 1347 chanctx_conf->rx_chains_dynamic); 1348 mutex_unlock(&mvm->mutex); 1349 1350 return ret ?: count; 1351 } 1352 1353 static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file, 1354 char __user *user_buf, 1355 size_t count, loff_t *ppos) 1356 { 1357 struct ieee80211_vif *vif = file->private_data; 1358 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1359 char buf[8]; 1360 1361 snprintf(buf, sizeof(buf), "0x%04x\n", mvmvif->mvm->dbgfs_rx_phyinfo); 1362 1363 return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); 1364 } 1365 1366 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ 1367 _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) 1368 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ 1369 _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) 1370 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ 1371 if (!debugfs_create_file(#name, mode, parent, vif, \ 1372 &iwl_dbgfs_##name##_ops)) \ 1373 goto err; \ 1374 } while (0) 1375 1376 MVM_DEBUGFS_READ_FILE_OPS(mac_params); 1377 MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt); 1378 MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); 1379 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); 1380 MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); 1381 MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); 1382 MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); 1383 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32); 1384 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512); 1385 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32); 1386 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32); 1387 MVM_DEBUGFS_READ_FILE_OPS(tof_range_response); 1388 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32); 1389 1390 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 1391 { 1392 struct dentry *dbgfs_dir = vif->debugfs_dir; 1393 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1394 char buf[100]; 1395 1396 /* 1397 * Check if debugfs directory already exist before creating it. 1398 * This may happen when, for example, resetting hw or suspend-resume 1399 */ 1400 if (!dbgfs_dir || mvmvif->dbgfs_dir) 1401 return; 1402 1403 mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); 1404 1405 if (!mvmvif->dbgfs_dir) { 1406 IWL_ERR(mvm, "Failed to create debugfs directory under %s\n", 1407 dbgfs_dir->d_name.name); 1408 return; 1409 } 1410 1411 if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && 1412 ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || 1413 (vif->type == NL80211_IFTYPE_STATION && vif->p2p && 1414 mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))) 1415 MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | 1416 S_IRUSR); 1417 1418 MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR); 1419 MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR); 1420 MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 1421 S_IRUSR | S_IWUSR); 1422 MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 1423 S_IRUSR | S_IWUSR); 1424 MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 1425 S_IRUSR | S_IWUSR); 1426 1427 if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && 1428 mvmvif == mvm->bf_allowed_vif) 1429 MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 1430 S_IRUSR | S_IWUSR); 1431 1432 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) && 1433 !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) { 1434 if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP) 1435 MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params, 1436 mvmvif->dbgfs_dir, 1437 S_IRUSR | S_IWUSR); 1438 1439 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir, 1440 S_IRUSR | S_IWUSR); 1441 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir, 1442 S_IRUSR | S_IWUSR); 1443 MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir, 1444 S_IRUSR | S_IWUSR); 1445 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir, 1446 S_IRUSR | S_IWUSR); 1447 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir, 1448 S_IRUSR); 1449 } 1450 1451 /* 1452 * Create symlink for convenience pointing to interface specific 1453 * debugfs entries for the driver. For example, under 1454 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/ 1455 * find 1456 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ 1457 */ 1458 snprintf(buf, 100, "../../../%s/%s/%s/%s", 1459 dbgfs_dir->d_parent->d_parent->d_name.name, 1460 dbgfs_dir->d_parent->d_name.name, 1461 dbgfs_dir->d_name.name, 1462 mvmvif->dbgfs_dir->d_name.name); 1463 1464 mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, 1465 mvm->debugfs_dir, buf); 1466 if (!mvmvif->dbgfs_slink) 1467 IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n", 1468 dbgfs_dir->d_name.name); 1469 return; 1470 err: 1471 IWL_ERR(mvm, "Can't create debugfs entity\n"); 1472 } 1473 1474 void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 1475 { 1476 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1477 1478 debugfs_remove(mvmvif->dbgfs_slink); 1479 mvmvif->dbgfs_slink = NULL; 1480 1481 debugfs_remove_recursive(mvmvif->dbgfs_dir); 1482 mvmvif->dbgfs_dir = NULL; 1483 } 1484