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 8 #include "fw/api/alive.h" 9 #include "fw/api/scan.h" 10 #include "fw/api/rx.h" 11 #include "phy.h" 12 #include "fw/dbg.h" 13 #include "fw/pnvm.h" 14 #include "hcmd.h" 15 #include "power.h" 16 #include "mcc.h" 17 #include "led.h" 18 #include "coex.h" 19 #include "regulatory.h" 20 #include "thermal.h" 21 22 static int iwl_mld_send_tx_ant_cfg(struct iwl_mld *mld) 23 { 24 struct iwl_tx_ant_cfg_cmd cmd; 25 26 lockdep_assert_wiphy(mld->wiphy); 27 28 cmd.valid = cpu_to_le32(iwl_mld_get_valid_tx_ant(mld)); 29 30 IWL_DEBUG_FW(mld, "select valid tx ant: %u\n", cmd.valid); 31 32 return iwl_mld_send_cmd_pdu(mld, TX_ANT_CONFIGURATION_CMD, &cmd); 33 } 34 35 static int iwl_mld_send_rss_cfg_cmd(struct iwl_mld *mld) 36 { 37 struct iwl_rss_config_cmd cmd = { 38 .flags = cpu_to_le32(IWL_RSS_ENABLE), 39 .hash_mask = BIT(IWL_RSS_HASH_TYPE_IPV4_TCP) | 40 BIT(IWL_RSS_HASH_TYPE_IPV4_UDP) | 41 BIT(IWL_RSS_HASH_TYPE_IPV4_PAYLOAD) | 42 BIT(IWL_RSS_HASH_TYPE_IPV6_TCP) | 43 BIT(IWL_RSS_HASH_TYPE_IPV6_UDP) | 44 BIT(IWL_RSS_HASH_TYPE_IPV6_PAYLOAD), 45 }; 46 47 lockdep_assert_wiphy(mld->wiphy); 48 49 /* Do not direct RSS traffic to Q 0 which is our fallback queue */ 50 for (int i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++) 51 cmd.indirection_table[i] = 52 1 + (i % (mld->trans->info.num_rxqs - 1)); 53 netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key)); 54 55 return iwl_mld_send_cmd_pdu(mld, RSS_CONFIG_CMD, &cmd); 56 } 57 58 static int iwl_mld_config_scan(struct iwl_mld *mld) 59 { 60 struct iwl_scan_config cmd = { 61 .tx_chains = cpu_to_le32(iwl_mld_get_valid_tx_ant(mld)), 62 .rx_chains = cpu_to_le32(iwl_mld_get_valid_rx_ant(mld)) 63 }; 64 65 return iwl_mld_send_cmd_pdu(mld, WIDE_ID(LONG_GROUP, SCAN_CFG_CMD), 66 &cmd); 67 } 68 69 static void iwl_mld_alive_imr_data(struct iwl_trans *trans, 70 const struct iwl_imr_alive_info *imr_info) 71 { 72 struct iwl_imr_data *imr_data = &trans->dbg.imr_data; 73 74 imr_data->imr_enable = le32_to_cpu(imr_info->enabled); 75 imr_data->imr_size = le32_to_cpu(imr_info->size); 76 imr_data->imr2sram_remainbyte = imr_data->imr_size; 77 imr_data->imr_base_addr = imr_info->base_addr; 78 imr_data->imr_curr_addr = le64_to_cpu(imr_data->imr_base_addr); 79 80 if (imr_data->imr_enable) 81 return; 82 83 for (int i = 0; i < ARRAY_SIZE(trans->dbg.active_regions); i++) { 84 struct iwl_fw_ini_region_tlv *reg; 85 86 if (!trans->dbg.active_regions[i]) 87 continue; 88 89 reg = (void *)trans->dbg.active_regions[i]->data; 90 91 /* We have only one DRAM IMR region, so we 92 * can break as soon as we find the first 93 * one. 94 */ 95 if (reg->type == IWL_FW_INI_REGION_DRAM_IMR) { 96 trans->dbg.unsupported_region_msk |= BIT(i); 97 break; 98 } 99 } 100 } 101 102 struct iwl_mld_alive_data { 103 __le32 sku_id[3]; 104 bool valid; 105 }; 106 107 static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, 108 struct iwl_rx_packet *pkt, void *data) 109 { 110 unsigned int pkt_len = iwl_rx_packet_payload_len(pkt); 111 unsigned int expected_sz; 112 struct iwl_mld *mld = 113 container_of(notif_wait, struct iwl_mld, notif_wait); 114 struct iwl_trans *trans = mld->trans; 115 u32 version = iwl_fw_lookup_notif_ver(mld->fw, LEGACY_GROUP, 116 UCODE_ALIVE_NTFY, 0); 117 struct iwl_mld_alive_data *alive_data = data; 118 struct iwl_alive_ntf *palive; 119 struct iwl_umac_alive *umac; 120 struct iwl_lmac_alive *lmac1; 121 struct iwl_lmac_alive *lmac2 = NULL; 122 u32 lmac_error_event_table; 123 u32 umac_error_table; 124 u16 status; 125 126 switch (version) { 127 case 6: 128 case 7: 129 expected_sz = sizeof(struct iwl_alive_ntf_v6); 130 break; 131 case 8: 132 expected_sz = sizeof(struct iwl_alive_ntf); 133 break; 134 default: 135 return false; 136 } 137 138 if (pkt_len != expected_sz) 139 return false; 140 141 palive = (void *)pkt->data; 142 143 iwl_mld_alive_imr_data(trans, &palive->imr); 144 145 umac = &palive->umac_data; 146 lmac1 = &palive->lmac_data[0]; 147 lmac2 = &palive->lmac_data[1]; 148 status = le16_to_cpu(palive->status); 149 150 BUILD_BUG_ON(sizeof(alive_data->sku_id) != 151 sizeof(palive->sku_id.data)); 152 memcpy(alive_data->sku_id, palive->sku_id.data, 153 sizeof(palive->sku_id.data)); 154 155 IWL_DEBUG_FW(mld, "Got sku_id: 0x0%x 0x0%x 0x0%x\n", 156 le32_to_cpu(alive_data->sku_id[0]), 157 le32_to_cpu(alive_data->sku_id[1]), 158 le32_to_cpu(alive_data->sku_id[2])); 159 160 lmac_error_event_table = 161 le32_to_cpu(lmac1->dbg_ptrs.error_event_table_ptr); 162 iwl_fw_lmac1_set_alive_err_table(trans, lmac_error_event_table); 163 164 if (lmac2) 165 trans->dbg.lmac_error_event_table[1] = 166 le32_to_cpu(lmac2->dbg_ptrs.error_event_table_ptr); 167 168 umac_error_table = le32_to_cpu(umac->dbg_ptrs.error_info_addr) & 169 ~FW_ADDR_CACHE_CONTROL; 170 171 if (umac_error_table >= trans->mac_cfg->base->min_umac_error_event_table) 172 iwl_fw_umac_set_alive_err_table(trans, umac_error_table); 173 else 174 IWL_ERR(mld, "Not valid error log pointer 0x%08X\n", 175 umac_error_table); 176 177 alive_data->valid = status == IWL_ALIVE_STATUS_OK; 178 179 IWL_DEBUG_FW(mld, 180 "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n", 181 status, lmac1->ver_type, lmac1->ver_subtype); 182 183 if (lmac2) 184 IWL_DEBUG_FW(mld, "Alive ucode CDB\n"); 185 186 IWL_DEBUG_FW(mld, 187 "UMAC version: Major - 0x%x, Minor - 0x%x\n", 188 le32_to_cpu(umac->umac_major), 189 le32_to_cpu(umac->umac_minor)); 190 191 if (version >= 7) 192 IWL_DEBUG_FW(mld, "FW alive flags 0x%x\n", 193 le16_to_cpu(palive->flags)); 194 195 if (version >= 8) 196 IWL_DEBUG_FW(mld, "platform_id 0x%llx\n", 197 le64_to_cpu(palive->platform_id)); 198 199 iwl_fwrt_update_fw_versions(&mld->fwrt, lmac1, umac); 200 201 return true; 202 } 203 204 #define MLD_ALIVE_TIMEOUT (2 * HZ) 205 #define MLD_INIT_COMPLETE_TIMEOUT (2 * HZ) 206 207 static void iwl_mld_print_alive_notif_timeout(struct iwl_mld *mld) 208 { 209 struct iwl_trans *trans = mld->trans; 210 struct iwl_pc_data *pc_data; 211 u8 count; 212 213 IWL_ERR(mld, 214 "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", 215 iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS), 216 iwl_read_umac_prph(trans, 217 UMAG_SB_CPU_2_STATUS)); 218 #define IWL_FW_PRINT_REG_INFO(reg_name) \ 219 IWL_ERR(mld, #reg_name ": 0x%x\n", iwl_read_umac_prph(trans, reg_name)) 220 221 IWL_FW_PRINT_REG_INFO(WFPM_LMAC1_PD_NOTIFICATION); 222 223 IWL_FW_PRINT_REG_INFO(HPM_SECONDARY_DEVICE_STATE); 224 225 /* print OTP info */ 226 IWL_FW_PRINT_REG_INFO(WFPM_MAC_OTP_CFG7_ADDR); 227 IWL_FW_PRINT_REG_INFO(WFPM_MAC_OTP_CFG7_DATA); 228 #undef IWL_FW_PRINT_REG_INFO 229 230 pc_data = trans->dbg.pc_data; 231 for (count = 0; count < trans->dbg.num_pc; count++, pc_data++) 232 IWL_ERR(mld, "%s: 0x%x\n", pc_data->pc_name, 233 pc_data->pc_address); 234 } 235 236 static int iwl_mld_load_fw_wait_alive(struct iwl_mld *mld, 237 struct iwl_mld_alive_data *alive_data) 238 { 239 static const u16 alive_cmd[] = { UCODE_ALIVE_NTFY }; 240 struct iwl_notification_wait alive_wait; 241 int ret; 242 243 lockdep_assert_wiphy(mld->wiphy); 244 245 iwl_init_notification_wait(&mld->notif_wait, &alive_wait, 246 alive_cmd, ARRAY_SIZE(alive_cmd), 247 iwl_alive_fn, alive_data); 248 249 iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_POINT_EARLY, NULL); 250 251 ret = iwl_trans_start_fw(mld->trans, mld->fw, IWL_UCODE_REGULAR, true); 252 if (ret) { 253 iwl_remove_notification(&mld->notif_wait, &alive_wait); 254 return ret; 255 } 256 257 ret = iwl_wait_notification(&mld->notif_wait, &alive_wait, 258 MLD_ALIVE_TIMEOUT); 259 260 if (ret) { 261 if (ret == -ETIMEDOUT) 262 iwl_fw_dbg_error_collect(&mld->fwrt, 263 FW_DBG_TRIGGER_ALIVE_TIMEOUT); 264 iwl_mld_print_alive_notif_timeout(mld); 265 return ret; 266 } 267 268 if (!alive_data->valid) { 269 IWL_ERR(mld, "Loaded firmware is not valid!\n"); 270 return -EIO; 271 } 272 273 iwl_trans_fw_alive(mld->trans); 274 275 return 0; 276 } 277 278 static int iwl_mld_run_fw_init_sequence(struct iwl_mld *mld) 279 { 280 struct iwl_notification_wait init_wait; 281 struct iwl_init_extended_cfg_cmd init_cfg = { 282 .init_flags = cpu_to_le32(BIT(IWL_INIT_PHY)), 283 }; 284 struct iwl_mld_alive_data alive_data = {}; 285 static const u16 init_complete[] = { 286 INIT_COMPLETE_NOTIF, 287 }; 288 int ret; 289 290 lockdep_assert_wiphy(mld->wiphy); 291 292 ret = iwl_mld_load_fw_wait_alive(mld, &alive_data); 293 if (ret) 294 return ret; 295 296 ret = iwl_pnvm_load(mld->trans, &mld->notif_wait, 297 &mld->fw->ucode_capa, alive_data.sku_id); 298 if (ret) { 299 IWL_ERR(mld, "Timeout waiting for PNVM load %d\n", ret); 300 return ret; 301 } 302 303 iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_POINT_AFTER_ALIVE, 304 NULL); 305 306 iwl_init_notification_wait(&mld->notif_wait, 307 &init_wait, 308 init_complete, 309 ARRAY_SIZE(init_complete), 310 NULL, NULL); 311 312 ret = iwl_mld_send_cmd_pdu(mld, 313 WIDE_ID(SYSTEM_GROUP, INIT_EXTENDED_CFG_CMD), 314 &init_cfg); 315 if (ret) { 316 IWL_ERR(mld, "Failed to send init config command: %d\n", ret); 317 iwl_remove_notification(&mld->notif_wait, &init_wait); 318 return ret; 319 } 320 321 ret = iwl_mld_send_phy_cfg_cmd(mld); 322 if (ret) { 323 IWL_ERR(mld, "Failed to send PHY config command: %d\n", ret); 324 iwl_remove_notification(&mld->notif_wait, &init_wait); 325 return ret; 326 } 327 328 ret = iwl_wait_notification(&mld->notif_wait, &init_wait, 329 MLD_INIT_COMPLETE_TIMEOUT); 330 if (ret) { 331 IWL_ERR(mld, "Failed to get INIT_COMPLETE %d\n", ret); 332 return ret; 333 } 334 335 return 0; 336 } 337 338 int iwl_mld_load_fw(struct iwl_mld *mld) 339 { 340 int ret; 341 342 lockdep_assert_wiphy(mld->wiphy); 343 344 ret = iwl_trans_start_hw(mld->trans); 345 if (ret) 346 return ret; 347 348 ret = iwl_mld_run_fw_init_sequence(mld); 349 if (ret) 350 goto err; 351 352 ret = iwl_mld_init_mcc(mld); 353 if (ret) 354 goto err; 355 356 mld->fw_status.running = true; 357 358 return 0; 359 err: 360 iwl_mld_stop_fw(mld); 361 return ret; 362 } 363 364 void iwl_mld_stop_fw(struct iwl_mld *mld) 365 { 366 lockdep_assert_wiphy(mld->wiphy); 367 368 iwl_abort_notification_waits(&mld->notif_wait); 369 370 iwl_fw_dbg_stop_sync(&mld->fwrt); 371 372 iwl_trans_stop_device(mld->trans); 373 374 /* HW is stopped, no more coming RX. Cancel all notifications in 375 * case they were sent just before stopping the HW. 376 */ 377 iwl_mld_cancel_async_notifications(mld); 378 379 mld->fw_status.running = false; 380 } 381 382 static void iwl_mld_restart_disconnect_iter(void *data, u8 *mac, 383 struct ieee80211_vif *vif) 384 { 385 if (vif->type == NL80211_IFTYPE_STATION) 386 ieee80211_hw_restart_disconnect(vif); 387 } 388 389 void iwl_mld_send_recovery_cmd(struct iwl_mld *mld, u32 flags) 390 { 391 u32 error_log_size = mld->fw->ucode_capa.error_log_size; 392 struct iwl_fw_error_recovery_cmd recovery_cmd = { 393 .flags = cpu_to_le32(flags), 394 }; 395 struct iwl_host_cmd cmd = { 396 .id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD), 397 .flags = CMD_WANT_SKB, 398 .data = {&recovery_cmd, }, 399 .len = {sizeof(recovery_cmd), }, 400 }; 401 int ret; 402 403 /* no error log was defined in TLV */ 404 if (!error_log_size) 405 return; 406 407 if (flags & ERROR_RECOVERY_UPDATE_DB) { 408 /* no buf was allocated upon NIC error */ 409 if (!mld->error_recovery_buf) 410 return; 411 412 cmd.data[1] = mld->error_recovery_buf; 413 cmd.len[1] = error_log_size; 414 cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; 415 recovery_cmd.buf_size = cpu_to_le32(error_log_size); 416 } 417 418 ret = iwl_mld_send_cmd(mld, &cmd); 419 420 /* we no longer need the recovery buffer */ 421 kfree(mld->error_recovery_buf); 422 mld->error_recovery_buf = NULL; 423 424 if (ret) { 425 IWL_ERR(mld, "Failed to send recovery cmd %d\n", ret); 426 return; 427 } 428 429 if (flags & ERROR_RECOVERY_UPDATE_DB) { 430 struct iwl_rx_packet *pkt = cmd.resp_pkt; 431 u32 pkt_len = iwl_rx_packet_payload_len(pkt); 432 u32 resp; 433 434 if (IWL_FW_CHECK(mld, pkt_len != sizeof(resp), 435 "Unexpected recovery cmd response size %u (expected %zu)\n", 436 pkt_len, sizeof(resp))) 437 goto out; 438 439 resp = le32_to_cpup((__le32 *)cmd.resp_pkt->data); 440 if (!resp) 441 goto out; 442 443 IWL_ERR(mld, 444 "Failed to send recovery cmd blob was invalid %d\n", 445 resp); 446 447 ieee80211_iterate_interfaces(mld->hw, 0, 448 iwl_mld_restart_disconnect_iter, 449 NULL); 450 } 451 452 out: 453 iwl_free_resp(&cmd); 454 } 455 456 static int iwl_mld_config_fw(struct iwl_mld *mld) 457 { 458 int ret; 459 460 lockdep_assert_wiphy(mld->wiphy); 461 462 iwl_fw_disable_dbg_asserts(&mld->fwrt); 463 iwl_get_shared_mem_conf(&mld->fwrt); 464 465 ret = iwl_mld_send_tx_ant_cfg(mld); 466 if (ret) 467 return ret; 468 469 ret = iwl_mld_send_bt_init_conf(mld); 470 if (ret) 471 return ret; 472 473 ret = iwl_set_soc_latency(&mld->fwrt); 474 if (ret) 475 return ret; 476 477 iwl_mld_configure_lari(mld); 478 479 ret = iwl_mld_config_temp_report_ths(mld); 480 if (ret) 481 return ret; 482 483 #ifdef CONFIG_THERMAL 484 ret = iwl_mld_config_ctdp(mld, mld->cooling_dev.cur_state, 485 CTDP_CMD_OPERATION_START); 486 if (ret) 487 return ret; 488 #endif 489 490 ret = iwl_configure_rxq(&mld->fwrt); 491 if (ret) 492 return ret; 493 494 ret = iwl_mld_send_rss_cfg_cmd(mld); 495 if (ret) 496 return ret; 497 498 ret = iwl_mld_config_scan(mld); 499 if (ret) 500 return ret; 501 502 ret = iwl_mld_update_device_power(mld, false); 503 if (ret) 504 return ret; 505 506 if (mld->fw_status.in_hw_restart) { 507 iwl_mld_send_recovery_cmd(mld, ERROR_RECOVERY_UPDATE_DB); 508 iwl_mld_time_sync_fw_config(mld); 509 } 510 511 iwl_mld_led_config_fw(mld); 512 513 ret = iwl_mld_init_ppag(mld); 514 if (ret) 515 return ret; 516 517 ret = iwl_mld_init_sar(mld); 518 if (ret) 519 return ret; 520 521 ret = iwl_mld_init_sgom(mld); 522 if (ret) 523 return ret; 524 525 iwl_mld_init_tas(mld); 526 iwl_mld_init_uats(mld); 527 528 return 0; 529 } 530 531 int iwl_mld_start_fw(struct iwl_mld *mld) 532 { 533 int ret; 534 535 lockdep_assert_wiphy(mld->wiphy); 536 537 ret = iwl_mld_load_fw(mld); 538 if (IWL_FW_CHECK(mld, ret, "Failed to start firmware %d\n", ret)) { 539 iwl_fw_dbg_error_collect(&mld->fwrt, FW_DBG_TRIGGER_DRIVER); 540 return ret; 541 } 542 543 IWL_DEBUG_INFO(mld, "uCode started.\n"); 544 545 ret = iwl_mld_config_fw(mld); 546 if (ret) 547 goto error; 548 549 return 0; 550 551 error: 552 iwl_mld_stop_fw(mld); 553 return ret; 554 } 555