1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright(c) 2020-2023 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 15 struct iwl_pnvm_section { 16 __le32 offset; 17 const u8 data[]; 18 } __packed; 19 20 static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, 21 struct iwl_rx_packet *pkt, void *data) 22 { 23 struct iwl_trans *trans = (struct iwl_trans *)data; 24 struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data; 25 26 IWL_DEBUG_FW(trans, 27 "PNVM complete notification received with status 0x%0x\n", 28 le32_to_cpu(pnvm_ntf->status)); 29 30 return true; 31 } 32 33 static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, 34 size_t len, 35 struct iwl_pnvm_image *pnvm_data) 36 { 37 const struct iwl_ucode_tlv *tlv; 38 u32 sha1 = 0; 39 u16 mac_type = 0, rf_id = 0; 40 bool hw_match = false; 41 42 IWL_DEBUG_FW(trans, "Handling PNVM section\n"); 43 44 memset(pnvm_data, 0, sizeof(*pnvm_data)); 45 46 while (len >= sizeof(*tlv)) { 47 u32 tlv_len, tlv_type; 48 49 len -= sizeof(*tlv); 50 tlv = (const void *)data; 51 52 tlv_len = le32_to_cpu(tlv->length); 53 tlv_type = le32_to_cpu(tlv->type); 54 55 if (len < tlv_len) { 56 IWL_ERR(trans, "invalid TLV len: %zd/%u\n", 57 len, tlv_len); 58 return -EINVAL; 59 } 60 61 data += sizeof(*tlv); 62 63 switch (tlv_type) { 64 case IWL_UCODE_TLV_PNVM_VERSION: 65 if (tlv_len < sizeof(__le32)) { 66 IWL_DEBUG_FW(trans, 67 "Invalid size for IWL_UCODE_TLV_PNVM_VERSION (expected %zd, got %d)\n", 68 sizeof(__le32), tlv_len); 69 break; 70 } 71 72 sha1 = le32_to_cpup((const __le32 *)data); 73 74 IWL_DEBUG_FW(trans, 75 "Got IWL_UCODE_TLV_PNVM_VERSION %0x\n", 76 sha1); 77 pnvm_data->version = sha1; 78 break; 79 case IWL_UCODE_TLV_HW_TYPE: 80 if (tlv_len < 2 * sizeof(__le16)) { 81 IWL_DEBUG_FW(trans, 82 "Invalid size for IWL_UCODE_TLV_HW_TYPE (expected %zd, got %d)\n", 83 2 * sizeof(__le16), tlv_len); 84 break; 85 } 86 87 if (hw_match) 88 break; 89 90 mac_type = le16_to_cpup((const __le16 *)data); 91 rf_id = le16_to_cpup((const __le16 *)(data + sizeof(__le16))); 92 93 IWL_DEBUG_FW(trans, 94 "Got IWL_UCODE_TLV_HW_TYPE mac_type 0x%0x rf_id 0x%0x\n", 95 mac_type, rf_id); 96 97 if (mac_type == CSR_HW_REV_TYPE(trans->hw_rev) && 98 rf_id == CSR_HW_RFID_TYPE(trans->hw_rf_id)) 99 hw_match = true; 100 break; 101 case IWL_UCODE_TLV_SEC_RT: { 102 const struct iwl_pnvm_section *section = (const void *)data; 103 u32 data_len = tlv_len - sizeof(*section); 104 105 IWL_DEBUG_FW(trans, 106 "Got IWL_UCODE_TLV_SEC_RT len %d\n", 107 tlv_len); 108 109 /* TODO: remove, this is a deprecated separator */ 110 if (le32_to_cpup((const __le32 *)data) == 0xddddeeee) { 111 IWL_DEBUG_FW(trans, "Ignoring separator.\n"); 112 break; 113 } 114 115 if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { 116 IWL_DEBUG_FW(trans, 117 "too many payloads to allocate in DRAM.\n"); 118 return -EINVAL; 119 } 120 121 IWL_DEBUG_FW(trans, "Adding data (size %d)\n", 122 data_len); 123 124 pnvm_data->chunks[pnvm_data->n_chunks].data = section->data; 125 pnvm_data->chunks[pnvm_data->n_chunks].len = data_len; 126 pnvm_data->n_chunks++; 127 128 break; 129 } 130 case IWL_UCODE_TLV_MEM_DESC: 131 if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len, 132 pnvm_data)) 133 return -EINVAL; 134 break; 135 case IWL_UCODE_TLV_PNVM_SKU: 136 IWL_DEBUG_FW(trans, 137 "New PNVM section started, stop parsing.\n"); 138 goto done; 139 default: 140 IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n", 141 tlv_type, tlv_len); 142 break; 143 } 144 145 len -= ALIGN(tlv_len, 4); 146 data += ALIGN(tlv_len, 4); 147 } 148 149 done: 150 if (!hw_match) { 151 IWL_DEBUG_FW(trans, 152 "HW mismatch, skipping PNVM section (need mac_type 0x%x rf_id 0x%x)\n", 153 CSR_HW_REV_TYPE(trans->hw_rev), 154 CSR_HW_RFID_TYPE(trans->hw_rf_id)); 155 return -ENOENT; 156 } 157 158 if (!pnvm_data->n_chunks) { 159 IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n"); 160 return -ENOENT; 161 } 162 163 return 0; 164 } 165 166 static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, 167 size_t len, 168 struct iwl_pnvm_image *pnvm_data) 169 { 170 const struct iwl_ucode_tlv *tlv; 171 172 IWL_DEBUG_FW(trans, "Parsing PNVM file\n"); 173 174 while (len >= sizeof(*tlv)) { 175 u32 tlv_len, tlv_type; 176 177 len -= sizeof(*tlv); 178 tlv = (const void *)data; 179 180 tlv_len = le32_to_cpu(tlv->length); 181 tlv_type = le32_to_cpu(tlv->type); 182 183 if (len < tlv_len) { 184 IWL_ERR(trans, "invalid TLV len: %zd/%u\n", 185 len, tlv_len); 186 return -EINVAL; 187 } 188 189 if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) { 190 const struct iwl_sku_id *sku_id = 191 (const void *)(data + sizeof(*tlv)); 192 193 IWL_DEBUG_FW(trans, 194 "Got IWL_UCODE_TLV_PNVM_SKU len %d\n", 195 tlv_len); 196 IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n", 197 le32_to_cpu(sku_id->data[0]), 198 le32_to_cpu(sku_id->data[1]), 199 le32_to_cpu(sku_id->data[2])); 200 201 data += sizeof(*tlv) + ALIGN(tlv_len, 4); 202 len -= ALIGN(tlv_len, 4); 203 204 if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) && 205 trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) && 206 trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { 207 int ret; 208 209 ret = iwl_pnvm_handle_section(trans, data, len, 210 pnvm_data); 211 if (!ret) 212 return 0; 213 } else { 214 IWL_DEBUG_FW(trans, "SKU ID didn't match!\n"); 215 } 216 } else { 217 data += sizeof(*tlv) + ALIGN(tlv_len, 4); 218 len -= ALIGN(tlv_len, 4); 219 } 220 } 221 222 return -ENOENT; 223 } 224 225 static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) 226 { 227 const struct firmware *pnvm; 228 char pnvm_name[MAX_PNVM_NAME]; 229 size_t new_len; 230 int ret; 231 232 iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name)); 233 234 ret = firmware_request_nowarn(&pnvm, pnvm_name, trans->dev); 235 if (ret) { 236 IWL_DEBUG_FW(trans, "PNVM file %s not found %d\n", 237 pnvm_name, ret); 238 return ret; 239 } 240 241 new_len = pnvm->size; 242 *data = kmemdup(pnvm->data, pnvm->size, GFP_KERNEL); 243 release_firmware(pnvm); 244 245 if (!*data) 246 return -ENOMEM; 247 248 *len = new_len; 249 250 return 0; 251 } 252 253 static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) 254 { 255 struct pnvm_sku_package *package; 256 u8 *image = NULL; 257 258 /* Get PNVM from BIOS for non-Intel SKU */ 259 if (trans_p->sku_id[2]) { 260 package = iwl_uefi_get_pnvm(trans_p, len); 261 if (!IS_ERR_OR_NULL(package)) { 262 if (*len >= sizeof(*package)) { 263 /* we need only the data */ 264 *len -= sizeof(*package); 265 image = kmemdup(package->data, 266 *len, GFP_KERNEL); 267 } 268 /* 269 * free package regardless of whether kmemdup 270 * succeeded 271 */ 272 kfree(package); 273 if (image) 274 return image; 275 } 276 } 277 278 /* If it's not available, or for Intel SKU, try from the filesystem */ 279 if (iwl_pnvm_get_from_fs(trans_p, &image, len)) 280 return NULL; 281 return image; 282 } 283 284 static void iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, 285 const struct iwl_ucode_capabilities *capa) 286 { 287 struct iwl_pnvm_image *pnvm_data = NULL; 288 u8 *data = NULL; 289 size_t length; 290 int ret; 291 292 /* failed to get/parse the image in the past, no use trying again */ 293 if (trans->fail_to_parse_pnvm_image) 294 return; 295 296 if (trans->pnvm_loaded) 297 goto set; 298 299 data = iwl_get_pnvm_image(trans, &length); 300 if (!data) { 301 trans->fail_to_parse_pnvm_image = true; 302 return; 303 } 304 305 pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); 306 if (!pnvm_data) 307 goto free; 308 309 ret = iwl_pnvm_parse(trans, data, length, pnvm_data); 310 if (ret) { 311 trans->fail_to_parse_pnvm_image = true; 312 goto free; 313 } 314 315 ret = iwl_trans_load_pnvm(trans, pnvm_data, capa); 316 if (ret) 317 goto free; 318 IWL_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version); 319 320 set: 321 iwl_trans_set_pnvm(trans, capa); 322 free: 323 kfree(data); 324 kfree(pnvm_data); 325 } 326 327 static void 328 iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans, 329 const struct iwl_ucode_capabilities *capa) 330 { 331 struct iwl_pnvm_image *pnvm_data = NULL; 332 u8 *data = NULL; 333 size_t length; 334 int ret; 335 336 if (trans->failed_to_load_reduce_power_image) 337 return; 338 339 if (trans->reduce_power_loaded) 340 goto set; 341 342 data = iwl_uefi_get_reduced_power(trans, &length); 343 if (IS_ERR(data)) { 344 trans->failed_to_load_reduce_power_image = true; 345 return; 346 } 347 348 pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); 349 if (!pnvm_data) 350 goto free; 351 352 ret = iwl_uefi_reduce_power_parse(trans, data, length, pnvm_data); 353 if (ret) { 354 trans->failed_to_load_reduce_power_image = true; 355 goto free; 356 } 357 358 ret = iwl_trans_load_reduce_power(trans, pnvm_data, capa); 359 if (ret) { 360 IWL_DEBUG_FW(trans, 361 "Failed to load reduce power table %d\n", 362 ret); 363 trans->failed_to_load_reduce_power_image = true; 364 goto free; 365 } 366 367 set: 368 iwl_trans_set_reduce_power(trans, capa); 369 free: 370 kfree(data); 371 kfree(pnvm_data); 372 } 373 374 int iwl_pnvm_load(struct iwl_trans *trans, 375 struct iwl_notif_wait_data *notif_wait, 376 const struct iwl_ucode_capabilities *capa) 377 { 378 struct iwl_notification_wait pnvm_wait; 379 static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, 380 PNVM_INIT_COMPLETE_NTFY) }; 381 382 /* if the SKU_ID is empty, there's nothing to do */ 383 if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2]) 384 return 0; 385 386 iwl_pnvm_load_pnvm_to_trans(trans, capa); 387 iwl_pnvm_load_reduce_power_to_trans(trans, capa); 388 389 iwl_init_notification_wait(notif_wait, &pnvm_wait, 390 ntf_cmds, ARRAY_SIZE(ntf_cmds), 391 iwl_pnvm_complete_fn, trans); 392 393 /* kick the doorbell */ 394 iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, 395 UREG_DOORBELL_TO_ISR6_PNVM); 396 397 return iwl_wait_notification(notif_wait, &pnvm_wait, 398 MVM_UCODE_PNVM_TIMEOUT); 399 } 400 IWL_EXPORT_SYMBOL(iwl_pnvm_load); 401