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 int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) 241 { 242 const struct firmware *pnvm; 243 char pnvm_name[MAX_PNVM_NAME]; 244 size_t new_len; 245 int ret; 246 247 iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name)); 248 249 ret = firmware_request_nowarn(&pnvm, pnvm_name, trans->dev); 250 if (ret) { 251 IWL_DEBUG_FW(trans, "PNVM file %s not found %d\n", 252 pnvm_name, ret); 253 return ret; 254 } 255 256 new_len = pnvm->size; 257 *data = kvmemdup(pnvm->data, pnvm->size, GFP_KERNEL); 258 release_firmware(pnvm); 259 260 if (!*data) 261 return -ENOMEM; 262 263 *len = new_len; 264 265 return 0; 266 } 267 268 static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, 269 __le32 sku_id[3], const struct iwl_fw *fw) 270 { 271 struct pnvm_sku_package *package; 272 u8 *image = NULL; 273 274 /* Get PNVM from BIOS for non-Intel SKU */ 275 if (sku_id[2]) { 276 package = iwl_uefi_get_pnvm(trans_p, len); 277 if (!IS_ERR_OR_NULL(package)) { 278 if (*len >= sizeof(*package)) { 279 /* we need only the data */ 280 *len -= sizeof(*package); 281 image = kvmemdup(package->data, 282 *len, GFP_KERNEL); 283 } 284 /* 285 * free package regardless of whether kmemdup 286 * succeeded 287 */ 288 kfree(package); 289 if (image) 290 return image; 291 } 292 } 293 294 if (fw->pnvm_data) { 295 *len = fw->pnvm_size; 296 297 return fw->pnvm_data; 298 } 299 300 /* If it's not available, or for Intel SKU, try from the filesystem */ 301 if (iwl_pnvm_get_from_fs(trans_p, &image, len)) 302 return NULL; 303 return image; 304 } 305 306 static void 307 iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, 308 const struct iwl_fw *fw, 309 __le32 sku_id[3]) 310 { 311 struct iwl_pnvm_image *pnvm_data = NULL; 312 const u8 *data = NULL; 313 size_t length; 314 int ret; 315 316 /* failed to get/parse the image in the past, no use trying again */ 317 if (trans->fail_to_parse_pnvm_image) 318 return; 319 320 if (trans->pnvm_loaded) 321 goto set; 322 323 data = iwl_get_pnvm_image(trans, &length, sku_id, fw); 324 if (!data) { 325 trans->fail_to_parse_pnvm_image = true; 326 return; 327 } 328 329 pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); 330 if (!pnvm_data) 331 goto free; 332 333 ret = iwl_pnvm_parse(trans, data, length, pnvm_data, sku_id); 334 if (ret) { 335 trans->fail_to_parse_pnvm_image = true; 336 goto free; 337 } 338 339 ret = iwl_trans_load_pnvm(trans, pnvm_data, &fw->ucode_capa); 340 if (ret) 341 goto free; 342 IWL_DEBUG_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version); 343 344 set: 345 iwl_trans_set_pnvm(trans, &fw->ucode_capa); 346 free: 347 /* free only if it was allocated, i.e. not just embedded PNVM data */ 348 if (data != fw->pnvm_data) 349 kvfree(data); 350 kfree(pnvm_data); 351 } 352 353 static void 354 iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans, 355 const struct iwl_ucode_capabilities *capa, 356 __le32 sku_id[3]) 357 { 358 struct iwl_pnvm_image *pnvm_data = NULL; 359 u8 *data = NULL; 360 size_t length; 361 int ret; 362 363 if (trans->failed_to_load_reduce_power_image) 364 return; 365 366 if (trans->reduce_power_loaded) 367 goto set; 368 369 data = iwl_uefi_get_reduced_power(trans, &length); 370 if (IS_ERR(data)) { 371 trans->failed_to_load_reduce_power_image = true; 372 return; 373 } 374 375 pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); 376 if (!pnvm_data) 377 goto free; 378 379 ret = iwl_uefi_reduce_power_parse(trans, data, length, pnvm_data, 380 sku_id); 381 if (ret) { 382 trans->failed_to_load_reduce_power_image = true; 383 goto free; 384 } 385 386 ret = iwl_trans_load_reduce_power(trans, pnvm_data, capa); 387 if (ret) { 388 IWL_DEBUG_FW(trans, 389 "Failed to load reduce power table %d\n", 390 ret); 391 trans->failed_to_load_reduce_power_image = true; 392 goto free; 393 } 394 395 set: 396 iwl_trans_set_reduce_power(trans, capa); 397 free: 398 kfree(data); 399 kfree(pnvm_data); 400 } 401 402 int iwl_pnvm_load(struct iwl_trans *trans, 403 struct iwl_notif_wait_data *notif_wait, 404 const struct iwl_fw *fw, __le32 sku_id[3]) 405 { 406 struct iwl_notification_wait pnvm_wait; 407 static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, 408 PNVM_INIT_COMPLETE_NTFY) }; 409 410 /* if the SKU_ID is empty, there's nothing to do */ 411 if (!sku_id[0] && !sku_id[1] && !sku_id[2]) 412 return 0; 413 414 iwl_pnvm_load_pnvm_to_trans(trans, fw, sku_id); 415 iwl_pnvm_load_reduce_power_to_trans(trans, &fw->ucode_capa, sku_id); 416 417 iwl_init_notification_wait(notif_wait, &pnvm_wait, 418 ntf_cmds, ARRAY_SIZE(ntf_cmds), 419 iwl_pnvm_complete_fn, trans); 420 421 /* kick the doorbell */ 422 iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, 423 UREG_DOORBELL_TO_ISR6_PNVM); 424 425 return iwl_wait_notification(notif_wait, &pnvm_wait, 426 MVM_UCODE_PNVM_TIMEOUT); 427 } 428 IWL_EXPORT_SYMBOL(iwl_pnvm_load); 429