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_tof_enable_write(struct ieee80211_vif *vif, 508 char *buf, 509 size_t count, loff_t *ppos) 510 { 511 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 512 struct iwl_mvm *mvm = mvmvif->mvm; 513 u32 value; 514 int ret = -EINVAL; 515 char *data; 516 517 mutex_lock(&mvm->mutex); 518 519 data = iwl_dbgfs_is_match("tof_disabled=", buf); 520 if (data) { 521 ret = kstrtou32(data, 10, &value); 522 if (ret == 0) 523 mvm->tof_data.tof_cfg.tof_disabled = value; 524 goto out; 525 } 526 527 data = iwl_dbgfs_is_match("one_sided_disabled=", buf); 528 if (data) { 529 ret = kstrtou32(data, 10, &value); 530 if (ret == 0) 531 mvm->tof_data.tof_cfg.one_sided_disabled = value; 532 goto out; 533 } 534 535 data = iwl_dbgfs_is_match("is_debug_mode=", buf); 536 if (data) { 537 ret = kstrtou32(data, 10, &value); 538 if (ret == 0) 539 mvm->tof_data.tof_cfg.is_debug_mode = value; 540 goto out; 541 } 542 543 data = iwl_dbgfs_is_match("is_buf=", buf); 544 if (data) { 545 ret = kstrtou32(data, 10, &value); 546 if (ret == 0) 547 mvm->tof_data.tof_cfg.is_buf_required = value; 548 goto out; 549 } 550 551 data = iwl_dbgfs_is_match("send_tof_cfg=", buf); 552 if (data) { 553 ret = kstrtou32(data, 10, &value); 554 if (ret == 0 && value) { 555 ret = iwl_mvm_tof_config_cmd(mvm); 556 goto out; 557 } 558 } 559 560 out: 561 mutex_unlock(&mvm->mutex); 562 563 return ret ?: count; 564 } 565 566 static ssize_t iwl_dbgfs_tof_enable_read(struct file *file, 567 char __user *user_buf, 568 size_t count, loff_t *ppos) 569 { 570 struct ieee80211_vif *vif = file->private_data; 571 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 572 struct iwl_mvm *mvm = mvmvif->mvm; 573 char buf[256]; 574 int pos = 0; 575 const size_t bufsz = sizeof(buf); 576 struct iwl_tof_config_cmd *cmd; 577 578 cmd = &mvm->tof_data.tof_cfg; 579 580 mutex_lock(&mvm->mutex); 581 582 pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n", 583 cmd->tof_disabled); 584 pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n", 585 cmd->one_sided_disabled); 586 pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n", 587 cmd->is_debug_mode); 588 pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n", 589 cmd->is_buf_required); 590 591 mutex_unlock(&mvm->mutex); 592 593 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 594 } 595 596 static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif, 597 char *buf, 598 size_t count, loff_t *ppos) 599 { 600 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 601 struct iwl_mvm *mvm = mvmvif->mvm; 602 u32 value; 603 int ret = 0; 604 char *data; 605 606 mutex_lock(&mvm->mutex); 607 608 data = iwl_dbgfs_is_match("burst_period=", buf); 609 if (data) { 610 ret = kstrtou32(data, 10, &value); 611 if (!ret) 612 mvm->tof_data.responder_cfg.burst_period = 613 cpu_to_le16(value); 614 goto out; 615 } 616 617 data = iwl_dbgfs_is_match("min_delta_ftm=", buf); 618 if (data) { 619 ret = kstrtou32(data, 10, &value); 620 if (ret == 0) 621 mvm->tof_data.responder_cfg.min_delta_ftm = value; 622 goto out; 623 } 624 625 data = iwl_dbgfs_is_match("burst_duration=", buf); 626 if (data) { 627 ret = kstrtou32(data, 10, &value); 628 if (ret == 0) 629 mvm->tof_data.responder_cfg.burst_duration = value; 630 goto out; 631 } 632 633 data = iwl_dbgfs_is_match("num_of_burst_exp=", buf); 634 if (data) { 635 ret = kstrtou32(data, 10, &value); 636 if (ret == 0) 637 mvm->tof_data.responder_cfg.num_of_burst_exp = value; 638 goto out; 639 } 640 641 data = iwl_dbgfs_is_match("abort_responder=", buf); 642 if (data) { 643 ret = kstrtou32(data, 10, &value); 644 if (ret == 0) 645 mvm->tof_data.responder_cfg.abort_responder = value; 646 goto out; 647 } 648 649 data = iwl_dbgfs_is_match("get_ch_est=", buf); 650 if (data) { 651 ret = kstrtou32(data, 10, &value); 652 if (ret == 0) 653 mvm->tof_data.responder_cfg.get_ch_est = value; 654 goto out; 655 } 656 657 data = iwl_dbgfs_is_match("recv_sta_req_params=", buf); 658 if (data) { 659 ret = kstrtou32(data, 10, &value); 660 if (ret == 0) 661 mvm->tof_data.responder_cfg.recv_sta_req_params = value; 662 goto out; 663 } 664 665 data = iwl_dbgfs_is_match("channel_num=", buf); 666 if (data) { 667 ret = kstrtou32(data, 10, &value); 668 if (ret == 0) 669 mvm->tof_data.responder_cfg.channel_num = value; 670 goto out; 671 } 672 673 data = iwl_dbgfs_is_match("bandwidth=", buf); 674 if (data) { 675 ret = kstrtou32(data, 10, &value); 676 if (ret == 0) 677 mvm->tof_data.responder_cfg.bandwidth = value; 678 goto out; 679 } 680 681 data = iwl_dbgfs_is_match("rate=", buf); 682 if (data) { 683 ret = kstrtou32(data, 10, &value); 684 if (ret == 0) 685 mvm->tof_data.responder_cfg.rate = value; 686 goto out; 687 } 688 689 data = iwl_dbgfs_is_match("bssid=", buf); 690 if (data) { 691 u8 *mac = mvm->tof_data.responder_cfg.bssid; 692 693 if (!mac_pton(data, mac)) { 694 ret = -EINVAL; 695 goto out; 696 } 697 } 698 699 data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf); 700 if (data) { 701 ret = kstrtou32(data, 10, &value); 702 if (ret == 0) 703 mvm->tof_data.responder_cfg.tsf_timer_offset_msecs = 704 cpu_to_le16(value); 705 goto out; 706 } 707 708 data = iwl_dbgfs_is_match("toa_offset=", buf); 709 if (data) { 710 ret = kstrtou32(data, 10, &value); 711 if (ret == 0) 712 mvm->tof_data.responder_cfg.toa_offset = 713 cpu_to_le16(value); 714 goto out; 715 } 716 717 data = iwl_dbgfs_is_match("center_freq=", buf); 718 if (data) { 719 struct iwl_tof_responder_config_cmd *cmd = 720 &mvm->tof_data.responder_cfg; 721 722 ret = kstrtou32(data, 10, &value); 723 if (ret == 0 && value) { 724 enum nl80211_band band = (cmd->channel_num <= 14) ? 725 NL80211_BAND_2GHZ : 726 NL80211_BAND_5GHZ; 727 struct ieee80211_channel chn = { 728 .band = band, 729 .center_freq = ieee80211_channel_to_frequency( 730 cmd->channel_num, band), 731 }; 732 struct cfg80211_chan_def chandef = { 733 .chan = &chn, 734 .center_freq1 = 735 ieee80211_channel_to_frequency(value, 736 band), 737 }; 738 739 cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef); 740 } 741 goto out; 742 } 743 744 data = iwl_dbgfs_is_match("ftm_per_burst=", buf); 745 if (data) { 746 ret = kstrtou32(data, 10, &value); 747 if (ret == 0) 748 mvm->tof_data.responder_cfg.ftm_per_burst = value; 749 goto out; 750 } 751 752 data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf); 753 if (data) { 754 ret = kstrtou32(data, 10, &value); 755 if (ret == 0) 756 mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value; 757 goto out; 758 } 759 760 data = iwl_dbgfs_is_match("asap_mode=", buf); 761 if (data) { 762 ret = kstrtou32(data, 10, &value); 763 if (ret == 0) 764 mvm->tof_data.responder_cfg.asap_mode = value; 765 goto out; 766 } 767 768 data = iwl_dbgfs_is_match("send_responder_cfg=", buf); 769 if (data) { 770 ret = kstrtou32(data, 10, &value); 771 if (ret == 0 && value) { 772 ret = iwl_mvm_tof_responder_cmd(mvm, vif); 773 goto out; 774 } 775 } 776 777 out: 778 mutex_unlock(&mvm->mutex); 779 780 return ret ?: count; 781 } 782 783 static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file, 784 char __user *user_buf, 785 size_t count, loff_t *ppos) 786 { 787 struct ieee80211_vif *vif = file->private_data; 788 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 789 struct iwl_mvm *mvm = mvmvif->mvm; 790 char buf[256]; 791 int pos = 0; 792 const size_t bufsz = sizeof(buf); 793 struct iwl_tof_responder_config_cmd *cmd; 794 795 cmd = &mvm->tof_data.responder_cfg; 796 797 mutex_lock(&mvm->mutex); 798 799 pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n", 800 le16_to_cpu(cmd->burst_period)); 801 pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n", 802 cmd->burst_duration); 803 pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n", 804 cmd->bandwidth); 805 pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n", 806 cmd->channel_num); 807 pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n", 808 cmd->ctrl_ch_position); 809 pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n", 810 cmd->bssid); 811 pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n", 812 cmd->min_delta_ftm); 813 pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n", 814 cmd->num_of_burst_exp); 815 pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate); 816 pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n", 817 cmd->abort_responder); 818 pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n", 819 cmd->get_ch_est); 820 pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n", 821 cmd->recv_sta_req_params); 822 pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n", 823 cmd->ftm_per_burst); 824 pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n", 825 cmd->ftm_resp_ts_avail); 826 pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n", 827 cmd->asap_mode); 828 pos += scnprintf(buf + pos, bufsz - pos, 829 "tsf_timer_offset_msecs = %d\n", 830 le16_to_cpu(cmd->tsf_timer_offset_msecs)); 831 pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n", 832 le16_to_cpu(cmd->toa_offset)); 833 834 mutex_unlock(&mvm->mutex); 835 836 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 837 } 838 839 static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif, 840 char *buf, size_t count, 841 loff_t *ppos) 842 { 843 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 844 struct iwl_mvm *mvm = mvmvif->mvm; 845 u32 value; 846 int ret = 0; 847 char *data; 848 849 mutex_lock(&mvm->mutex); 850 851 data = iwl_dbgfs_is_match("request_id=", buf); 852 if (data) { 853 ret = kstrtou32(data, 10, &value); 854 if (ret == 0) 855 mvm->tof_data.range_req.request_id = value; 856 goto out; 857 } 858 859 data = iwl_dbgfs_is_match("initiator=", buf); 860 if (data) { 861 ret = kstrtou32(data, 10, &value); 862 if (ret == 0) 863 mvm->tof_data.range_req.initiator = value; 864 goto out; 865 } 866 867 data = iwl_dbgfs_is_match("one_sided_los_disable=", buf); 868 if (data) { 869 ret = kstrtou32(data, 10, &value); 870 if (ret == 0) 871 mvm->tof_data.range_req.one_sided_los_disable = value; 872 goto out; 873 } 874 875 data = iwl_dbgfs_is_match("req_timeout=", buf); 876 if (data) { 877 ret = kstrtou32(data, 10, &value); 878 if (ret == 0) 879 mvm->tof_data.range_req.req_timeout = value; 880 goto out; 881 } 882 883 data = iwl_dbgfs_is_match("report_policy=", buf); 884 if (data) { 885 ret = kstrtou32(data, 10, &value); 886 if (ret == 0) 887 mvm->tof_data.range_req.report_policy = value; 888 goto out; 889 } 890 891 data = iwl_dbgfs_is_match("macaddr_random=", buf); 892 if (data) { 893 ret = kstrtou32(data, 10, &value); 894 if (ret == 0) 895 mvm->tof_data.range_req.macaddr_random = value; 896 goto out; 897 } 898 899 data = iwl_dbgfs_is_match("num_of_ap=", buf); 900 if (data) { 901 ret = kstrtou32(data, 10, &value); 902 if (ret == 0) 903 mvm->tof_data.range_req.num_of_ap = value; 904 goto out; 905 } 906 907 data = iwl_dbgfs_is_match("macaddr_template=", buf); 908 if (data) { 909 u8 mac[ETH_ALEN]; 910 911 if (!mac_pton(data, mac)) { 912 ret = -EINVAL; 913 goto out; 914 } 915 memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN); 916 goto out; 917 } 918 919 data = iwl_dbgfs_is_match("macaddr_mask=", buf); 920 if (data) { 921 u8 mac[ETH_ALEN]; 922 923 if (!mac_pton(data, mac)) { 924 ret = -EINVAL; 925 goto out; 926 } 927 memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN); 928 goto out; 929 } 930 931 data = iwl_dbgfs_is_match("ap=", buf); 932 if (data) { 933 struct iwl_tof_range_req_ap_entry ap = {}; 934 int size = sizeof(struct iwl_tof_range_req_ap_entry); 935 u16 burst_period; 936 u8 *mac = ap.bssid; 937 unsigned int i; 938 939 if (sscanf(data, "%u %hhd %hhd %hhd" 940 "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" 941 "%hhd %hhd %hd" 942 "%hhd %hhd %d" 943 "%hhx %hhd %hhd %hhd", 944 &i, &ap.channel_num, &ap.bandwidth, 945 &ap.ctrl_ch_position, 946 mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5, 947 &ap.measure_type, &ap.num_of_bursts, 948 &burst_period, 949 &ap.samples_per_burst, &ap.retries_per_sample, 950 &ap.tsf_delta, &ap.location_req, &ap.asap_mode, 951 &ap.enable_dyn_ack, &ap.rssi) != 20) { 952 ret = -EINVAL; 953 goto out; 954 } 955 if (i >= IWL_MVM_TOF_MAX_APS) { 956 IWL_ERR(mvm, "Invalid AP index %d\n", i); 957 ret = -EINVAL; 958 goto out; 959 } 960 961 ap.burst_period = cpu_to_le16(burst_period); 962 963 memcpy(&mvm->tof_data.range_req.ap[i], &ap, size); 964 goto out; 965 } 966 967 data = iwl_dbgfs_is_match("send_range_request=", buf); 968 if (data) { 969 ret = kstrtou32(data, 10, &value); 970 if (ret == 0 && value) 971 ret = iwl_mvm_tof_range_request_cmd(mvm, vif); 972 goto out; 973 } 974 975 ret = -EINVAL; 976 out: 977 mutex_unlock(&mvm->mutex); 978 return ret ?: count; 979 } 980 981 static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file, 982 char __user *user_buf, 983 size_t count, loff_t *ppos) 984 { 985 struct ieee80211_vif *vif = file->private_data; 986 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 987 struct iwl_mvm *mvm = mvmvif->mvm; 988 char buf[512]; 989 int pos = 0; 990 const size_t bufsz = sizeof(buf); 991 struct iwl_tof_range_req_cmd *cmd; 992 int i; 993 994 cmd = &mvm->tof_data.range_req; 995 996 mutex_lock(&mvm->mutex); 997 998 pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n", 999 cmd->request_id); 1000 pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n", 1001 cmd->initiator); 1002 pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n", 1003 cmd->one_sided_los_disable); 1004 pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n", 1005 cmd->req_timeout); 1006 pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n", 1007 cmd->report_policy); 1008 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n", 1009 cmd->macaddr_random); 1010 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n", 1011 cmd->macaddr_template); 1012 pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n", 1013 cmd->macaddr_mask); 1014 pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n", 1015 cmd->num_of_ap); 1016 for (i = 0; i < cmd->num_of_ap; i++) { 1017 struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i]; 1018 1019 pos += scnprintf(buf + pos, bufsz - pos, 1020 "ap %.2d: channel_num=%hhd bw=%hhd" 1021 " control=%hhd bssid=%pM type=%hhd" 1022 " num_of_bursts=%hhd burst_period=%hd ftm=%hhd" 1023 " retries=%hhd tsf_delta=%d" 1024 " tsf_delta_direction=%hhd location_req=0x%hhx " 1025 " asap=%hhd enable=%hhd rssi=%hhd\n", 1026 i, ap->channel_num, ap->bandwidth, 1027 ap->ctrl_ch_position, ap->bssid, 1028 ap->measure_type, ap->num_of_bursts, 1029 ap->burst_period, ap->samples_per_burst, 1030 ap->retries_per_sample, ap->tsf_delta, 1031 ap->tsf_delta_direction, 1032 ap->location_req, ap->asap_mode, 1033 ap->enable_dyn_ack, ap->rssi); 1034 } 1035 1036 mutex_unlock(&mvm->mutex); 1037 1038 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1039 } 1040 1041 static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif, 1042 char *buf, 1043 size_t count, loff_t *ppos) 1044 { 1045 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1046 struct iwl_mvm *mvm = mvmvif->mvm; 1047 u32 value; 1048 int ret = 0; 1049 char *data; 1050 1051 mutex_lock(&mvm->mutex); 1052 1053 data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf); 1054 if (data) { 1055 ret = kstrtou32(data, 10, &value); 1056 if (ret == 0) 1057 mvm->tof_data.range_req_ext.tsf_timer_offset_msec = 1058 cpu_to_le16(value); 1059 goto out; 1060 } 1061 1062 data = iwl_dbgfs_is_match("min_delta_ftm=", buf); 1063 if (data) { 1064 ret = kstrtou32(data, 10, &value); 1065 if (ret == 0) 1066 mvm->tof_data.range_req_ext.min_delta_ftm = value; 1067 goto out; 1068 } 1069 1070 data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf); 1071 if (data) { 1072 ret = kstrtou32(data, 10, &value); 1073 if (ret == 0) 1074 mvm->tof_data.range_req_ext.ftm_format_and_bw20M = 1075 value; 1076 goto out; 1077 } 1078 1079 data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf); 1080 if (data) { 1081 ret = kstrtou32(data, 10, &value); 1082 if (ret == 0) 1083 mvm->tof_data.range_req_ext.ftm_format_and_bw40M = 1084 value; 1085 goto out; 1086 } 1087 1088 data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf); 1089 if (data) { 1090 ret = kstrtou32(data, 10, &value); 1091 if (ret == 0) 1092 mvm->tof_data.range_req_ext.ftm_format_and_bw80M = 1093 value; 1094 goto out; 1095 } 1096 1097 data = iwl_dbgfs_is_match("send_range_req_ext=", buf); 1098 if (data) { 1099 ret = kstrtou32(data, 10, &value); 1100 if (ret == 0 && value) 1101 ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif); 1102 goto out; 1103 } 1104 1105 ret = -EINVAL; 1106 out: 1107 mutex_unlock(&mvm->mutex); 1108 return ret ?: count; 1109 } 1110 1111 static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file, 1112 char __user *user_buf, 1113 size_t count, loff_t *ppos) 1114 { 1115 struct ieee80211_vif *vif = file->private_data; 1116 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1117 struct iwl_mvm *mvm = mvmvif->mvm; 1118 char buf[256]; 1119 int pos = 0; 1120 const size_t bufsz = sizeof(buf); 1121 struct iwl_tof_range_req_ext_cmd *cmd; 1122 1123 cmd = &mvm->tof_data.range_req_ext; 1124 1125 mutex_lock(&mvm->mutex); 1126 1127 pos += scnprintf(buf + pos, bufsz - pos, 1128 "tsf_timer_offset_msec = %hd\n", 1129 cmd->tsf_timer_offset_msec); 1130 pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n", 1131 cmd->min_delta_ftm); 1132 pos += scnprintf(buf + pos, bufsz - pos, 1133 "ftm_format_and_bw20M = %hhd\n", 1134 cmd->ftm_format_and_bw20M); 1135 pos += scnprintf(buf + pos, bufsz - pos, 1136 "ftm_format_and_bw40M = %hhd\n", 1137 cmd->ftm_format_and_bw40M); 1138 pos += scnprintf(buf + pos, bufsz - pos, 1139 "ftm_format_and_bw80M = %hhd\n", 1140 cmd->ftm_format_and_bw80M); 1141 1142 mutex_unlock(&mvm->mutex); 1143 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1144 } 1145 1146 static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif, 1147 char *buf, 1148 size_t count, loff_t *ppos) 1149 { 1150 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1151 struct iwl_mvm *mvm = mvmvif->mvm; 1152 u32 value; 1153 int abort_id, ret = 0; 1154 char *data; 1155 1156 mutex_lock(&mvm->mutex); 1157 1158 data = iwl_dbgfs_is_match("abort_id=", buf); 1159 if (data) { 1160 ret = kstrtou32(data, 10, &value); 1161 if (ret == 0) 1162 mvm->tof_data.last_abort_id = value; 1163 goto out; 1164 } 1165 1166 data = iwl_dbgfs_is_match("send_range_abort=", buf); 1167 if (data) { 1168 ret = kstrtou32(data, 10, &value); 1169 if (ret == 0 && value) { 1170 abort_id = mvm->tof_data.last_abort_id; 1171 ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id); 1172 goto out; 1173 } 1174 } 1175 1176 out: 1177 mutex_unlock(&mvm->mutex); 1178 return ret ?: count; 1179 } 1180 1181 static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file, 1182 char __user *user_buf, 1183 size_t count, loff_t *ppos) 1184 { 1185 struct ieee80211_vif *vif = file->private_data; 1186 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1187 struct iwl_mvm *mvm = mvmvif->mvm; 1188 char buf[32]; 1189 int pos = 0; 1190 const size_t bufsz = sizeof(buf); 1191 int last_abort_id; 1192 1193 mutex_lock(&mvm->mutex); 1194 last_abort_id = mvm->tof_data.last_abort_id; 1195 mutex_unlock(&mvm->mutex); 1196 1197 pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n", 1198 last_abort_id); 1199 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1200 } 1201 1202 static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file, 1203 char __user *user_buf, 1204 size_t count, loff_t *ppos) 1205 { 1206 struct ieee80211_vif *vif = file->private_data; 1207 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1208 struct iwl_mvm *mvm = mvmvif->mvm; 1209 char *buf; 1210 int pos = 0; 1211 const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256; 1212 struct iwl_tof_range_rsp_ntfy *cmd; 1213 int i, ret; 1214 1215 buf = kzalloc(bufsz, GFP_KERNEL); 1216 if (!buf) 1217 return -ENOMEM; 1218 1219 mutex_lock(&mvm->mutex); 1220 cmd = &mvm->tof_data.range_resp; 1221 1222 pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n", 1223 cmd->request_id); 1224 pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n", 1225 cmd->request_status); 1226 pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n", 1227 cmd->last_in_batch); 1228 pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n", 1229 cmd->num_of_aps); 1230 for (i = 0; i < cmd->num_of_aps; i++) { 1231 struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i]; 1232 1233 pos += scnprintf(buf + pos, bufsz - pos, 1234 "ap %.2d: bssid=%pM status=%hhd bw=%hhd" 1235 " rtt=%d rtt_var=%d rtt_spread=%d" 1236 " rssi=%hhd rssi_spread=%hhd" 1237 " range=%d range_var=%d" 1238 " time_stamp=%d\n", 1239 i, ap->bssid, ap->measure_status, 1240 ap->measure_bw, 1241 ap->rtt, ap->rtt_variance, ap->rtt_spread, 1242 ap->rssi, ap->rssi_spread, ap->range, 1243 ap->range_variance, ap->timestamp); 1244 } 1245 mutex_unlock(&mvm->mutex); 1246 1247 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1248 kfree(buf); 1249 return ret; 1250 } 1251 1252 static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, 1253 size_t count, loff_t *ppos) 1254 { 1255 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1256 struct iwl_mvm *mvm = mvmvif->mvm; 1257 bool prev; 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 prev = iwl_mvm_vif_low_latency(mvmvif); 1269 mvmvif->low_latency_dbgfs = value; 1270 iwl_mvm_update_low_latency(mvm, vif, prev); 1271 mutex_unlock(&mvm->mutex); 1272 1273 return count; 1274 } 1275 1276 static ssize_t iwl_dbgfs_low_latency_read(struct file *file, 1277 char __user *user_buf, 1278 size_t count, loff_t *ppos) 1279 { 1280 struct ieee80211_vif *vif = file->private_data; 1281 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1282 char buf[30] = {}; 1283 int len; 1284 1285 len = snprintf(buf, sizeof(buf) - 1, 1286 "traffic=%d\ndbgfs=%d\nvcmd=%d\n", 1287 mvmvif->low_latency_traffic, 1288 mvmvif->low_latency_dbgfs, 1289 mvmvif->low_latency_vcmd); 1290 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1291 } 1292 1293 static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file, 1294 char __user *user_buf, 1295 size_t count, loff_t *ppos) 1296 { 1297 struct ieee80211_vif *vif = file->private_data; 1298 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1299 char buf[20]; 1300 int len; 1301 1302 len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid); 1303 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1304 } 1305 1306 static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif, 1307 char *buf, size_t count, 1308 loff_t *ppos) 1309 { 1310 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1311 struct iwl_mvm *mvm = mvmvif->mvm; 1312 bool ret; 1313 1314 mutex_lock(&mvm->mutex); 1315 ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid); 1316 mutex_unlock(&mvm->mutex); 1317 1318 return ret ? count : -EINVAL; 1319 } 1320 1321 static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, 1322 size_t count, loff_t *ppos) 1323 { 1324 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1325 struct iwl_mvm *mvm = mvmvif->mvm; 1326 struct ieee80211_chanctx_conf *chanctx_conf; 1327 struct iwl_mvm_phy_ctxt *phy_ctxt; 1328 u16 value; 1329 int ret; 1330 1331 ret = kstrtou16(buf, 0, &value); 1332 if (ret) 1333 return ret; 1334 1335 mutex_lock(&mvm->mutex); 1336 rcu_read_lock(); 1337 1338 chanctx_conf = rcu_dereference(vif->chanctx_conf); 1339 /* make sure the channel context is assigned */ 1340 if (!chanctx_conf) { 1341 rcu_read_unlock(); 1342 mutex_unlock(&mvm->mutex); 1343 return -EINVAL; 1344 } 1345 1346 phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv]; 1347 rcu_read_unlock(); 1348 1349 mvm->dbgfs_rx_phyinfo = value; 1350 1351 ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def, 1352 chanctx_conf->rx_chains_static, 1353 chanctx_conf->rx_chains_dynamic); 1354 mutex_unlock(&mvm->mutex); 1355 1356 return ret ?: count; 1357 } 1358 1359 static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file, 1360 char __user *user_buf, 1361 size_t count, loff_t *ppos) 1362 { 1363 struct ieee80211_vif *vif = file->private_data; 1364 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1365 char buf[8]; 1366 1367 snprintf(buf, sizeof(buf), "0x%04x\n", mvmvif->mvm->dbgfs_rx_phyinfo); 1368 1369 return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); 1370 } 1371 1372 static void iwl_dbgfs_quota_check(void *data, u8 *mac, 1373 struct ieee80211_vif *vif) 1374 { 1375 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1376 int *ret = data; 1377 1378 if (mvmvif->dbgfs_quota_min) 1379 *ret = -EINVAL; 1380 } 1381 1382 static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf, 1383 size_t count, loff_t *ppos) 1384 { 1385 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1386 struct iwl_mvm *mvm = mvmvif->mvm; 1387 u16 value; 1388 int ret; 1389 1390 ret = kstrtou16(buf, 0, &value); 1391 if (ret) 1392 return ret; 1393 1394 if (value > 95) 1395 return -EINVAL; 1396 1397 mutex_lock(&mvm->mutex); 1398 1399 mvmvif->dbgfs_quota_min = 0; 1400 ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 1401 iwl_dbgfs_quota_check, &ret); 1402 if (ret == 0) { 1403 mvmvif->dbgfs_quota_min = value; 1404 iwl_mvm_update_quotas(mvm, false, NULL); 1405 } 1406 mutex_unlock(&mvm->mutex); 1407 1408 return ret ?: count; 1409 } 1410 1411 static ssize_t iwl_dbgfs_quota_min_read(struct file *file, 1412 char __user *user_buf, 1413 size_t count, loff_t *ppos) 1414 { 1415 struct ieee80211_vif *vif = file->private_data; 1416 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1417 char buf[10]; 1418 int len; 1419 1420 len = snprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min); 1421 1422 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1423 } 1424 1425 static const char * const chanwidths[] = { 1426 [NL80211_CHAN_WIDTH_20_NOHT] = "noht", 1427 [NL80211_CHAN_WIDTH_20] = "ht20", 1428 [NL80211_CHAN_WIDTH_40] = "ht40", 1429 [NL80211_CHAN_WIDTH_80] = "vht80", 1430 [NL80211_CHAN_WIDTH_80P80] = "vht80p80", 1431 [NL80211_CHAN_WIDTH_160] = "vht160", 1432 }; 1433 1434 static bool iwl_mvm_lqm_notif_wait(struct iwl_notif_wait_data *notif_wait, 1435 struct iwl_rx_packet *pkt, void *data) 1436 { 1437 struct ieee80211_vif *vif = data; 1438 struct iwl_mvm *mvm = 1439 container_of(notif_wait, struct iwl_mvm, notif_wait); 1440 struct iwl_link_qual_msrmnt_notif *report = (void *)pkt->data; 1441 u32 num_of_stations = le32_to_cpu(report->number_of_stations); 1442 int i; 1443 1444 IWL_INFO(mvm, "LQM report:\n"); 1445 IWL_INFO(mvm, "\tstatus: %d\n", report->status); 1446 IWL_INFO(mvm, "\tmacID: %d\n", le32_to_cpu(report->mac_id)); 1447 IWL_INFO(mvm, "\ttx_frame_dropped: %d\n", 1448 le32_to_cpu(report->tx_frame_dropped)); 1449 IWL_INFO(mvm, "\ttime_in_measurement_window: %d us\n", 1450 le32_to_cpu(report->time_in_measurement_window)); 1451 IWL_INFO(mvm, "\ttotal_air_time_other_stations: %d\n", 1452 le32_to_cpu(report->total_air_time_other_stations)); 1453 IWL_INFO(mvm, "\tchannel_freq: %d\n", 1454 vif->bss_conf.chandef.center_freq1); 1455 IWL_INFO(mvm, "\tchannel_width: %s\n", 1456 chanwidths[vif->bss_conf.chandef.width]); 1457 IWL_INFO(mvm, "\tnumber_of_stations: %d\n", num_of_stations); 1458 for (i = 0; i < num_of_stations; i++) 1459 IWL_INFO(mvm, "\t\tsta[%d]: %d\n", i, 1460 report->frequent_stations_air_time[i]); 1461 1462 return true; 1463 } 1464 1465 static ssize_t iwl_dbgfs_lqm_send_cmd_write(struct ieee80211_vif *vif, 1466 char *buf, size_t count, 1467 loff_t *ppos) 1468 { 1469 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1470 struct iwl_mvm *mvm = mvmvif->mvm; 1471 struct iwl_notification_wait wait_lqm_notif; 1472 static u16 lqm_notif[] = { 1473 WIDE_ID(MAC_CONF_GROUP, 1474 LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF) 1475 }; 1476 int err; 1477 u32 duration; 1478 u32 timeout; 1479 1480 if (sscanf(buf, "%d,%d", &duration, &timeout) != 2) 1481 return -EINVAL; 1482 1483 iwl_init_notification_wait(&mvm->notif_wait, &wait_lqm_notif, 1484 lqm_notif, ARRAY_SIZE(lqm_notif), 1485 iwl_mvm_lqm_notif_wait, vif); 1486 mutex_lock(&mvm->mutex); 1487 err = iwl_mvm_send_lqm_cmd(vif, LQM_CMD_OPERATION_START_MEASUREMENT, 1488 duration, timeout); 1489 mutex_unlock(&mvm->mutex); 1490 1491 if (err) { 1492 IWL_ERR(mvm, "Failed to send lqm cmdf(err=%d)\n", err); 1493 iwl_remove_notification(&mvm->notif_wait, &wait_lqm_notif); 1494 return err; 1495 } 1496 1497 /* wait for 2 * timeout (safety guard) and convert to jiffies*/ 1498 timeout = msecs_to_jiffies((timeout * 2) / 1000); 1499 1500 err = iwl_wait_notification(&mvm->notif_wait, &wait_lqm_notif, 1501 timeout); 1502 if (err) 1503 IWL_ERR(mvm, "Getting lqm notif timed out\n"); 1504 1505 return count; 1506 } 1507 1508 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ 1509 _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) 1510 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ 1511 _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) 1512 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ 1513 if (!debugfs_create_file(#name, mode, parent, vif, \ 1514 &iwl_dbgfs_##name##_ops)) \ 1515 goto err; \ 1516 } while (0) 1517 1518 MVM_DEBUGFS_READ_FILE_OPS(mac_params); 1519 MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt); 1520 MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); 1521 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); 1522 MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); 1523 MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); 1524 MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); 1525 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32); 1526 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512); 1527 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32); 1528 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32); 1529 MVM_DEBUGFS_READ_FILE_OPS(tof_range_response); 1530 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32); 1531 MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); 1532 MVM_DEBUGFS_WRITE_FILE_OPS(lqm_send_cmd, 64); 1533 1534 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 1535 { 1536 struct dentry *dbgfs_dir = vif->debugfs_dir; 1537 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1538 char buf[100]; 1539 1540 /* 1541 * Check if debugfs directory already exist before creating it. 1542 * This may happen when, for example, resetting hw or suspend-resume 1543 */ 1544 if (!dbgfs_dir || mvmvif->dbgfs_dir) 1545 return; 1546 1547 mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); 1548 1549 if (!mvmvif->dbgfs_dir) { 1550 IWL_ERR(mvm, "Failed to create debugfs directory under %s\n", 1551 dbgfs_dir->d_name.name); 1552 return; 1553 } 1554 1555 if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && 1556 ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || 1557 (vif->type == NL80211_IFTYPE_STATION && vif->p2p && 1558 mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))) 1559 MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | 1560 S_IRUSR); 1561 1562 MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR); 1563 MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR); 1564 MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 1565 S_IRUSR | S_IWUSR); 1566 MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 1567 S_IRUSR | S_IWUSR); 1568 MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 1569 S_IRUSR | S_IWUSR); 1570 MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 1571 S_IRUSR | S_IWUSR); 1572 MVM_DEBUGFS_ADD_FILE_VIF(lqm_send_cmd, mvmvif->dbgfs_dir, S_IWUSR); 1573 1574 if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && 1575 mvmvif == mvm->bf_allowed_vif) 1576 MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 1577 S_IRUSR | S_IWUSR); 1578 1579 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) && 1580 !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) { 1581 if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP) 1582 MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params, 1583 mvmvif->dbgfs_dir, 1584 S_IRUSR | S_IWUSR); 1585 1586 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir, 1587 S_IRUSR | S_IWUSR); 1588 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir, 1589 S_IRUSR | S_IWUSR); 1590 MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir, 1591 S_IRUSR | S_IWUSR); 1592 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir, 1593 S_IRUSR | S_IWUSR); 1594 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir, 1595 S_IRUSR); 1596 } 1597 1598 /* 1599 * Create symlink for convenience pointing to interface specific 1600 * debugfs entries for the driver. For example, under 1601 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/ 1602 * find 1603 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ 1604 */ 1605 snprintf(buf, 100, "../../../%s/%s/%s/%s", 1606 dbgfs_dir->d_parent->d_parent->d_name.name, 1607 dbgfs_dir->d_parent->d_name.name, 1608 dbgfs_dir->d_name.name, 1609 mvmvif->dbgfs_dir->d_name.name); 1610 1611 mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, 1612 mvm->debugfs_dir, buf); 1613 if (!mvmvif->dbgfs_slink) 1614 IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n", 1615 dbgfs_dir->d_name.name); 1616 return; 1617 err: 1618 IWL_ERR(mvm, "Can't create debugfs entity\n"); 1619 } 1620 1621 void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 1622 { 1623 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1624 1625 debugfs_remove(mvmvif->dbgfs_slink); 1626 mvmvif->dbgfs_slink = NULL; 1627 1628 debugfs_remove_recursive(mvmvif->dbgfs_dir); 1629 mvmvif->dbgfs_dir = NULL; 1630 } 1631