1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright(c) 2020-2025 Intel Corporation 4 */ 5 6 #include "iwl-drv.h" 7 #include "pnvm.h" 8 #include "iwl-prph.h" 9 #include "iwl-io.h" 10 #include "fw/api/commands.h" 11 #include "fw/api/nvm-reg.h" 12 #include "fw/api/alive.h" 13 #include "fw/uefi.h" 14 #include "fw/img.h" 15 16 #define IWL_PNVM_REDUCED_CAP_BIT BIT(25) 17 18 struct iwl_pnvm_section { 19 __le32 offset; 20 const u8 data[]; 21 } __packed; 22 23 static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, 24 struct iwl_rx_packet *pkt, void *data) 25 { 26 struct iwl_trans *trans = (struct iwl_trans *)data; 27 struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data; 28 29 IWL_DEBUG_FW(trans, 30 "PNVM complete notification received with status 0x%0x\n", 31 le32_to_cpu(pnvm_ntf->status)); 32 33 return true; 34 } 35 36 static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, 37 size_t len, 38 struct iwl_pnvm_image *pnvm_data) 39 { 40 const struct iwl_ucode_tlv *tlv; 41 u32 sha1 = 0; 42 u16 mac_type = 0, rf_id = 0; 43 bool hw_match = false; 44 45 IWL_DEBUG_FW(trans, "Handling PNVM section\n"); 46 47 memset(pnvm_data, 0, sizeof(*pnvm_data)); 48 49 while (len >= sizeof(*tlv)) { 50 u32 tlv_len, tlv_type; 51 52 len -= sizeof(*tlv); 53 tlv = (const void *)data; 54 55 tlv_len = le32_to_cpu(tlv->length); 56 tlv_type = le32_to_cpu(tlv->type); 57 58 if (len < tlv_len) { 59 IWL_ERR(trans, "invalid TLV len: %zd/%u\n", 60 len, tlv_len); 61 return -EINVAL; 62 } 63 64 data += sizeof(*tlv); 65 66 switch (tlv_type) { 67 case IWL_UCODE_TLV_PNVM_VERSION: 68 if (tlv_len < sizeof(__le32)) { 69 IWL_DEBUG_FW(trans, 70 "Invalid size for IWL_UCODE_TLV_PNVM_VERSION (expected %zd, got %d)\n", 71 sizeof(__le32), tlv_len); 72 break; 73 } 74 75 sha1 = le32_to_cpup((const __le32 *)data); 76 77 IWL_DEBUG_FW(trans, 78 "Got IWL_UCODE_TLV_PNVM_VERSION %0x\n", 79 sha1); 80 pnvm_data->version = sha1; 81 break; 82 case IWL_UCODE_TLV_HW_TYPE: 83 if (tlv_len < 2 * sizeof(__le16)) { 84 IWL_DEBUG_FW(trans, 85 "Invalid size for IWL_UCODE_TLV_HW_TYPE (expected %zd, got %d)\n", 86 2 * sizeof(__le16), tlv_len); 87 break; 88 } 89 90 if (hw_match) 91 break; 92 93 mac_type = le16_to_cpup((const __le16 *)data); 94 rf_id = le16_to_cpup((const __le16 *)(data + sizeof(__le16))); 95 96 IWL_DEBUG_FW(trans, 97 "Got IWL_UCODE_TLV_HW_TYPE mac_type 0x%0x rf_id 0x%0x\n", 98 mac_type, rf_id); 99 100 if (mac_type == CSR_HW_REV_TYPE(trans->info.hw_rev) && 101 rf_id == CSR_HW_RFID_TYPE(trans->info.hw_rf_id)) 102 hw_match = true; 103 break; 104 case IWL_UCODE_TLV_SEC_RT: { 105 const struct iwl_pnvm_section *section = (const void *)data; 106 u32 data_len = tlv_len - sizeof(*section); 107 108 IWL_DEBUG_FW(trans, 109 "Got IWL_UCODE_TLV_SEC_RT len %d\n", 110 tlv_len); 111 112 /* TODO: remove, this is a deprecated separator */ 113 if (le32_to_cpup((const __le32 *)data) == 0xddddeeee) { 114 IWL_DEBUG_FW(trans, "Ignoring separator.\n"); 115 break; 116 } 117 118 if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { 119 IWL_DEBUG_FW(trans, 120 "too many payloads to allocate in DRAM.\n"); 121 return -EINVAL; 122 } 123 124 IWL_DEBUG_FW(trans, "Adding data (size %d)\n", 125 data_len); 126 127 pnvm_data->chunks[pnvm_data->n_chunks].data = section->data; 128 pnvm_data->chunks[pnvm_data->n_chunks].len = data_len; 129 pnvm_data->n_chunks++; 130 131 break; 132 } 133 case IWL_UCODE_TLV_MEM_DESC: 134 if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len, 135 pnvm_data)) 136 return -EINVAL; 137 break; 138 case IWL_UCODE_TLV_PNVM_SKU: 139 IWL_DEBUG_FW(trans, 140 "New PNVM section started, stop parsing.\n"); 141 goto done; 142 default: 143 IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n", 144 tlv_type, tlv_len); 145 break; 146 } 147 148 len -= ALIGN(tlv_len, 4); 149 data += ALIGN(tlv_len, 4); 150 } 151 152 done: 153 if (!hw_match) { 154 IWL_DEBUG_FW(trans, 155 "HW mismatch, skipping PNVM section (need mac_type 0x%x rf_id 0x%x)\n", 156 CSR_HW_REV_TYPE(trans->info.hw_rev), 157 CSR_HW_RFID_TYPE(trans->info.hw_rf_id)); 158 return -ENOENT; 159 } 160 161 if (!pnvm_data->n_chunks) { 162 IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n"); 163 return -ENOENT; 164 } 165 166 return 0; 167 } 168 169 static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, 170 size_t len, 171 struct iwl_pnvm_image *pnvm_data, 172 __le32 sku_id[3]) 173 { 174 const struct iwl_ucode_tlv *tlv; 175 176 IWL_DEBUG_FW(trans, "Parsing PNVM file\n"); 177 178 while (len >= sizeof(*tlv)) { 179 u32 tlv_len, tlv_type; 180 u32 rf_type; 181 182 len -= sizeof(*tlv); 183 tlv = (const void *)data; 184 185 tlv_len = le32_to_cpu(tlv->length); 186 tlv_type = le32_to_cpu(tlv->type); 187 188 if (len < tlv_len) { 189 IWL_ERR(trans, "invalid TLV len: %zd/%u\n", 190 len, tlv_len); 191 return -EINVAL; 192 } 193 194 if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) { 195 const struct iwl_sku_id *tlv_sku_id = 196 (const void *)(data + sizeof(*tlv)); 197 198 IWL_DEBUG_FW(trans, 199 "Got IWL_UCODE_TLV_PNVM_SKU len %d\n", 200 tlv_len); 201 IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n", 202 le32_to_cpu(tlv_sku_id->data[0]), 203 le32_to_cpu(tlv_sku_id->data[1]), 204 le32_to_cpu(tlv_sku_id->data[2])); 205 206 data += sizeof(*tlv) + ALIGN(tlv_len, 4); 207 len -= ALIGN(tlv_len, 4); 208 209 trans->reduced_cap_sku = false; 210 rf_type = CSR_HW_RFID_TYPE(trans->info.hw_rf_id); 211 if ((sku_id[0] & cpu_to_le32(IWL_PNVM_REDUCED_CAP_BIT)) && 212 rf_type == IWL_CFG_RF_TYPE_FM) 213 trans->reduced_cap_sku = true; 214 215 IWL_DEBUG_FW(trans, 216 "Reduced SKU device %d\n", 217 trans->reduced_cap_sku); 218 219 if (sku_id[0] == tlv_sku_id->data[0] && 220 sku_id[1] == tlv_sku_id->data[1] && 221 sku_id[2] == tlv_sku_id->data[2]) { 222 int ret; 223 224 ret = iwl_pnvm_handle_section(trans, data, len, 225 pnvm_data); 226 if (!ret) 227 return 0; 228 } else { 229 IWL_DEBUG_FW(trans, "SKU ID didn't match!\n"); 230 } 231 } else { 232 data += sizeof(*tlv) + ALIGN(tlv_len, 4); 233 len -= ALIGN(tlv_len, 4); 234 } 235 } 236 237 return -ENOENT; 238 } 239 240 static u8 *iwl_pnvm_get_from_fs(struct iwl_trans *trans, size_t *len) 241 { 242 const struct firmware *pnvm; 243 char pnvm_name[MAX_PNVM_NAME]; 244 size_t new_len; 245 u8 *data; 246 int ret; 247 248 iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name)); 249 250 ret = firmware_request_nowarn(&pnvm, pnvm_name, trans->dev); 251 if (ret) { 252 IWL_DEBUG_FW(trans, "PNVM file %s not found %d\n", 253 pnvm_name, ret); 254 return NULL; 255 } 256 257 new_len = pnvm->size; 258 data = kvmemdup(pnvm->data, pnvm->size, GFP_KERNEL); 259 release_firmware(pnvm); 260 261 if (!data) 262 return NULL; 263 264 *len = new_len; 265 266 return data; 267 } 268 269 /** 270 * enum iwl_pnvm_source - different PNVM possible sources 271 * 272 * @IWL_PNVM_SOURCE_NONE: No PNVM. 273 * @IWL_PNVM_SOURCE_BIOS: PNVM should be read from BIOS. 274 * @IWL_PNVM_SOURCE_EXTERNAL: read .pnvm external file 275 * @IWL_PNVM_SOURCE_EMBEDDED: PNVM is embedded in the .ucode file. 276 */ 277 enum iwl_pnvm_source { 278 IWL_PNVM_SOURCE_NONE, 279 IWL_PNVM_SOURCE_BIOS, 280 IWL_PNVM_SOURCE_EXTERNAL, 281 IWL_PNVM_SOURCE_EMBEDDED 282 }; 283 284 static enum iwl_pnvm_source iwl_select_pnvm_source(struct iwl_trans *trans, 285 bool intel_sku) 286 { 287 288 /* Get PNVM from BIOS for non-Intel SKU */ 289 if (!intel_sku) 290 return IWL_PNVM_SOURCE_BIOS; 291 292 /* Before those devices, PNVM didn't exist at all */ 293 if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) 294 return IWL_PNVM_SOURCE_NONE; 295 296 /* After those devices, we moved to embedded PNVM */ 297 if (trans->mac_cfg->device_family > IWL_DEVICE_FAMILY_AX210) 298 return IWL_PNVM_SOURCE_EMBEDDED; 299 300 /* For IWL_DEVICE_FAMILY_AX210, depends on the CRF */ 301 if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_GF) 302 return IWL_PNVM_SOURCE_EXTERNAL; 303 304 return IWL_PNVM_SOURCE_NONE; 305 } 306 307 static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, 308 __le32 sku_id[3], const struct iwl_fw *fw) 309 { 310 struct pnvm_sku_package *package; 311 enum iwl_pnvm_source pnvm_src = 312 iwl_select_pnvm_source(trans_p, sku_id[2] == 0); 313 u8 *image = NULL; 314 315 IWL_DEBUG_FW(trans_p, "PNVM source %d\n", pnvm_src); 316 317 if (pnvm_src == IWL_PNVM_SOURCE_NONE) 318 return NULL; 319 320 if (pnvm_src == IWL_PNVM_SOURCE_BIOS) { 321 package = iwl_uefi_get_pnvm(trans_p, len); 322 if (!IS_ERR_OR_NULL(package)) { 323 if (*len >= sizeof(*package)) { 324 /* we need only the data */ 325 *len -= sizeof(*package); 326 image = kvmemdup(package->data, 327 *len, GFP_KERNEL); 328 } 329 /* 330 * free package regardless of whether kmemdup 331 * succeeded 332 */ 333 kfree(package); 334 if (image) 335 return image; 336 } 337 338 /* PNVM doesn't exist in BIOS. Find the fallback source */ 339 pnvm_src = iwl_select_pnvm_source(trans_p, true); 340 IWL_DEBUG_FW(trans_p, "PNVM in BIOS doesn't exist, try %d\n", 341 pnvm_src); 342 } 343 344 if (pnvm_src == IWL_PNVM_SOURCE_EXTERNAL) { 345 image = iwl_pnvm_get_from_fs(trans_p, len); 346 if (image) 347 return image; 348 } 349 350 if (pnvm_src == IWL_PNVM_SOURCE_EMBEDDED && fw->pnvm_data) { 351 *len = fw->pnvm_size; 352 return fw->pnvm_data; 353 } 354 355 IWL_ERR(trans_p, "Couldn't get PNVM from required source: %d\n", pnvm_src); 356 return NULL; 357 } 358 359 static void 360 iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, 361 const struct iwl_fw *fw, 362 __le32 sku_id[3]) 363 { 364 struct iwl_pnvm_image *pnvm_data = NULL; 365 const u8 *data = NULL; 366 size_t length; 367 int ret; 368 369 /* failed to get/parse the image in the past, no use trying again */ 370 if (trans->fail_to_parse_pnvm_image) 371 return; 372 373 if (trans->pnvm_loaded) 374 goto set; 375 376 data = iwl_get_pnvm_image(trans, &length, sku_id, fw); 377 if (!data) { 378 trans->fail_to_parse_pnvm_image = true; 379 return; 380 } 381 382 pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); 383 if (!pnvm_data) 384 goto free; 385 386 ret = iwl_pnvm_parse(trans, data, length, pnvm_data, sku_id); 387 if (ret) { 388 trans->fail_to_parse_pnvm_image = true; 389 goto free; 390 } 391 392 ret = iwl_trans_load_pnvm(trans, pnvm_data, &fw->ucode_capa); 393 if (ret) 394 goto free; 395 IWL_DEBUG_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version); 396 397 set: 398 iwl_trans_set_pnvm(trans, &fw->ucode_capa); 399 free: 400 /* free only if it was allocated, i.e. not just embedded PNVM data */ 401 if (data != fw->pnvm_data) 402 kvfree(data); 403 kfree(pnvm_data); 404 } 405 406 static void 407 iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans, 408 const struct iwl_ucode_capabilities *capa, 409 __le32 sku_id[3]) 410 { 411 struct iwl_pnvm_image *pnvm_data = NULL; 412 u8 *data = NULL; 413 size_t length; 414 int ret; 415 416 if (trans->failed_to_load_reduce_power_image) 417 return; 418 419 if (trans->reduce_power_loaded) 420 goto set; 421 422 data = iwl_uefi_get_reduced_power(trans, &length); 423 if (IS_ERR(data)) { 424 trans->failed_to_load_reduce_power_image = true; 425 return; 426 } 427 428 pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); 429 if (!pnvm_data) 430 goto free; 431 432 ret = iwl_uefi_reduce_power_parse(trans, data, length, pnvm_data, 433 sku_id); 434 if (ret) { 435 trans->failed_to_load_reduce_power_image = true; 436 goto free; 437 } 438 439 ret = iwl_trans_load_reduce_power(trans, pnvm_data, capa); 440 if (ret) { 441 IWL_DEBUG_FW(trans, 442 "Failed to load reduce power table %d\n", 443 ret); 444 trans->failed_to_load_reduce_power_image = true; 445 goto free; 446 } 447 448 set: 449 iwl_trans_set_reduce_power(trans, capa); 450 free: 451 kfree(data); 452 kfree(pnvm_data); 453 } 454 455 int iwl_pnvm_load(struct iwl_trans *trans, 456 struct iwl_notif_wait_data *notif_wait, 457 const struct iwl_fw *fw, __le32 sku_id[3]) 458 { 459 struct iwl_notification_wait pnvm_wait; 460 static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, 461 PNVM_INIT_COMPLETE_NTFY) }; 462 463 /* if the SKU_ID is empty, there's nothing to do */ 464 if (!sku_id[0] && !sku_id[1] && !sku_id[2]) 465 return 0; 466 467 iwl_pnvm_load_pnvm_to_trans(trans, fw, sku_id); 468 iwl_pnvm_load_reduce_power_to_trans(trans, &fw->ucode_capa, sku_id); 469 470 iwl_init_notification_wait(notif_wait, &pnvm_wait, 471 ntf_cmds, ARRAY_SIZE(ntf_cmds), 472 iwl_pnvm_complete_fn, trans); 473 474 /* kick the doorbell */ 475 iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, 476 UREG_DOORBELL_TO_ISR6_PNVM); 477 478 return iwl_wait_notification(notif_wait, &pnvm_wait, 479 MVM_UCODE_PNVM_TIMEOUT); 480 } 481 IWL_EXPORT_SYMBOL(iwl_pnvm_load); 482