1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright(c) 2021-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 11 #include "fw/uefi.h" 12 #include "fw/api/alive.h" 13 #include <linux/efi.h> 14 #include "fw/runtime.h" 15 16 #define IWL_EFI_WIFI_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \ 17 0xb2, 0xec, 0xf5, 0xa3, \ 18 0x59, 0x4f, 0x4a, 0xea) 19 #define IWL_EFI_WIFI_BT_GUID EFI_GUID(0xe65d8884, 0xd4af, 0x4b20, \ 20 0x8d, 0x03, 0x77, 0x2e, \ 21 0xcc, 0x3d, 0xa5, 0x31) 22 23 struct iwl_uefi_pnvm_mem_desc { 24 __le32 addr; 25 __le32 size; 26 const u8 data[]; 27 } __packed; 28 29 static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid, 30 unsigned long *data_size) 31 { 32 efi_status_t status; 33 void *data; 34 35 if (!data_size) 36 return ERR_PTR(-EINVAL); 37 38 if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) 39 return ERR_PTR(-ENODEV); 40 41 /* first call with NULL data to get the exact entry size */ 42 *data_size = 0; 43 status = efi.get_variable(name, guid, NULL, data_size, NULL); 44 if (status != EFI_BUFFER_TOO_SMALL || !*data_size) 45 return ERR_PTR(-EIO); 46 47 data = kmalloc(*data_size, GFP_KERNEL); 48 if (!data) 49 return ERR_PTR(-ENOMEM); 50 51 status = efi.get_variable(name, guid, NULL, data_size, data); 52 if (status != EFI_SUCCESS) { 53 kfree(data); 54 return ERR_PTR(-ENOENT); 55 } 56 57 return data; 58 } 59 60 void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) 61 { 62 unsigned long package_size; 63 void *data; 64 65 *len = 0; 66 67 data = iwl_uefi_get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_WIFI_GUID, 68 &package_size); 69 if (IS_ERR(data)) { 70 IWL_DEBUG_FW(trans, 71 "PNVM UEFI variable not found 0x%lx (len %lu)\n", 72 PTR_ERR(data), package_size); 73 return data; 74 } 75 76 IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %lu\n", package_size); 77 *len = package_size; 78 79 return data; 80 } 81 82 static void * 83 iwl_uefi_get_verified_variable_guid(struct iwl_trans *trans, 84 efi_guid_t *guid, 85 efi_char16_t *uefi_var_name, 86 char *var_name, 87 unsigned int expected_size, 88 unsigned long *size) 89 { 90 void *var; 91 unsigned long var_size; 92 93 var = iwl_uefi_get_variable(uefi_var_name, guid, &var_size); 94 95 if (IS_ERR(var)) { 96 IWL_DEBUG_RADIO(trans, 97 "%s UEFI variable not found 0x%lx\n", var_name, 98 PTR_ERR(var)); 99 return var; 100 } 101 102 if (var_size < expected_size) { 103 IWL_DEBUG_RADIO(trans, 104 "Invalid %s UEFI variable len (%lu)\n", 105 var_name, var_size); 106 kfree(var); 107 return ERR_PTR(-EINVAL); 108 } 109 110 IWL_DEBUG_RADIO(trans, "%s from UEFI with size %lu\n", var_name, 111 var_size); 112 113 if (size) 114 *size = var_size; 115 return var; 116 } 117 118 static void * 119 iwl_uefi_get_verified_variable(struct iwl_trans *trans, 120 efi_char16_t *uefi_var_name, 121 char *var_name, 122 unsigned int expected_size, 123 unsigned long *size) 124 { 125 return iwl_uefi_get_verified_variable_guid(trans, &IWL_EFI_WIFI_GUID, 126 uefi_var_name, var_name, 127 expected_size, size); 128 } 129 130 int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, 131 u32 tlv_len, struct iwl_pnvm_image *pnvm_data) 132 { 133 const struct iwl_uefi_pnvm_mem_desc *desc = (const void *)data; 134 u32 data_len; 135 136 if (tlv_len < sizeof(*desc)) { 137 IWL_DEBUG_FW(trans, "TLV len (%d) is too small\n", tlv_len); 138 return -EINVAL; 139 } 140 141 data_len = tlv_len - sizeof(*desc); 142 143 IWL_DEBUG_FW(trans, 144 "Handle IWL_UCODE_TLV_MEM_DESC, len %d data_len %d\n", 145 tlv_len, data_len); 146 147 if (le32_to_cpu(desc->size) != data_len) { 148 IWL_DEBUG_FW(trans, "invalid mem desc size %d\n", desc->size); 149 return -EINVAL; 150 } 151 152 if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { 153 IWL_DEBUG_FW(trans, "too many payloads to allocate in DRAM.\n"); 154 return -EINVAL; 155 } 156 157 IWL_DEBUG_FW(trans, "Adding data (size %d)\n", data_len); 158 159 pnvm_data->chunks[pnvm_data->n_chunks].data = desc->data; 160 pnvm_data->chunks[pnvm_data->n_chunks].len = data_len; 161 pnvm_data->n_chunks++; 162 163 return 0; 164 } 165 166 static int iwl_uefi_reduce_power_section(struct iwl_trans *trans, 167 const u8 *data, size_t len, 168 struct iwl_pnvm_image *pnvm_data) 169 { 170 const struct iwl_ucode_tlv *tlv; 171 172 IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n"); 173 memset(pnvm_data, 0, sizeof(*pnvm_data)); 174 175 while (len >= sizeof(*tlv)) { 176 u32 tlv_len, tlv_type; 177 178 len -= sizeof(*tlv); 179 tlv = (const void *)data; 180 181 tlv_len = le32_to_cpu(tlv->length); 182 tlv_type = le32_to_cpu(tlv->type); 183 184 if (len < tlv_len) { 185 IWL_ERR(trans, "invalid TLV len: %zd/%u\n", 186 len, tlv_len); 187 return -EINVAL; 188 } 189 190 data += sizeof(*tlv); 191 192 switch (tlv_type) { 193 case IWL_UCODE_TLV_MEM_DESC: 194 if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len, 195 pnvm_data)) 196 return -EINVAL; 197 break; 198 case IWL_UCODE_TLV_PNVM_SKU: 199 IWL_DEBUG_FW(trans, 200 "New REDUCE_POWER section started, stop parsing.\n"); 201 goto done; 202 default: 203 IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n", 204 tlv_type, tlv_len); 205 break; 206 } 207 208 len -= ALIGN(tlv_len, 4); 209 data += ALIGN(tlv_len, 4); 210 } 211 212 done: 213 if (!pnvm_data->n_chunks) { 214 IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n"); 215 return -ENOENT; 216 } 217 return 0; 218 } 219 220 int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, 221 const u8 *data, size_t len, 222 struct iwl_pnvm_image *pnvm_data, 223 __le32 sku_id[3]) 224 { 225 const struct iwl_ucode_tlv *tlv; 226 227 IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n"); 228 229 while (len >= sizeof(*tlv)) { 230 u32 tlv_len, tlv_type; 231 232 len -= sizeof(*tlv); 233 tlv = (const void *)data; 234 235 tlv_len = le32_to_cpu(tlv->length); 236 tlv_type = le32_to_cpu(tlv->type); 237 238 if (len < tlv_len) { 239 IWL_ERR(trans, "invalid TLV len: %zd/%u\n", 240 len, tlv_len); 241 return -EINVAL; 242 } 243 244 if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) { 245 const struct iwl_sku_id *tlv_sku_id = 246 (const void *)(data + sizeof(*tlv)); 247 248 IWL_DEBUG_FW(trans, 249 "Got IWL_UCODE_TLV_PNVM_SKU len %d\n", 250 tlv_len); 251 IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n", 252 le32_to_cpu(tlv_sku_id->data[0]), 253 le32_to_cpu(tlv_sku_id->data[1]), 254 le32_to_cpu(tlv_sku_id->data[2])); 255 256 data += sizeof(*tlv) + ALIGN(tlv_len, 4); 257 len -= ALIGN(tlv_len, 4); 258 259 if (sku_id[0] == tlv_sku_id->data[0] && 260 sku_id[1] == tlv_sku_id->data[1] && 261 sku_id[2] == tlv_sku_id->data[2]) { 262 int ret = iwl_uefi_reduce_power_section(trans, 263 data, len, 264 pnvm_data); 265 if (!ret) 266 return 0; 267 } else { 268 IWL_DEBUG_FW(trans, "SKU ID didn't match!\n"); 269 } 270 } else { 271 data += sizeof(*tlv) + ALIGN(tlv_len, 4); 272 len -= ALIGN(tlv_len, 4); 273 } 274 } 275 276 return -ENOENT; 277 } 278 279 u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) 280 { 281 struct pnvm_sku_package *package; 282 unsigned long package_size; 283 u8 *data; 284 285 package = iwl_uefi_get_verified_variable(trans, 286 IWL_UEFI_REDUCED_POWER_NAME, 287 "Reduced Power", 288 sizeof(*package), 289 &package_size); 290 if (IS_ERR(package)) 291 return ERR_CAST(package); 292 293 IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n", 294 package->rev, package->total_size, package->n_skus); 295 296 *len = package_size - sizeof(*package); 297 data = kmemdup(package->data, *len, GFP_KERNEL); 298 if (!data) { 299 kfree(package); 300 return ERR_PTR(-ENOMEM); 301 } 302 303 kfree(package); 304 305 return data; 306 } 307 308 static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_data, 309 struct iwl_trans *trans) 310 { 311 if (common_step_data->revision != 1) 312 return -EINVAL; 313 314 trans->conf.mbx_addr_0_step = 315 (u32)common_step_data->revision | 316 (u32)common_step_data->cnvi_eq_channel << 8 | 317 (u32)common_step_data->cnvr_eq_channel << 16 | 318 (u32)common_step_data->radio1 << 24; 319 trans->conf.mbx_addr_1_step = (u32)common_step_data->radio2; 320 return 0; 321 } 322 323 void iwl_uefi_get_step_table(struct iwl_trans *trans) 324 { 325 struct uefi_cnv_common_step_data *data; 326 int ret; 327 328 if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) 329 return; 330 331 data = iwl_uefi_get_verified_variable_guid(trans, &IWL_EFI_WIFI_BT_GUID, 332 IWL_UEFI_STEP_NAME, 333 "STEP", sizeof(*data), NULL); 334 if (IS_ERR(data)) 335 return; 336 337 ret = iwl_uefi_step_parse(data, trans); 338 if (ret < 0) 339 IWL_DEBUG_FW(trans, "Cannot read STEP tables. rev is invalid\n"); 340 341 kfree(data); 342 } 343 IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table); 344 345 static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data, 346 struct iwl_fw_runtime *fwrt) 347 { 348 int i, j; 349 350 if (sgom_data->revision != 1) 351 return -EINVAL; 352 353 memcpy(fwrt->sgom_table.offset_map, sgom_data->offset_map, 354 sizeof(fwrt->sgom_table.offset_map)); 355 356 for (i = 0; i < MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE; i++) { 357 for (j = 0; j < MCC_TO_SAR_OFFSET_TABLE_COL_SIZE; j++) { 358 /* since each byte is composed of to values, */ 359 /* one for each letter, */ 360 /* extract and check each of them separately */ 361 u8 value = fwrt->sgom_table.offset_map[i][j]; 362 u8 low = value & 0xF; 363 u8 high = (value & 0xF0) >> 4; 364 365 if (high > fwrt->geo_num_profiles) 366 high = 0; 367 if (low > fwrt->geo_num_profiles) 368 low = 0; 369 fwrt->sgom_table.offset_map[i][j] = (high << 4) | low; 370 } 371 } 372 373 fwrt->sgom_enabled = true; 374 return 0; 375 } 376 377 void iwl_uefi_get_sgom_table(struct iwl_trans *trans, 378 struct iwl_fw_runtime *fwrt) 379 { 380 struct uefi_cnv_wlan_sgom_data *data; 381 int ret; 382 383 if (!fwrt->geo_enabled) 384 return; 385 386 data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_SGOM_NAME, 387 "SGOM", sizeof(*data), NULL); 388 if (IS_ERR(data)) 389 return; 390 391 ret = iwl_uefi_sgom_parse(data, fwrt); 392 if (ret < 0) 393 IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n"); 394 395 kfree(data); 396 } 397 IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table); 398 399 static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data, 400 struct iwl_fw_runtime *fwrt) 401 { 402 if (uats_data->revision != 1) 403 return -EINVAL; 404 405 memcpy(fwrt->uats_table.offset_map, uats_data->offset_map, 406 sizeof(fwrt->uats_table.offset_map)); 407 408 fwrt->uats_valid = true; 409 410 return 0; 411 } 412 413 void iwl_uefi_get_uats_table(struct iwl_trans *trans, 414 struct iwl_fw_runtime *fwrt) 415 { 416 struct uefi_cnv_wlan_uats_data *data; 417 int ret; 418 419 data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UATS_NAME, 420 "UATS", sizeof(*data), NULL); 421 if (IS_ERR(data)) 422 return; 423 424 ret = iwl_uefi_uats_parse(data, fwrt); 425 if (ret < 0) 426 IWL_DEBUG_FW(trans, "Cannot read UATS table. rev is invalid\n"); 427 kfree(data); 428 } 429 IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table); 430 431 static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, 432 struct uefi_sar_profile *uefi_sar_prof, 433 u8 prof_index, bool enabled) 434 { 435 memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof, 436 sizeof(struct uefi_sar_profile)); 437 438 fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK; 439 } 440 441 int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) 442 { 443 struct uefi_cnv_var_wrds *data; 444 int ret = 0; 445 446 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME, 447 "WRDS", sizeof(*data), NULL); 448 if (IS_ERR(data)) 449 return -EINVAL; 450 451 if (data->revision != IWL_UEFI_WRDS_REVISION) { 452 ret = -EINVAL; 453 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n", 454 data->revision); 455 goto out; 456 } 457 458 /* The profile from WRDS is officially profile 1, but goes 459 * into sar_profiles[0] (because we don't have a profile 0). 460 */ 461 iwl_uefi_set_sar_profile(fwrt, &data->sar_profile, 0, data->mode); 462 out: 463 kfree(data); 464 return ret; 465 } 466 467 int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) 468 { 469 struct uefi_cnv_var_ewrd *data; 470 int i, ret = 0; 471 472 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME, 473 "EWRD", sizeof(*data), NULL); 474 if (IS_ERR(data)) 475 return -EINVAL; 476 477 if (data->revision != IWL_UEFI_EWRD_REVISION) { 478 ret = -EINVAL; 479 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n", 480 data->revision); 481 goto out; 482 } 483 484 if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { 485 ret = -EINVAL; 486 goto out; 487 } 488 489 for (i = 0; i < data->num_profiles; i++) 490 /* The EWRD profiles officially go from 2 to 4, but we 491 * save them in sar_profiles[1-3] (because we don't 492 * have profile 0). So in the array we start from 1. 493 */ 494 iwl_uefi_set_sar_profile(fwrt, &data->sar_profiles[i], i + 1, 495 data->mode); 496 497 out: 498 kfree(data); 499 return ret; 500 } 501 502 int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) 503 { 504 struct uefi_cnv_var_wgds *data; 505 int i, ret = 0; 506 507 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME, 508 "WGDS", sizeof(*data), NULL); 509 if (IS_ERR(data)) 510 return -EINVAL; 511 512 if (data->revision != IWL_UEFI_WGDS_REVISION) { 513 ret = -EINVAL; 514 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n", 515 data->revision); 516 goto out; 517 } 518 519 if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM || 520 data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) { 521 ret = -EINVAL; 522 IWL_DEBUG_RADIO(fwrt, "Invalid number of profiles in WGDS: %d\n", 523 data->num_profiles); 524 goto out; 525 } 526 527 fwrt->geo_rev = data->revision; 528 for (i = 0; i < data->num_profiles; i++) 529 memcpy(&fwrt->geo_profiles[i], &data->geo_profiles[i], 530 sizeof(struct iwl_geo_profile)); 531 532 fwrt->geo_num_profiles = data->num_profiles; 533 fwrt->geo_enabled = true; 534 out: 535 kfree(data); 536 return ret; 537 } 538 539 int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) 540 { 541 struct uefi_cnv_var_ppag *data; 542 int ret = 0; 543 544 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME, 545 "PPAG", sizeof(*data), NULL); 546 if (IS_ERR(data)) 547 return -EINVAL; 548 549 if (data->revision < IWL_UEFI_MIN_PPAG_REV || 550 data->revision > IWL_UEFI_MAX_PPAG_REV) { 551 ret = -EINVAL; 552 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PPAG revision:%d\n", 553 data->revision); 554 goto out; 555 } 556 557 fwrt->ppag_bios_rev = data->revision; 558 fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes, 559 fwrt->ppag_bios_rev); 560 561 BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains)); 562 memcpy(&fwrt->ppag_chains, &data->ppag_chains, 563 sizeof(data->ppag_chains)); 564 fwrt->ppag_bios_source = BIOS_SOURCE_UEFI; 565 out: 566 kfree(data); 567 return ret; 568 } 569 570 int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, 571 struct iwl_tas_data *tas_data) 572 { 573 struct uefi_cnv_var_wtas *uefi_tas; 574 int ret, enabled; 575 576 uefi_tas = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WTAS_NAME, 577 "WTAS", sizeof(*uefi_tas), NULL); 578 if (IS_ERR(uefi_tas)) 579 return -EINVAL; 580 581 if (uefi_tas->revision < IWL_UEFI_MIN_WTAS_REVISION || 582 uefi_tas->revision > IWL_UEFI_MAX_WTAS_REVISION) { 583 ret = -EINVAL; 584 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WTAS revision:%d\n", 585 uefi_tas->revision); 586 goto out; 587 } 588 589 IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n", 590 uefi_tas->tas_selection); 591 592 enabled = uefi_tas->tas_selection & IWL_WTAS_ENABLED_MSK; 593 tas_data->table_source = BIOS_SOURCE_UEFI; 594 tas_data->table_revision = uefi_tas->revision; 595 tas_data->tas_selection = uefi_tas->tas_selection; 596 597 IWL_DEBUG_RADIO(fwrt, "TAS %s enabled\n", 598 enabled ? "is" : "not"); 599 600 IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", 601 uefi_tas->revision); 602 if (uefi_tas->black_list_size > IWL_WTAS_BLACK_LIST_MAX) { 603 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %d\n", 604 uefi_tas->black_list_size); 605 ret = -EINVAL; 606 goto out; 607 } 608 609 tas_data->block_list_size = uefi_tas->black_list_size; 610 IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", uefi_tas->black_list_size); 611 612 for (u8 i = 0; i < uefi_tas->black_list_size; i++) { 613 tas_data->block_list_array[i] = uefi_tas->black_list[i]; 614 IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", 615 uefi_tas->black_list[i]); 616 } 617 ret = enabled; 618 out: 619 kfree(uefi_tas); 620 return ret; 621 } 622 623 int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, 624 u64 *dflt_pwr_limit) 625 { 626 struct uefi_cnv_var_splc *data; 627 int ret = 0; 628 629 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_SPLC_NAME, 630 "SPLC", sizeof(*data), NULL); 631 if (IS_ERR(data)) 632 return -EINVAL; 633 634 if (data->revision != IWL_UEFI_SPLC_REVISION) { 635 ret = -EINVAL; 636 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI SPLC revision:%d\n", 637 data->revision); 638 goto out; 639 } 640 *dflt_pwr_limit = data->default_pwr_limit; 641 out: 642 kfree(data); 643 return ret; 644 } 645 646 int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) 647 { 648 struct uefi_cnv_var_wrdd *data; 649 int ret = 0; 650 651 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDD_NAME, 652 "WRDD", sizeof(*data), NULL); 653 if (IS_ERR(data)) 654 return -EINVAL; 655 656 if (data->revision != IWL_UEFI_WRDD_REVISION) { 657 ret = -EINVAL; 658 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n", 659 data->revision); 660 goto out; 661 } 662 663 if (data->mcc != BIOS_MCC_CHINA) { 664 ret = -EINVAL; 665 IWL_DEBUG_RADIO(fwrt, "UEFI WRDD is supported only for CN\n"); 666 goto out; 667 } 668 669 mcc[0] = (data->mcc >> 8) & 0xff; 670 mcc[1] = data->mcc & 0xff; 671 mcc[2] = '\0'; 672 out: 673 kfree(data); 674 return ret; 675 } 676 677 int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) 678 { 679 struct uefi_cnv_var_eckv *data; 680 int ret = 0; 681 682 data = iwl_uefi_get_verified_variable_guid(fwrt->trans, 683 &IWL_EFI_WIFI_BT_GUID, 684 IWL_UEFI_ECKV_NAME, 685 "ECKV", sizeof(*data), NULL); 686 if (IS_ERR(data)) 687 return -EINVAL; 688 689 if (data->revision != IWL_UEFI_ECKV_REVISION) { 690 ret = -EINVAL; 691 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI ECKV revision:%d\n", 692 data->revision); 693 goto out; 694 } 695 *extl_clk = data->ext_clock_valid; 696 out: 697 kfree(data); 698 return ret; 699 } 700 701 int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value) 702 { 703 struct uefi_cnv_wlan_wbem_data *data; 704 int ret = 0; 705 706 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WBEM_NAME, 707 "WBEM", sizeof(*data), NULL); 708 if (IS_ERR(data)) 709 return -EINVAL; 710 711 if (data->revision != IWL_UEFI_WBEM_REVISION) { 712 ret = -EINVAL; 713 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WBEM revision:%d\n", 714 data->revision); 715 goto out; 716 } 717 *value = data->wbem_320mhz_per_mcc & IWL_UEFI_WBEM_REV0_MASK; 718 IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from UEFI\n"); 719 out: 720 kfree(data); 721 return ret; 722 } 723 724 int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, 725 u32 *value) 726 { 727 struct uefi_cnv_var_general_cfg *data; 728 int ret = -EINVAL; 729 730 /* Not supported function index */ 731 if (func >= DSM_FUNC_NUM_FUNCS || func == 5) 732 return -EOPNOTSUPP; 733 734 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME, 735 "DSM", sizeof(*data), NULL); 736 if (IS_ERR(data)) 737 return -EINVAL; 738 739 if (data->revision != IWL_UEFI_DSM_REVISION) { 740 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSM revision:%d\n", 741 data->revision); 742 goto out; 743 } 744 745 if (ARRAY_SIZE(data->functions) != UEFI_MAX_DSM_FUNCS) { 746 IWL_DEBUG_RADIO(fwrt, "Invalid size of DSM functions array\n"); 747 goto out; 748 } 749 750 if (!(data->functions[DSM_FUNC_QUERY] & BIT(func))) { 751 IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", 752 func, data->functions[DSM_FUNC_QUERY]); 753 goto out; 754 } 755 756 *value = data->functions[func]; 757 758 IWL_DEBUG_RADIO(fwrt, 759 "UEFI: DSM func=%d: value=%d\n", func, *value); 760 761 ret = 0; 762 out: 763 kfree(data); 764 return ret; 765 } 766 767 int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt) 768 { 769 struct uefi_cnv_var_puncturing_data *data; 770 /* default value is not enabled if there is any issue in reading 771 * uefi variable or revision is not supported 772 */ 773 int puncturing = 0; 774 775 data = iwl_uefi_get_verified_variable(fwrt->trans, 776 IWL_UEFI_PUNCTURING_NAME, 777 "UefiCnvWlanPuncturing", 778 sizeof(*data), NULL); 779 if (IS_ERR(data)) 780 return puncturing; 781 782 if (data->revision != IWL_UEFI_PUNCTURING_REVISION) { 783 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PUNCTURING rev:%d\n", 784 data->revision); 785 } else { 786 puncturing = data->puncturing & IWL_UEFI_PUNCTURING_REV0_MASK; 787 IWL_DEBUG_RADIO(fwrt, "Loaded puncturing bits from UEFI: %d\n", 788 puncturing); 789 } 790 791 kfree(data); 792 return puncturing; 793 } 794 IWL_EXPORT_SYMBOL(iwl_uefi_get_puncturing); 795 796 int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value) 797 { 798 struct uefi_cnv_wlan_dsbr_data *data; 799 int ret = 0; 800 801 data = iwl_uefi_get_verified_variable_guid(fwrt->trans, 802 &IWL_EFI_WIFI_BT_GUID, 803 IWL_UEFI_DSBR_NAME, "DSBR", 804 sizeof(*data), NULL); 805 if (IS_ERR(data)) 806 return -EINVAL; 807 808 if (data->revision != IWL_UEFI_DSBR_REVISION) { 809 ret = -EINVAL; 810 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSBR revision:%d\n", 811 data->revision); 812 goto out; 813 } 814 *value = data->config; 815 IWL_DEBUG_RADIO(fwrt, "Loaded DSBR config from UEFI value: 0x%x\n", 816 *value); 817 out: 818 kfree(data); 819 return ret; 820 } 821 822 int iwl_uefi_get_phy_filters(struct iwl_fw_runtime *fwrt) 823 { 824 struct uefi_cnv_wpfc_data *data __free(kfree); 825 struct iwl_phy_specific_cfg *filters = &fwrt->phy_filters; 826 827 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WPFC_NAME, 828 "WPFC", sizeof(*data), NULL); 829 if (IS_ERR(data)) 830 return -EINVAL; 831 832 if (data->revision != 0) { 833 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WPFC revision:%d\n", 834 data->revision); 835 return -EINVAL; 836 } 837 838 BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) != 839 ARRAY_SIZE(data->chains)); 840 841 for (int i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) { 842 filters->filter_cfg_chains[i] = cpu_to_le32(data->chains[i]); 843 IWL_DEBUG_RADIO(fwrt, "WPFC: chain %d: %u\n", i, data->chains[i]); 844 } 845 846 IWL_DEBUG_RADIO(fwrt, "Loaded WPFC config from UEFI\n"); 847 return 0; 848 } 849