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