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 /* First attempt to get the PNVM from BIOS */ 259 package = iwl_uefi_get_pnvm(trans_p, len); 260 if (!IS_ERR_OR_NULL(package)) { 261 if (*len >= sizeof(*package)) { 262 /* we need only the data */ 263 *len -= sizeof(*package); 264 image = kmemdup(package->data, *len, GFP_KERNEL); 265 } 266 /* free package regardless of whether kmemdup succeeded */ 267 kfree(package); 268 if (image) 269 return image; 270 } 271 272 /* If it's not available, try from the filesystem */ 273 if (iwl_pnvm_get_from_fs(trans_p, &image, len)) 274 return NULL; 275 return image; 276 } 277 278 static void iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, 279 const struct iwl_ucode_capabilities *capa) 280 { 281 struct iwl_pnvm_image *pnvm_data = NULL; 282 u8 *data = NULL; 283 size_t length; 284 int ret; 285 286 /* failed to get/parse the image in the past, no use trying again */ 287 if (trans->fail_to_parse_pnvm_image) 288 return; 289 290 if (trans->pnvm_loaded) 291 goto set; 292 293 data = iwl_get_pnvm_image(trans, &length); 294 if (!data) { 295 trans->fail_to_parse_pnvm_image = true; 296 return; 297 } 298 299 pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); 300 if (!pnvm_data) 301 goto free; 302 303 ret = iwl_pnvm_parse(trans, data, length, pnvm_data); 304 if (ret) { 305 trans->fail_to_parse_pnvm_image = true; 306 goto free; 307 } 308 309 ret = iwl_trans_load_pnvm(trans, pnvm_data, capa); 310 if (ret) 311 goto free; 312 IWL_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version); 313 314 set: 315 iwl_trans_set_pnvm(trans, capa); 316 free: 317 kfree(data); 318 kfree(pnvm_data); 319 } 320 321 static void 322 iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans, 323 const struct iwl_ucode_capabilities *capa) 324 { 325 struct iwl_pnvm_image *pnvm_data = NULL; 326 u8 *data = NULL; 327 size_t length; 328 int ret; 329 330 if (trans->failed_to_load_reduce_power_image) 331 return; 332 333 if (trans->reduce_power_loaded) 334 goto set; 335 336 data = iwl_uefi_get_reduced_power(trans, &length); 337 if (IS_ERR(data)) { 338 trans->failed_to_load_reduce_power_image = true; 339 return; 340 } 341 342 pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); 343 if (!pnvm_data) 344 goto free; 345 346 ret = iwl_uefi_reduce_power_parse(trans, data, length, pnvm_data); 347 if (ret) { 348 trans->failed_to_load_reduce_power_image = true; 349 goto free; 350 } 351 352 ret = iwl_trans_load_reduce_power(trans, pnvm_data, capa); 353 if (ret) { 354 IWL_DEBUG_FW(trans, 355 "Failed to load reduce power table %d\n", 356 ret); 357 trans->failed_to_load_reduce_power_image = true; 358 goto free; 359 } 360 361 set: 362 iwl_trans_set_reduce_power(trans, capa); 363 free: 364 kfree(data); 365 kfree(pnvm_data); 366 } 367 368 int iwl_pnvm_load(struct iwl_trans *trans, 369 struct iwl_notif_wait_data *notif_wait, 370 const struct iwl_ucode_capabilities *capa) 371 { 372 struct iwl_notification_wait pnvm_wait; 373 static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, 374 PNVM_INIT_COMPLETE_NTFY) }; 375 376 /* if the SKU_ID is empty, there's nothing to do */ 377 if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2]) 378 return 0; 379 380 iwl_pnvm_load_pnvm_to_trans(trans, capa); 381 iwl_pnvm_load_reduce_power_to_trans(trans, capa); 382 383 iwl_init_notification_wait(notif_wait, &pnvm_wait, 384 ntf_cmds, ARRAY_SIZE(ntf_cmds), 385 iwl_pnvm_complete_fn, trans); 386 387 /* kick the doorbell */ 388 iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, 389 UREG_DOORBELL_TO_ISR6_PNVM); 390 391 return iwl_wait_notification(notif_wait, &pnvm_wait, 392 MVM_UCODE_PNVM_TIMEOUT); 393 } 394 IWL_EXPORT_SYMBOL(iwl_pnvm_load); 395