1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright (C) 2024-2025 Intel Corporation 4 */ 5 6 #include "mld.h" 7 #include "debugfs.h" 8 #include "iwl-io.h" 9 #include "hcmd.h" 10 #include "iface.h" 11 #include "sta.h" 12 #include "tlc.h" 13 #include "power.h" 14 #include "notif.h" 15 #include "ap.h" 16 #include "iwl-utils.h" 17 #include "scan.h" 18 #ifdef CONFIG_THERMAL 19 #include "thermal.h" 20 #endif 21 22 #include "fw/api/rs.h" 23 #include "fw/api/dhc.h" 24 #include "fw/api/rfi.h" 25 #include "fw/dhc-utils.h" 26 #include <linux/dmi.h> 27 28 #define MLD_DEBUGFS_READ_FILE_OPS(name, bufsz) \ 29 _MLD_DEBUGFS_READ_FILE_OPS(name, bufsz, struct iwl_mld) 30 31 #define MLD_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) \ 32 debugfs_create_file(alias, mode, parent, mld, \ 33 &iwl_dbgfs_##name##_ops) 34 #define MLD_DEBUGFS_ADD_FILE(name, parent, mode) \ 35 MLD_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) 36 37 static bool iwl_mld_dbgfs_fw_cmd_disabled(struct iwl_mld *mld) 38 { 39 #ifdef CONFIG_PM_SLEEP 40 return !mld->fw_status.running || mld->fw_status.in_d3; 41 #else 42 return !mld->fw_status.running; 43 #endif /* CONFIG_PM_SLEEP */ 44 } 45 46 static ssize_t iwl_dbgfs_fw_dbg_clear_write(struct iwl_mld *mld, 47 char *buf, size_t count) 48 { 49 /* If the firmware is not running, silently succeed since there is 50 * no data to clear. 51 */ 52 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 53 return 0; 54 55 iwl_fw_dbg_clear_monitor_buf(&mld->fwrt); 56 57 return count; 58 } 59 60 static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mld *mld, char *buf, 61 size_t count) 62 { 63 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 64 return -EIO; 65 66 IWL_ERR(mld, "Triggering an NMI from debugfs\n"); 67 68 if (count == 6 && !strcmp(buf, "nolog\n")) 69 mld->fw_status.do_not_dump_once = true; 70 71 iwl_force_nmi(mld->trans); 72 73 return count; 74 } 75 76 static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mld *mld, char *buf, 77 size_t count) 78 { 79 int __maybe_unused ret; 80 81 if (!iwlwifi_mod_params.fw_restart) 82 return -EPERM; 83 84 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 85 return -EIO; 86 87 if (count == 6 && !strcmp(buf, "nolog\n")) { 88 mld->fw_status.do_not_dump_once = true; 89 set_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, &mld->trans->status); 90 } 91 92 /* take the return value to make compiler happy - it will 93 * fail anyway 94 */ 95 ret = iwl_mld_send_cmd_empty(mld, WIDE_ID(LONG_GROUP, REPLY_ERROR)); 96 97 return count; 98 } 99 100 static ssize_t iwl_dbgfs_send_echo_cmd_write(struct iwl_mld *mld, char *buf, 101 size_t count) 102 { 103 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 104 return -EIO; 105 106 return iwl_mld_send_cmd_empty(mld, ECHO_CMD) ?: count; 107 } 108 109 struct iwl_mld_sniffer_apply { 110 struct iwl_mld *mld; 111 const u8 *bssid; 112 u16 aid; 113 }; 114 115 static bool iwl_mld_sniffer_apply(struct iwl_notif_wait_data *notif_data, 116 struct iwl_rx_packet *pkt, void *data) 117 { 118 struct iwl_mld_sniffer_apply *apply = data; 119 120 apply->mld->monitor.cur_aid = cpu_to_le16(apply->aid); 121 memcpy(apply->mld->monitor.cur_bssid, apply->bssid, 122 sizeof(apply->mld->monitor.cur_bssid)); 123 124 return true; 125 } 126 127 static ssize_t 128 iwl_dbgfs_he_sniffer_params_write(struct iwl_mld *mld, char *buf, 129 size_t count) 130 { 131 struct iwl_notification_wait wait; 132 struct iwl_he_monitor_cmd he_mon_cmd = {}; 133 struct iwl_mld_sniffer_apply apply = { 134 .mld = mld, 135 }; 136 u16 wait_cmds[] = { 137 WIDE_ID(DATA_PATH_GROUP, HE_AIR_SNIFFER_CONFIG_CMD), 138 }; 139 u32 aid; 140 int ret; 141 142 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 143 return -EIO; 144 145 if (!mld->monitor.on) 146 return -ENODEV; 147 148 ret = sscanf(buf, "%x %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", &aid, 149 &he_mon_cmd.bssid[0], &he_mon_cmd.bssid[1], 150 &he_mon_cmd.bssid[2], &he_mon_cmd.bssid[3], 151 &he_mon_cmd.bssid[4], &he_mon_cmd.bssid[5]); 152 if (ret != 7) 153 return -EINVAL; 154 155 he_mon_cmd.aid = cpu_to_le16(aid); 156 157 apply.aid = aid; 158 apply.bssid = (void *)he_mon_cmd.bssid; 159 160 /* Use the notification waiter to get our function triggered 161 * in sequence with other RX. This ensures that frames we get 162 * on the RX queue _before_ the new configuration is applied 163 * still have mld->cur_aid pointing to the old AID, and that 164 * frames on the RX queue _after_ the firmware processed the 165 * new configuration (and sent the response, synchronously) 166 * get mld->cur_aid correctly set to the new AID. 167 */ 168 iwl_init_notification_wait(&mld->notif_wait, &wait, 169 wait_cmds, ARRAY_SIZE(wait_cmds), 170 iwl_mld_sniffer_apply, &apply); 171 172 ret = iwl_mld_send_cmd_pdu(mld, 173 WIDE_ID(DATA_PATH_GROUP, 174 HE_AIR_SNIFFER_CONFIG_CMD), 175 &he_mon_cmd); 176 177 /* no need to really wait, we already did anyway */ 178 iwl_remove_notification(&mld->notif_wait, &wait); 179 180 return ret ?: count; 181 } 182 183 static ssize_t 184 iwl_dbgfs_he_sniffer_params_read(struct iwl_mld *mld, char *buf, size_t count) 185 { 186 return scnprintf(buf, count, 187 "%d %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", 188 le16_to_cpu(mld->monitor.cur_aid), 189 mld->monitor.cur_bssid[0], mld->monitor.cur_bssid[1], 190 mld->monitor.cur_bssid[2], mld->monitor.cur_bssid[3], 191 mld->monitor.cur_bssid[4], mld->monitor.cur_bssid[5]); 192 } 193 194 /* The size computation is as follows: 195 * each number needs at most 3 characters, number of rows is the size of 196 * the table; So, need 5 chars for the "freq: " part and each tuple afterwards 197 * needs 6 characters for numbers and 5 for the punctuation around. 32 bytes 198 * for feature support message. 199 */ 200 #define IWL_RFI_DDR_BUF_SIZE (IWL_RFI_DDR_LUT_INSTALLED_SIZE *\ 201 (5 + IWL_RFI_DDR_LUT_ENTRY_CHANNELS_NUM *\ 202 (6 + 5)) + 32) 203 #define IWL_RFI_DLVR_BUF_SIZE (IWL_RFI_DLVR_LUT_INSTALLED_SIZE *\ 204 (5 + IWL_RFI_DLVR_LUT_ENTRY_CHANNELS_NUM *\ 205 (6 + 5)) + 32) 206 #define IWL_RFI_DESENSE_BUF_SIZE IWL_RFI_DDR_BUF_SIZE 207 208 /* Extra 32 for "DDR and DLVR table" message */ 209 #define IWL_RFI_BUF_SIZE (IWL_RFI_DDR_BUF_SIZE + IWL_RFI_DLVR_BUF_SIZE +\ 210 IWL_RFI_DESENSE_BUF_SIZE + 32) 211 212 static size_t iwl_mld_dump_tas_resp(struct iwl_dhc_tas_status_resp *resp, 213 size_t count, u8 *buf) 214 { 215 const char * const tas_dis_reason[TAS_DISABLED_REASON_MAX] = { 216 [TAS_DISABLED_DUE_TO_BIOS] = 217 "Due To BIOS", 218 [TAS_DISABLED_DUE_TO_SAR_6DBM] = 219 "Due To SAR Limit Less Than 6 dBm", 220 [TAS_DISABLED_REASON_INVALID] = 221 "N/A", 222 [TAS_DISABLED_DUE_TO_TABLE_SOURCE_INVALID] = 223 "Due to table source invalid" 224 }; 225 const char * const tas_current_status[TAS_DYNA_STATUS_MAX] = { 226 [TAS_DYNA_INACTIVE] = "INACTIVE", 227 [TAS_DYNA_INACTIVE_MVM_MODE] = 228 "inactive due to mvm mode", 229 [TAS_DYNA_INACTIVE_TRIGGER_MODE] = 230 "inactive due to trigger mode", 231 [TAS_DYNA_INACTIVE_BLOCK_LISTED] = 232 "inactive due to block listed", 233 [TAS_DYNA_INACTIVE_UHB_NON_US] = 234 "inactive due to uhb non US", 235 [TAS_DYNA_ACTIVE] = "ACTIVE", 236 }; 237 ssize_t pos = 0; 238 239 if (resp->header.version != 1) { 240 pos += scnprintf(buf + pos, count - pos, 241 "Unsupported TAS response version:%d", 242 resp->header.version); 243 return pos; 244 } 245 246 pos += scnprintf(buf + pos, count - pos, "TAS Report\n"); 247 switch (resp->tas_config_info.table_source) { 248 case BIOS_SOURCE_NONE: 249 pos += scnprintf(buf + pos, count - pos, 250 "BIOS SOURCE NONE "); 251 break; 252 case BIOS_SOURCE_ACPI: 253 pos += scnprintf(buf + pos, count - pos, 254 "BIOS SOURCE ACPI "); 255 break; 256 case BIOS_SOURCE_UEFI: 257 pos += scnprintf(buf + pos, count - pos, 258 "BIOS SOURCE UEFI "); 259 break; 260 default: 261 pos += scnprintf(buf + pos, count - pos, 262 "BIOS SOURCE UNKNOWN (%d) ", 263 resp->tas_config_info.table_source); 264 break; 265 } 266 267 pos += scnprintf(buf + pos, count - pos, 268 "revision is: %d data is: 0x%08x\n", 269 resp->tas_config_info.table_revision, 270 resp->tas_config_info.value); 271 pos += scnprintf(buf + pos, count - pos, "Current MCC: 0x%x\n", 272 le16_to_cpu(resp->curr_mcc)); 273 274 pos += scnprintf(buf + pos, count - pos, "Block list entries:"); 275 for (int i = 0; i < ARRAY_SIZE(resp->mcc_block_list); i++) 276 pos += scnprintf(buf + pos, count - pos, " 0x%x", 277 le16_to_cpu(resp->mcc_block_list[i])); 278 279 pos += scnprintf(buf + pos, count - pos, 280 "\nDo TAS Support Dual Radio?: %s\n", 281 hweight8(resp->valid_radio_mask) > 1 ? 282 "TRUE" : "FALSE"); 283 284 for (int i = 0; i < ARRAY_SIZE(resp->tas_status_radio); i++) { 285 int tmp; 286 unsigned long dynamic_status; 287 288 if (!(resp->valid_radio_mask & BIT(i))) 289 continue; 290 291 pos += scnprintf(buf + pos, count - pos, 292 "TAS report for radio:%d\n", i + 1); 293 pos += scnprintf(buf + pos, count - pos, 294 "Static status: %sabled\n", 295 resp->tas_status_radio[i].static_status ? 296 "En" : "Dis"); 297 if (!resp->tas_status_radio[i].static_status) { 298 u8 static_disable_reason = 299 resp->tas_status_radio[i].static_disable_reason; 300 301 pos += scnprintf(buf + pos, count - pos, 302 "\tStatic Disabled Reason: "); 303 if (static_disable_reason >= TAS_DISABLED_REASON_MAX) { 304 pos += scnprintf(buf + pos, count - pos, 305 "unsupported value (%d)\n", 306 static_disable_reason); 307 continue; 308 } 309 310 pos += scnprintf(buf + pos, count - pos, 311 "%s (%d)\n", 312 tas_dis_reason[static_disable_reason], 313 static_disable_reason); 314 continue; 315 } 316 317 pos += scnprintf(buf + pos, count - pos, "\tANT A %s and ", 318 (resp->tas_status_radio[i].dynamic_status_ant_a 319 & BIT(TAS_DYNA_ACTIVE)) ? "ON" : "OFF"); 320 321 pos += scnprintf(buf + pos, count - pos, "ANT B %s for ", 322 (resp->tas_status_radio[i].dynamic_status_ant_b 323 & BIT(TAS_DYNA_ACTIVE)) ? "ON" : "OFF"); 324 325 switch (resp->tas_status_radio[i].band) { 326 case PHY_BAND_5: 327 pos += scnprintf(buf + pos, count - pos, "HB\n"); 328 break; 329 case PHY_BAND_24: 330 pos += scnprintf(buf + pos, count - pos, "LB\n"); 331 break; 332 case PHY_BAND_6: 333 pos += scnprintf(buf + pos, count - pos, "UHB\n"); 334 break; 335 default: 336 pos += scnprintf(buf + pos, count - pos, 337 "Unsupported band (%d)\n", 338 resp->tas_status_radio[i].band); 339 break; 340 } 341 342 pos += scnprintf(buf + pos, count - pos, 343 "Is near disconnection?: %s\n", 344 resp->tas_status_radio[i].near_disconnection ? 345 "True" : "False"); 346 347 pos += scnprintf(buf + pos, count - pos, 348 "Dynamic status antenna A:\n"); 349 dynamic_status = resp->tas_status_radio[i].dynamic_status_ant_a; 350 for_each_set_bit(tmp, &dynamic_status, TAS_DYNA_STATUS_MAX) { 351 pos += scnprintf(buf + pos, count - pos, "\t%s (%d)\n", 352 tas_current_status[tmp], tmp); 353 } 354 pos += scnprintf(buf + pos, count - pos, 355 "\nDynamic status antenna B:\n"); 356 dynamic_status = resp->tas_status_radio[i].dynamic_status_ant_b; 357 for_each_set_bit(tmp, &dynamic_status, TAS_DYNA_STATUS_MAX) { 358 pos += scnprintf(buf + pos, count - pos, "\t%s (%d)\n", 359 tas_current_status[tmp], tmp); 360 } 361 362 tmp = le16_to_cpu(resp->tas_status_radio[i].max_reg_pwr_limit_ant_a); 363 pos += scnprintf(buf + pos, count - pos, 364 "Max antenna A regulatory pwr limit (dBm): %d.%03d\n", 365 tmp / 8, 125 * (tmp % 8)); 366 tmp = le16_to_cpu(resp->tas_status_radio[i].max_reg_pwr_limit_ant_b); 367 pos += scnprintf(buf + pos, count - pos, 368 "Max antenna B regulatory pwr limit (dBm): %d.%03d\n", 369 tmp / 8, 125 * (tmp % 8)); 370 371 tmp = le16_to_cpu(resp->tas_status_radio[i].sar_limit_ant_a); 372 pos += scnprintf(buf + pos, count - pos, 373 "Antenna A SAR limit (dBm): %d.%03d\n", 374 tmp / 8, 125 * (tmp % 8)); 375 tmp = le16_to_cpu(resp->tas_status_radio[i].sar_limit_ant_b); 376 pos += scnprintf(buf + pos, count - pos, 377 "Antenna B SAR limit (dBm): %d.%03d\n", 378 tmp / 8, 125 * (tmp % 8)); 379 } 380 381 return pos; 382 } 383 384 static ssize_t iwl_dbgfs_tas_get_status_read(struct iwl_mld *mld, char *buf, 385 size_t count) 386 { 387 struct iwl_dhc_cmd cmd = { 388 .index_and_mask = cpu_to_le32(DHC_TABLE_TOOLS | 389 DHC_TARGET_UMAC | 390 DHC_TOOLS_UMAC_GET_TAS_STATUS), 391 }; 392 struct iwl_host_cmd hcmd = { 393 .id = WIDE_ID(LEGACY_GROUP, DEBUG_HOST_COMMAND), 394 .flags = CMD_WANT_SKB, 395 .len[0] = sizeof(cmd), 396 .data[0] = &cmd, 397 }; 398 struct iwl_dhc_tas_status_resp *resp = NULL; 399 u32 resp_len = 0; 400 ssize_t pos = 0; 401 u32 status; 402 int ret; 403 404 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 405 return -EIO; 406 407 ret = iwl_mld_send_cmd(mld, &hcmd); 408 if (ret) 409 return ret; 410 411 pos += scnprintf(buf + pos, count - pos, "\nOEM name: %s\n", 412 dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>"); 413 pos += scnprintf(buf + pos, count - pos, 414 "\tVendor In Approved List: %s\n", 415 iwl_is_tas_approved() ? "YES" : "NO"); 416 417 status = iwl_dhc_resp_status(mld->fwrt.fw, hcmd.resp_pkt); 418 if (status != 1) { 419 pos += scnprintf(buf + pos, count - pos, 420 "response status is not success: %d\n", 421 status); 422 goto out; 423 } 424 425 resp = iwl_dhc_resp_data(mld->fwrt.fw, hcmd.resp_pkt, &resp_len); 426 if (IS_ERR(resp) || resp_len != sizeof(*resp)) { 427 pos += scnprintf(buf + pos, count - pos, 428 "Invalid size for TAS response (%u instead of %zd)\n", 429 resp_len, sizeof(*resp)); 430 goto out; 431 } 432 433 pos += iwl_mld_dump_tas_resp(resp, count - pos, buf + pos); 434 435 out: 436 iwl_free_resp(&hcmd); 437 return pos; 438 } 439 440 WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(fw_nmi, 10); 441 WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(fw_restart, 10); 442 WIPHY_DEBUGFS_READ_WRITE_FILE_OPS_MLD(he_sniffer_params, 32); 443 WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(fw_dbg_clear, 10); 444 WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(send_echo_cmd, 8); 445 WIPHY_DEBUGFS_READ_FILE_OPS_MLD(tas_get_status, 2048); 446 447 static ssize_t iwl_dbgfs_wifi_6e_enable_read(struct iwl_mld *mld, 448 size_t count, u8 *buf) 449 { 450 int err; 451 u32 value; 452 453 err = iwl_bios_get_dsm(&mld->fwrt, DSM_FUNC_ENABLE_6E, &value); 454 if (err) 455 return err; 456 457 return scnprintf(buf, count, "0x%08x\n", value); 458 } 459 460 MLD_DEBUGFS_READ_FILE_OPS(wifi_6e_enable, 64); 461 462 static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mld *mld, 463 char *buf, size_t count) 464 { 465 struct iwl_op_mode *opmode = container_of((void *)mld, 466 struct iwl_op_mode, 467 op_mode_specific); 468 struct iwl_rx_cmd_buffer rxb = {}; 469 struct iwl_rx_packet *pkt; 470 int n_bytes = count / 2; 471 int ret = -EINVAL; 472 473 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 474 return -EIO; 475 476 rxb._page = alloc_pages(GFP_KERNEL, 0); 477 if (!rxb._page) 478 return -ENOMEM; 479 pkt = rxb_addr(&rxb); 480 481 ret = hex2bin(page_address(rxb._page), buf, n_bytes); 482 if (ret) 483 goto out; 484 485 /* avoid invalid memory access and malformed packet */ 486 if (n_bytes < sizeof(*pkt) || 487 n_bytes != sizeof(*pkt) + iwl_rx_packet_payload_len(pkt)) 488 goto out; 489 490 local_bh_disable(); 491 iwl_mld_rx(opmode, NULL, &rxb); 492 local_bh_enable(); 493 ret = 0; 494 495 out: 496 iwl_free_rxb(&rxb); 497 498 return ret ?: count; 499 } 500 501 WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(inject_packet, 512); 502 503 #ifdef CONFIG_THERMAL 504 505 static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mld *mld, 506 char *buf, size_t count) 507 { 508 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 509 return -EIO; 510 511 return iwl_mld_config_ctdp(mld, mld->cooling_dev.cur_state, 512 CTDP_CMD_OPERATION_STOP) ? : count; 513 } 514 515 WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(stop_ctdp, 8); 516 517 static ssize_t iwl_dbgfs_start_ctdp_write(struct iwl_mld *mld, 518 char *buf, size_t count) 519 { 520 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 521 return -EIO; 522 523 return iwl_mld_config_ctdp(mld, mld->cooling_dev.cur_state, 524 CTDP_CMD_OPERATION_START) ? : count; 525 } 526 527 WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(start_ctdp, 8); 528 529 #endif /* CONFIG_THERMAL */ 530 531 void 532 iwl_mld_add_debugfs_files(struct iwl_mld *mld, struct dentry *debugfs_dir) 533 { 534 /* Add debugfs files here */ 535 536 MLD_DEBUGFS_ADD_FILE(fw_nmi, debugfs_dir, 0200); 537 MLD_DEBUGFS_ADD_FILE(fw_restart, debugfs_dir, 0200); 538 MLD_DEBUGFS_ADD_FILE(wifi_6e_enable, debugfs_dir, 0400); 539 MLD_DEBUGFS_ADD_FILE(he_sniffer_params, debugfs_dir, 0600); 540 MLD_DEBUGFS_ADD_FILE(fw_dbg_clear, debugfs_dir, 0200); 541 MLD_DEBUGFS_ADD_FILE(send_echo_cmd, debugfs_dir, 0200); 542 MLD_DEBUGFS_ADD_FILE(tas_get_status, debugfs_dir, 0400); 543 #ifdef CONFIG_THERMAL 544 MLD_DEBUGFS_ADD_FILE(start_ctdp, debugfs_dir, 0200); 545 MLD_DEBUGFS_ADD_FILE(stop_ctdp, debugfs_dir, 0200); 546 #endif 547 MLD_DEBUGFS_ADD_FILE(inject_packet, debugfs_dir, 0200); 548 549 #ifdef CONFIG_PM_SLEEP 550 debugfs_create_u32("max_sleep", 0600, debugfs_dir, 551 &mld->debug_max_sleep); 552 #endif 553 554 debugfs_create_bool("rx_ts_ptp", 0600, debugfs_dir, 555 &mld->monitor.ptp_time); 556 557 /* Create a symlink with mac80211. It will be removed when mac80211 558 * exits (before the opmode exits which removes the target.) 559 */ 560 if (!IS_ERR(debugfs_dir)) { 561 char buf[100]; 562 563 snprintf(buf, 100, "../../%pd2", debugfs_dir->d_parent); 564 debugfs_create_symlink("iwlwifi", mld->wiphy->debugfsdir, 565 buf); 566 } 567 } 568 569 #define VIF_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ 570 WIPHY_DEBUGFS_WRITE_FILE_OPS(vif_##name, bufsz, vif) 571 572 #define VIF_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ 573 IEEE80211_WIPHY_DEBUGFS_READ_WRITE_FILE_OPS(vif_##name, bufsz, vif) \ 574 575 #define VIF_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) \ 576 debugfs_create_file(alias, mode, parent, vif, \ 577 &iwl_dbgfs_vif_##name##_ops) 578 #define VIF_DEBUGFS_ADD_FILE(name, parent, mode) \ 579 VIF_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) 580 581 static ssize_t iwl_dbgfs_vif_bf_params_write(struct iwl_mld *mld, char *buf, 582 size_t count, void *data) 583 { 584 struct ieee80211_vif *vif = data; 585 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 586 int link_id = vif->active_links ? __ffs(vif->active_links) : 0; 587 struct ieee80211_bss_conf *link_conf; 588 int val; 589 590 if (!strncmp("bf_enable_beacon_filter=", buf, 24)) { 591 if (sscanf(buf + 24, "%d", &val) != 1) 592 return -EINVAL; 593 } else { 594 return -EINVAL; 595 } 596 597 if (val != 0 && val != 1) 598 return -EINVAL; 599 600 link_conf = link_conf_dereference_protected(vif, link_id); 601 if (WARN_ON(!link_conf)) 602 return -ENODEV; 603 604 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 605 return -EIO; 606 607 mld_vif->disable_bf = !val; 608 609 if (val) 610 return iwl_mld_enable_beacon_filter(mld, link_conf, 611 false) ?: count; 612 else 613 return iwl_mld_disable_beacon_filter(mld, vif) ?: count; 614 } 615 616 static ssize_t iwl_dbgfs_vif_pm_params_write(struct iwl_mld *mld, 617 char *buf, 618 size_t count, void *data) 619 { 620 struct ieee80211_vif *vif = data; 621 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 622 int val; 623 624 if (!strncmp("use_ps_poll=", buf, 12)) { 625 if (sscanf(buf + 12, "%d", &val) != 1) 626 return -EINVAL; 627 } else { 628 return -EINVAL; 629 } 630 631 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 632 return -EIO; 633 634 mld_vif->use_ps_poll = val; 635 636 return iwl_mld_update_mac_power(mld, vif, false) ?: count; 637 } 638 639 static ssize_t iwl_dbgfs_vif_low_latency_write(struct iwl_mld *mld, 640 char *buf, size_t count, 641 void *data) 642 { 643 struct ieee80211_vif *vif = data; 644 u8 value; 645 int ret; 646 647 ret = kstrtou8(buf, 0, &value); 648 if (ret) 649 return ret; 650 651 if (value > 1) 652 return -EINVAL; 653 654 iwl_mld_vif_update_low_latency(mld, vif, value, LOW_LATENCY_DEBUGFS); 655 656 return count; 657 } 658 659 static ssize_t iwl_dbgfs_vif_low_latency_read(struct ieee80211_vif *vif, 660 size_t count, char *buf) 661 { 662 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 663 char format[] = "traffic=%d\ndbgfs=%d\nvif_type=%d\nactual=%d\n"; 664 u8 ll_causes; 665 666 if (WARN_ON(count < sizeof(format))) 667 return -EINVAL; 668 669 ll_causes = READ_ONCE(mld_vif->low_latency_causes); 670 671 /* all values in format are boolean so the size of format is enough 672 * for holding the result string 673 */ 674 return scnprintf(buf, count, format, 675 !!(ll_causes & LOW_LATENCY_TRAFFIC), 676 !!(ll_causes & LOW_LATENCY_DEBUGFS), 677 !!(ll_causes & LOW_LATENCY_VIF_TYPE), 678 !!(ll_causes)); 679 } 680 681 VIF_DEBUGFS_WRITE_FILE_OPS(pm_params, 32); 682 VIF_DEBUGFS_WRITE_FILE_OPS(bf_params, 32); 683 VIF_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 45); 684 685 static int 686 _iwl_dbgfs_inject_beacon_ie(struct iwl_mld *mld, struct ieee80211_vif *vif, 687 char *bin, ssize_t len, 688 bool restore) 689 { 690 struct iwl_mld_vif *mld_vif; 691 struct iwl_mld_link *mld_link; 692 struct iwl_mac_beacon_cmd beacon_cmd = {}; 693 int n_bytes = len / 2; 694 695 /* Element len should be represented by u8 */ 696 if (n_bytes >= U8_MAX) 697 return -EINVAL; 698 699 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 700 return -EIO; 701 702 if (!vif) 703 return -EINVAL; 704 705 mld_vif = iwl_mld_vif_from_mac80211(vif); 706 mld_vif->beacon_inject_active = true; 707 mld->hw->extra_beacon_tailroom = n_bytes; 708 709 for_each_mld_vif_valid_link(mld_vif, mld_link) { 710 u32 offset; 711 struct ieee80211_tx_info *info; 712 struct ieee80211_bss_conf *link_conf = 713 link_conf_dereference_protected(vif, link_id); 714 struct ieee80211_chanctx_conf *ctx = 715 wiphy_dereference(mld->wiphy, link_conf->chanctx_conf); 716 struct sk_buff *beacon = 717 ieee80211_beacon_get_template(mld->hw, vif, 718 NULL, link_id); 719 720 if (!beacon) 721 return -EINVAL; 722 723 if (!restore && (WARN_ON(!n_bytes || !bin) || 724 hex2bin(skb_put_zero(beacon, n_bytes), 725 bin, n_bytes))) { 726 dev_kfree_skb(beacon); 727 return -EINVAL; 728 } 729 730 info = IEEE80211_SKB_CB(beacon); 731 732 beacon_cmd.flags = 733 cpu_to_le16(iwl_mld_get_rate_flags(mld, info, vif, 734 link_conf, 735 ctx->def.chan->band)); 736 beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len); 737 beacon_cmd.link_id = 738 cpu_to_le32(mld_link->fw_id); 739 740 iwl_mld_set_tim_idx(mld, &beacon_cmd.tim_idx, 741 beacon->data, beacon->len); 742 743 offset = iwl_find_ie_offset(beacon->data, 744 WLAN_EID_S1G_TWT, 745 beacon->len); 746 747 beacon_cmd.btwt_offset = cpu_to_le32(offset); 748 749 iwl_mld_send_beacon_template_cmd(mld, beacon, &beacon_cmd); 750 dev_kfree_skb(beacon); 751 } 752 753 if (restore) 754 mld_vif->beacon_inject_active = false; 755 756 return 0; 757 } 758 759 static ssize_t 760 iwl_dbgfs_vif_inject_beacon_ie_write(struct iwl_mld *mld, 761 char *buf, size_t count, 762 void *data) 763 { 764 struct ieee80211_vif *vif = data; 765 int ret = _iwl_dbgfs_inject_beacon_ie(mld, vif, buf, 766 count, false); 767 768 mld->hw->extra_beacon_tailroom = 0; 769 return ret ?: count; 770 } 771 772 VIF_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie, 512); 773 774 static ssize_t 775 iwl_dbgfs_vif_inject_beacon_ie_restore_write(struct iwl_mld *mld, 776 char *buf, 777 size_t count, 778 void *data) 779 { 780 struct ieee80211_vif *vif = data; 781 int ret = _iwl_dbgfs_inject_beacon_ie(mld, vif, NULL, 782 0, true); 783 784 mld->hw->extra_beacon_tailroom = 0; 785 return ret ?: count; 786 } 787 788 VIF_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie_restore, 512); 789 790 static ssize_t 791 iwl_dbgfs_vif_twt_setup_write(struct iwl_mld *mld, char *buf, size_t count, 792 void *data) 793 { 794 struct iwl_host_cmd hcmd = { 795 .id = WIDE_ID(IWL_ALWAYS_LONG_GROUP, DEBUG_HOST_COMMAND), 796 }; 797 struct ieee80211_vif *vif = data; 798 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 799 struct iwl_dhc_cmd *cmd __free(kfree) = NULL; 800 struct iwl_dhc_twt_operation *dhc_twt_cmd; 801 u64 target_wake_time; 802 u32 twt_operation, interval_exp, interval_mantissa, min_wake_duration; 803 u8 trigger, flow_type, flow_id, protection, tenth_param; 804 u8 twt_request = 1, broadcast = 0; 805 int ret; 806 807 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 808 return -EIO; 809 810 ret = sscanf(buf, "%u %llu %u %u %u %hhu %hhu %hhu %hhu %hhu", 811 &twt_operation, &target_wake_time, &interval_exp, 812 &interval_mantissa, &min_wake_duration, &trigger, 813 &flow_type, &flow_id, &protection, &tenth_param); 814 815 /* the new twt_request parameter is optional for station */ 816 if ((ret != 9 && ret != 10) || 817 (ret == 10 && vif->type != NL80211_IFTYPE_STATION && 818 tenth_param == 1)) 819 return -EINVAL; 820 821 /* The 10th parameter: 822 * In STA mode - the TWT type (broadcast or individual) 823 * In AP mode - the role (0 responder, 2 unsolicited) 824 */ 825 if (ret == 10) { 826 if (vif->type == NL80211_IFTYPE_STATION) 827 broadcast = tenth_param; 828 else 829 twt_request = tenth_param; 830 } 831 832 cmd = kzalloc(sizeof(*cmd) + sizeof(*dhc_twt_cmd), GFP_KERNEL); 833 if (!cmd) 834 return -ENOMEM; 835 836 dhc_twt_cmd = (void *)cmd->data; 837 dhc_twt_cmd->mac_id = cpu_to_le32(mld_vif->fw_id); 838 dhc_twt_cmd->twt_operation = cpu_to_le32(twt_operation); 839 dhc_twt_cmd->target_wake_time = cpu_to_le64(target_wake_time); 840 dhc_twt_cmd->interval_exp = cpu_to_le32(interval_exp); 841 dhc_twt_cmd->interval_mantissa = cpu_to_le32(interval_mantissa); 842 dhc_twt_cmd->min_wake_duration = cpu_to_le32(min_wake_duration); 843 dhc_twt_cmd->trigger = trigger; 844 dhc_twt_cmd->flow_type = flow_type; 845 dhc_twt_cmd->flow_id = flow_id; 846 dhc_twt_cmd->protection = protection; 847 dhc_twt_cmd->twt_request = twt_request; 848 dhc_twt_cmd->negotiation_type = broadcast ? 3 : 0; 849 850 cmd->length = cpu_to_le32(sizeof(*dhc_twt_cmd) >> 2); 851 cmd->index_and_mask = 852 cpu_to_le32(DHC_TABLE_INTEGRATION | DHC_TARGET_UMAC | 853 DHC_INT_UMAC_TWT_OPERATION); 854 855 hcmd.len[0] = sizeof(*cmd) + sizeof(*dhc_twt_cmd); 856 hcmd.data[0] = cmd; 857 858 ret = iwl_mld_send_cmd(mld, &hcmd); 859 860 return ret ?: count; 861 } 862 863 VIF_DEBUGFS_WRITE_FILE_OPS(twt_setup, 256); 864 865 static ssize_t 866 iwl_dbgfs_vif_twt_operation_write(struct iwl_mld *mld, char *buf, size_t count, 867 void *data) 868 { 869 struct ieee80211_vif *vif = data; 870 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 871 struct iwl_twt_operation_cmd twt_cmd = {}; 872 int link_id = vif->active_links ? __ffs(vif->active_links) : 0; 873 struct iwl_mld_link *mld_link = iwl_mld_link_dereference_check(mld_vif, 874 link_id); 875 int ret; 876 877 if (WARN_ON(!mld_link)) 878 return -ENODEV; 879 880 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 881 return -EIO; 882 883 if (hweight16(vif->active_links) > 1) 884 return -EOPNOTSUPP; 885 886 ret = sscanf(buf, 887 "%u %llu %u %u %u %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu", 888 &twt_cmd.twt_operation, &twt_cmd.target_wake_time, 889 &twt_cmd.interval_exponent, &twt_cmd.interval_mantissa, 890 &twt_cmd.minimum_wake_duration, &twt_cmd.trigger, 891 &twt_cmd.flow_type, &twt_cmd.flow_id, 892 &twt_cmd.twt_protection, &twt_cmd.ndp_paging_indicator, 893 &twt_cmd.responder_pm_mode, &twt_cmd.negotiation_type, 894 &twt_cmd.twt_request, &twt_cmd.implicit, 895 &twt_cmd.twt_group_assignment, &twt_cmd.twt_channel, 896 &twt_cmd.restricted_info_present, &twt_cmd.dl_bitmap_valid, 897 &twt_cmd.ul_bitmap_valid, &twt_cmd.dl_tid_bitmap, 898 &twt_cmd.ul_tid_bitmap); 899 900 if (ret != 21) 901 return -EINVAL; 902 903 twt_cmd.link_id = cpu_to_le32(mld_link->fw_id); 904 905 ret = iwl_mld_send_cmd_pdu(mld, 906 WIDE_ID(MAC_CONF_GROUP, TWT_OPERATION_CMD), 907 &twt_cmd); 908 return ret ?: count; 909 } 910 911 VIF_DEBUGFS_WRITE_FILE_OPS(twt_operation, 256); 912 913 static ssize_t iwl_dbgfs_vif_int_mlo_scan_write(struct iwl_mld *mld, char *buf, 914 size_t count, void *data) 915 { 916 struct ieee80211_vif *vif = data; 917 u32 action; 918 int ret; 919 920 if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) 921 return -EINVAL; 922 923 if (kstrtou32(buf, 0, &action)) 924 return -EINVAL; 925 926 if (action == 0) { 927 ret = iwl_mld_scan_stop(mld, IWL_MLD_SCAN_INT_MLO, false); 928 } else if (action == 1) { 929 iwl_mld_int_mlo_scan(mld, vif); 930 ret = 0; 931 } else { 932 ret = -EINVAL; 933 } 934 935 return ret ?: count; 936 } 937 938 VIF_DEBUGFS_WRITE_FILE_OPS(int_mlo_scan, 32); 939 940 void iwl_mld_add_vif_debugfs(struct ieee80211_hw *hw, 941 struct ieee80211_vif *vif) 942 { 943 struct dentry *mld_vif_dbgfs = 944 debugfs_create_dir("iwlmld", vif->debugfs_dir); 945 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 946 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); 947 char target[3 * 3 + 11 + (NL80211_WIPHY_NAME_MAXLEN + 1) + 948 (7 + IFNAMSIZ + 1) + 6 + 1]; 949 char name[7 + IFNAMSIZ + 1]; 950 951 /* Create symlink for convenience pointing to interface specific 952 * debugfs entries for the driver. For example, under 953 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmld/ 954 * find 955 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmld/ 956 */ 957 snprintf(name, sizeof(name), "%pd", vif->debugfs_dir); 958 snprintf(target, sizeof(target), "../../../%pd3/iwlmld", 959 vif->debugfs_dir); 960 if (!mld_vif->dbgfs_slink) 961 mld_vif->dbgfs_slink = 962 debugfs_create_symlink(name, mld->debugfs_dir, target); 963 964 if (iwlmld_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && 965 vif->type == NL80211_IFTYPE_STATION) { 966 VIF_DEBUGFS_ADD_FILE(pm_params, mld_vif_dbgfs, 0200); 967 VIF_DEBUGFS_ADD_FILE(bf_params, mld_vif_dbgfs, 0200); 968 } 969 970 if (vif->type == NL80211_IFTYPE_AP) { 971 VIF_DEBUGFS_ADD_FILE(inject_beacon_ie, mld_vif_dbgfs, 0200); 972 VIF_DEBUGFS_ADD_FILE(inject_beacon_ie_restore, 973 mld_vif_dbgfs, 0200); 974 } 975 976 VIF_DEBUGFS_ADD_FILE(low_latency, mld_vif_dbgfs, 0600); 977 VIF_DEBUGFS_ADD_FILE(twt_setup, mld_vif_dbgfs, 0200); 978 VIF_DEBUGFS_ADD_FILE(twt_operation, mld_vif_dbgfs, 0200); 979 VIF_DEBUGFS_ADD_FILE(int_mlo_scan, mld_vif_dbgfs, 0200); 980 } 981 #define LINK_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ 982 WIPHY_DEBUGFS_WRITE_FILE_OPS(link_##name, bufsz, bss_conf) 983 984 #define LINK_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) \ 985 debugfs_create_file(alias, mode, parent, link_conf, \ 986 &iwl_dbgfs_link_##name##_ops) 987 #define LINK_DEBUGFS_ADD_FILE(name, parent, mode) \ 988 LINK_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) 989 990 void iwl_mld_add_link_debugfs(struct ieee80211_hw *hw, 991 struct ieee80211_vif *vif, 992 struct ieee80211_bss_conf *link_conf, 993 struct dentry *dir) 994 { 995 struct dentry *mld_link_dir; 996 997 mld_link_dir = debugfs_lookup("iwlmld", dir); 998 999 /* For non-MLO vifs, the dir of deflink is the same as the vif's one. 1000 * so if iwlmld dir already exists, this means that this is deflink. 1001 * If not, this is a per-link dir of a MLO vif, add in it the iwlmld 1002 * dir. 1003 */ 1004 if (!mld_link_dir) 1005 mld_link_dir = debugfs_create_dir("iwlmld", dir); 1006 } 1007 1008 static ssize_t _iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf, 1009 size_t count, void *data, bool v3) 1010 { 1011 struct ieee80211_link_sta *link_sta = data; 1012 struct iwl_mld_link_sta *mld_link_sta; 1013 u32 rate; 1014 u32 partial = false; 1015 char pretty_rate[100]; 1016 int ret; 1017 u8 fw_sta_id; 1018 1019 mld_link_sta = iwl_mld_link_sta_from_mac80211(link_sta); 1020 if (WARN_ON(!mld_link_sta)) 1021 return -EINVAL; 1022 1023 fw_sta_id = mld_link_sta->fw_id; 1024 1025 if (sscanf(buf, "%i %i", &rate, &partial) == 0) 1026 return -EINVAL; 1027 1028 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 1029 return -EIO; 1030 1031 /* input is in FW format (v2 or v3) so convert to v3 */ 1032 rate = iwl_v3_rate_from_v2_v3(cpu_to_le32(rate), v3); 1033 rate = le32_to_cpu(iwl_v3_rate_to_v2_v3(rate, mld->fw_rates_ver_3)); 1034 1035 ret = iwl_mld_send_tlc_dhc(mld, fw_sta_id, 1036 partial ? IWL_TLC_DEBUG_PARTIAL_FIXED_RATE : 1037 IWL_TLC_DEBUG_FIXED_RATE, 1038 rate); 1039 1040 rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate), rate); 1041 1042 IWL_DEBUG_RATE(mld, "sta_id %d rate %s partial: %d, ret:%d\n", 1043 fw_sta_id, pretty_rate, partial, ret); 1044 1045 return ret ? : count; 1046 } 1047 1048 static ssize_t iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf, 1049 size_t count, void *data) 1050 { 1051 return _iwl_dbgfs_fixed_rate_write(mld, buf, count, data, false); 1052 } 1053 1054 static ssize_t iwl_dbgfs_fixed_rate_v3_write(struct iwl_mld *mld, char *buf, 1055 size_t count, void *data) 1056 { 1057 return _iwl_dbgfs_fixed_rate_write(mld, buf, count, data, true); 1058 } 1059 1060 static ssize_t iwl_dbgfs_tlc_dhc_write(struct iwl_mld *mld, char *buf, 1061 size_t count, void *data) 1062 { 1063 struct ieee80211_link_sta *link_sta = data; 1064 struct iwl_mld_link_sta *mld_link_sta; 1065 u32 type, value; 1066 int ret; 1067 u8 fw_sta_id; 1068 1069 mld_link_sta = iwl_mld_link_sta_from_mac80211(link_sta); 1070 if (WARN_ON(!mld_link_sta)) 1071 return -EINVAL; 1072 1073 fw_sta_id = mld_link_sta->fw_id; 1074 1075 if (sscanf(buf, "%i %i", &type, &value) != 2) { 1076 IWL_DEBUG_RATE(mld, "usage <type> <value>\n"); 1077 return -EINVAL; 1078 } 1079 1080 if (iwl_mld_dbgfs_fw_cmd_disabled(mld)) 1081 return -EIO; 1082 1083 ret = iwl_mld_send_tlc_dhc(mld, fw_sta_id, type, value); 1084 1085 return ret ? : count; 1086 } 1087 1088 #define LINK_STA_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) \ 1089 debugfs_create_file(alias, mode, parent, link_sta, \ 1090 &iwl_dbgfs_##name##_ops) 1091 #define LINK_STA_DEBUGFS_ADD_FILE(name, parent, mode) \ 1092 LINK_STA_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) 1093 1094 #define LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(name, bufsz) \ 1095 WIPHY_DEBUGFS_WRITE_FILE_OPS(name, bufsz, link_sta) 1096 1097 LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(tlc_dhc, 64); 1098 LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(fixed_rate, 64); 1099 LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(fixed_rate_v3, 64); 1100 1101 void iwl_mld_add_link_sta_debugfs(struct ieee80211_hw *hw, 1102 struct ieee80211_vif *vif, 1103 struct ieee80211_link_sta *link_sta, 1104 struct dentry *dir) 1105 { 1106 LINK_STA_DEBUGFS_ADD_FILE(fixed_rate, dir, 0200); 1107 LINK_STA_DEBUGFS_ADD_FILE(fixed_rate_v3, dir, 0200); 1108 LINK_STA_DEBUGFS_ADD_FILE(tlc_dhc, dir, 0200); 1109 } 1110