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 { 224 const struct iwl_ucode_tlv *tlv; 225 226 IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n"); 227 228 while (len >= sizeof(*tlv)) { 229 u32 tlv_len, tlv_type; 230 231 len -= sizeof(*tlv); 232 tlv = (const void *)data; 233 234 tlv_len = le32_to_cpu(tlv->length); 235 tlv_type = le32_to_cpu(tlv->type); 236 237 if (len < tlv_len) { 238 IWL_ERR(trans, "invalid TLV len: %zd/%u\n", 239 len, tlv_len); 240 return -EINVAL; 241 } 242 243 if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) { 244 const struct iwl_sku_id *sku_id = 245 (const void *)(data + sizeof(*tlv)); 246 247 IWL_DEBUG_FW(trans, 248 "Got IWL_UCODE_TLV_PNVM_SKU len %d\n", 249 tlv_len); 250 IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n", 251 le32_to_cpu(sku_id->data[0]), 252 le32_to_cpu(sku_id->data[1]), 253 le32_to_cpu(sku_id->data[2])); 254 255 data += sizeof(*tlv) + ALIGN(tlv_len, 4); 256 len -= ALIGN(tlv_len, 4); 257 258 if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) && 259 trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) && 260 trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { 261 int ret = iwl_uefi_reduce_power_section(trans, 262 data, len, 263 pnvm_data); 264 if (!ret) 265 return 0; 266 } else { 267 IWL_DEBUG_FW(trans, "SKU ID didn't match!\n"); 268 } 269 } else { 270 data += sizeof(*tlv) + ALIGN(tlv_len, 4); 271 len -= ALIGN(tlv_len, 4); 272 } 273 } 274 275 return -ENOENT; 276 } 277 278 u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) 279 { 280 struct pnvm_sku_package *package; 281 unsigned long package_size; 282 u8 *data; 283 284 package = iwl_uefi_get_verified_variable(trans, 285 IWL_UEFI_REDUCED_POWER_NAME, 286 "Reduced Power", 287 sizeof(*package), 288 &package_size); 289 if (IS_ERR(package)) 290 return ERR_CAST(package); 291 292 IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n", 293 package->rev, package->total_size, package->n_skus); 294 295 *len = package_size - sizeof(*package); 296 data = kmemdup(package->data, *len, GFP_KERNEL); 297 if (!data) { 298 kfree(package); 299 return ERR_PTR(-ENOMEM); 300 } 301 302 kfree(package); 303 304 return data; 305 } 306 307 static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_data, 308 struct iwl_trans *trans) 309 { 310 if (common_step_data->revision != 1) 311 return -EINVAL; 312 313 trans->mbx_addr_0_step = (u32)common_step_data->revision | 314 (u32)common_step_data->cnvi_eq_channel << 8 | 315 (u32)common_step_data->cnvr_eq_channel << 16 | 316 (u32)common_step_data->radio1 << 24; 317 trans->mbx_addr_1_step = (u32)common_step_data->radio2; 318 return 0; 319 } 320 321 void iwl_uefi_get_step_table(struct iwl_trans *trans) 322 { 323 struct uefi_cnv_common_step_data *data; 324 int ret; 325 326 if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) 327 return; 328 329 data = iwl_uefi_get_verified_variable_guid(trans, &IWL_EFI_WIFI_BT_GUID, 330 IWL_UEFI_STEP_NAME, 331 "STEP", sizeof(*data), NULL); 332 if (IS_ERR(data)) 333 return; 334 335 ret = iwl_uefi_step_parse(data, trans); 336 if (ret < 0) 337 IWL_DEBUG_FW(trans, "Cannot read STEP tables. rev is invalid\n"); 338 339 kfree(data); 340 } 341 IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table); 342 343 static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data, 344 struct iwl_fw_runtime *fwrt) 345 { 346 int i, j; 347 348 if (sgom_data->revision != 1) 349 return -EINVAL; 350 351 memcpy(fwrt->sgom_table.offset_map, sgom_data->offset_map, 352 sizeof(fwrt->sgom_table.offset_map)); 353 354 for (i = 0; i < MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE; i++) { 355 for (j = 0; j < MCC_TO_SAR_OFFSET_TABLE_COL_SIZE; j++) { 356 /* since each byte is composed of to values, */ 357 /* one for each letter, */ 358 /* extract and check each of them separately */ 359 u8 value = fwrt->sgom_table.offset_map[i][j]; 360 u8 low = value & 0xF; 361 u8 high = (value & 0xF0) >> 4; 362 363 if (high > fwrt->geo_num_profiles) 364 high = 0; 365 if (low > fwrt->geo_num_profiles) 366 low = 0; 367 fwrt->sgom_table.offset_map[i][j] = (high << 4) | low; 368 } 369 } 370 371 fwrt->sgom_enabled = true; 372 return 0; 373 } 374 375 void iwl_uefi_get_sgom_table(struct iwl_trans *trans, 376 struct iwl_fw_runtime *fwrt) 377 { 378 struct uefi_cnv_wlan_sgom_data *data; 379 int ret; 380 381 if (!fwrt->geo_enabled) 382 return; 383 384 data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_SGOM_NAME, 385 "SGOM", sizeof(*data), NULL); 386 if (IS_ERR(data)) 387 return; 388 389 ret = iwl_uefi_sgom_parse(data, fwrt); 390 if (ret < 0) 391 IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n"); 392 393 kfree(data); 394 } 395 IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table); 396 397 static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data, 398 struct iwl_fw_runtime *fwrt) 399 { 400 if (uats_data->revision != 1) 401 return -EINVAL; 402 403 memcpy(fwrt->uats_table.offset_map, uats_data->offset_map, 404 sizeof(fwrt->uats_table.offset_map)); 405 406 fwrt->uats_valid = true; 407 408 return 0; 409 } 410 411 int iwl_uefi_get_uats_table(struct iwl_trans *trans, 412 struct iwl_fw_runtime *fwrt) 413 { 414 struct uefi_cnv_wlan_uats_data *data; 415 int ret; 416 417 data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UATS_NAME, 418 "UATS", sizeof(*data), NULL); 419 if (IS_ERR(data)) 420 return -EINVAL; 421 422 ret = iwl_uefi_uats_parse(data, fwrt); 423 if (ret < 0) { 424 IWL_DEBUG_FW(trans, "Cannot read UATS table. rev is invalid\n"); 425 kfree(data); 426 return ret; 427 } 428 429 kfree(data); 430 return 0; 431 } 432 IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table); 433 434 static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, 435 struct uefi_sar_profile *uefi_sar_prof, 436 u8 prof_index, bool enabled) 437 { 438 memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof, 439 sizeof(struct uefi_sar_profile)); 440 441 fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK; 442 } 443 444 int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) 445 { 446 struct uefi_cnv_var_wrds *data; 447 int ret = 0; 448 449 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME, 450 "WRDS", sizeof(*data), NULL); 451 if (IS_ERR(data)) 452 return -EINVAL; 453 454 if (data->revision != IWL_UEFI_WRDS_REVISION) { 455 ret = -EINVAL; 456 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n", 457 data->revision); 458 goto out; 459 } 460 461 /* The profile from WRDS is officially profile 1, but goes 462 * into sar_profiles[0] (because we don't have a profile 0). 463 */ 464 iwl_uefi_set_sar_profile(fwrt, &data->sar_profile, 0, data->mode); 465 out: 466 kfree(data); 467 return ret; 468 } 469 470 int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) 471 { 472 struct uefi_cnv_var_ewrd *data; 473 int i, ret = 0; 474 475 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME, 476 "EWRD", sizeof(*data), NULL); 477 if (IS_ERR(data)) 478 return -EINVAL; 479 480 if (data->revision != IWL_UEFI_EWRD_REVISION) { 481 ret = -EINVAL; 482 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n", 483 data->revision); 484 goto out; 485 } 486 487 if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { 488 ret = -EINVAL; 489 goto out; 490 } 491 492 for (i = 0; i < data->num_profiles; i++) 493 /* The EWRD profiles officially go from 2 to 4, but we 494 * save them in sar_profiles[1-3] (because we don't 495 * have profile 0). So in the array we start from 1. 496 */ 497 iwl_uefi_set_sar_profile(fwrt, &data->sar_profiles[i], i + 1, 498 data->mode); 499 500 out: 501 kfree(data); 502 return ret; 503 } 504 505 int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) 506 { 507 struct uefi_cnv_var_wgds *data; 508 int i, ret = 0; 509 510 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME, 511 "WGDS", sizeof(*data), NULL); 512 if (IS_ERR(data)) 513 return -EINVAL; 514 515 if (data->revision != IWL_UEFI_WGDS_REVISION) { 516 ret = -EINVAL; 517 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n", 518 data->revision); 519 goto out; 520 } 521 522 if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM || 523 data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) { 524 ret = -EINVAL; 525 IWL_DEBUG_RADIO(fwrt, "Invalid number of profiles in WGDS: %d\n", 526 data->num_profiles); 527 goto out; 528 } 529 530 fwrt->geo_rev = data->revision; 531 for (i = 0; i < data->num_profiles; i++) 532 memcpy(&fwrt->geo_profiles[i], &data->geo_profiles[i], 533 sizeof(struct iwl_geo_profile)); 534 535 fwrt->geo_num_profiles = data->num_profiles; 536 fwrt->geo_enabled = true; 537 out: 538 kfree(data); 539 return ret; 540 } 541 542 int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) 543 { 544 struct uefi_cnv_var_ppag *data; 545 int ret = 0; 546 547 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME, 548 "PPAG", sizeof(*data), NULL); 549 if (IS_ERR(data)) 550 return -EINVAL; 551 552 if (data->revision < IWL_UEFI_MIN_PPAG_REV || 553 data->revision > IWL_UEFI_MAX_PPAG_REV) { 554 ret = -EINVAL; 555 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PPAG revision:%d\n", 556 data->revision); 557 goto out; 558 } 559 560 fwrt->ppag_ver = data->revision; 561 fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes, 562 fwrt->ppag_ver); 563 564 BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains)); 565 memcpy(&fwrt->ppag_chains, &data->ppag_chains, 566 sizeof(data->ppag_chains)); 567 out: 568 kfree(data); 569 return ret; 570 } 571 572 int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, 573 struct iwl_tas_data *tas_data) 574 { 575 struct uefi_cnv_var_wtas *uefi_tas; 576 int ret, enabled; 577 578 uefi_tas = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WTAS_NAME, 579 "WTAS", sizeof(*uefi_tas), NULL); 580 if (IS_ERR(uefi_tas)) 581 return -EINVAL; 582 583 if (uefi_tas->revision < IWL_UEFI_MIN_WTAS_REVISION || 584 uefi_tas->revision > IWL_UEFI_MAX_WTAS_REVISION) { 585 ret = -EINVAL; 586 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WTAS revision:%d\n", 587 uefi_tas->revision); 588 goto out; 589 } 590 591 IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n", 592 uefi_tas->tas_selection); 593 594 enabled = uefi_tas->tas_selection & IWL_WTAS_ENABLED_MSK; 595 tas_data->table_source = BIOS_SOURCE_UEFI; 596 tas_data->table_revision = uefi_tas->revision; 597 tas_data->tas_selection = uefi_tas->tas_selection; 598 599 IWL_DEBUG_RADIO(fwrt, "TAS %s enabled\n", 600 enabled ? "is" : "not"); 601 602 IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", 603 uefi_tas->revision); 604 if (uefi_tas->black_list_size > IWL_WTAS_BLACK_LIST_MAX) { 605 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %d\n", 606 uefi_tas->black_list_size); 607 ret = -EINVAL; 608 goto out; 609 } 610 611 tas_data->block_list_size = uefi_tas->black_list_size; 612 IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", uefi_tas->black_list_size); 613 614 for (u8 i = 0; i < uefi_tas->black_list_size; i++) { 615 tas_data->block_list_array[i] = uefi_tas->black_list[i]; 616 IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", 617 uefi_tas->black_list[i]); 618 } 619 ret = enabled; 620 out: 621 kfree(uefi_tas); 622 return ret; 623 } 624 625 int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, 626 u64 *dflt_pwr_limit) 627 { 628 struct uefi_cnv_var_splc *data; 629 int ret = 0; 630 631 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_SPLC_NAME, 632 "SPLC", sizeof(*data), NULL); 633 if (IS_ERR(data)) 634 return -EINVAL; 635 636 if (data->revision != IWL_UEFI_SPLC_REVISION) { 637 ret = -EINVAL; 638 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI SPLC revision:%d\n", 639 data->revision); 640 goto out; 641 } 642 *dflt_pwr_limit = data->default_pwr_limit; 643 out: 644 kfree(data); 645 return ret; 646 } 647 648 int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) 649 { 650 struct uefi_cnv_var_wrdd *data; 651 int ret = 0; 652 653 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDD_NAME, 654 "WRDD", sizeof(*data), NULL); 655 if (IS_ERR(data)) 656 return -EINVAL; 657 658 if (data->revision != IWL_UEFI_WRDD_REVISION) { 659 ret = -EINVAL; 660 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n", 661 data->revision); 662 goto out; 663 } 664 665 if (data->mcc != BIOS_MCC_CHINA) { 666 ret = -EINVAL; 667 IWL_DEBUG_RADIO(fwrt, "UEFI WRDD is supported only for CN\n"); 668 goto out; 669 } 670 671 mcc[0] = (data->mcc >> 8) & 0xff; 672 mcc[1] = data->mcc & 0xff; 673 mcc[2] = '\0'; 674 out: 675 kfree(data); 676 return ret; 677 } 678 679 int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) 680 { 681 struct uefi_cnv_var_eckv *data; 682 int ret = 0; 683 684 data = iwl_uefi_get_verified_variable_guid(fwrt->trans, 685 &IWL_EFI_WIFI_BT_GUID, 686 IWL_UEFI_ECKV_NAME, 687 "ECKV", sizeof(*data), NULL); 688 if (IS_ERR(data)) 689 return -EINVAL; 690 691 if (data->revision != IWL_UEFI_ECKV_REVISION) { 692 ret = -EINVAL; 693 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI ECKV revision:%d\n", 694 data->revision); 695 goto out; 696 } 697 *extl_clk = data->ext_clock_valid; 698 out: 699 kfree(data); 700 return ret; 701 } 702 703 int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value) 704 { 705 struct uefi_cnv_wlan_wbem_data *data; 706 int ret = 0; 707 708 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WBEM_NAME, 709 "WBEM", sizeof(*data), NULL); 710 if (IS_ERR(data)) 711 return -EINVAL; 712 713 if (data->revision != IWL_UEFI_WBEM_REVISION) { 714 ret = -EINVAL; 715 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WBEM revision:%d\n", 716 data->revision); 717 goto out; 718 } 719 *value = data->wbem_320mhz_per_mcc & IWL_UEFI_WBEM_REV0_MASK; 720 IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from UEFI\n"); 721 out: 722 kfree(data); 723 return ret; 724 } 725 726 int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, 727 u32 *value) 728 { 729 struct uefi_cnv_var_general_cfg *data; 730 int ret = -EINVAL; 731 732 /* Not supported function index */ 733 if (func >= DSM_FUNC_NUM_FUNCS || func == 5) 734 return -EOPNOTSUPP; 735 736 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME, 737 "DSM", sizeof(*data), NULL); 738 if (IS_ERR(data)) 739 return -EINVAL; 740 741 if (data->revision != IWL_UEFI_DSM_REVISION) { 742 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSM revision:%d\n", 743 data->revision); 744 goto out; 745 } 746 747 if (ARRAY_SIZE(data->functions) != UEFI_MAX_DSM_FUNCS) { 748 IWL_DEBUG_RADIO(fwrt, "Invalid size of DSM functions array\n"); 749 goto out; 750 } 751 752 *value = data->functions[func]; 753 ret = 0; 754 out: 755 kfree(data); 756 return ret; 757 } 758 759 int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt) 760 { 761 struct uefi_cnv_var_puncturing_data *data; 762 /* default value is not enabled if there is any issue in reading 763 * uefi variable or revision is not supported 764 */ 765 int puncturing = 0; 766 767 data = iwl_uefi_get_verified_variable(fwrt->trans, 768 IWL_UEFI_PUNCTURING_NAME, 769 "UefiCnvWlanPuncturing", 770 sizeof(*data), NULL); 771 if (IS_ERR(data)) 772 return puncturing; 773 774 if (data->revision != IWL_UEFI_PUNCTURING_REVISION) { 775 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PUNCTURING rev:%d\n", 776 data->revision); 777 } else { 778 puncturing = data->puncturing & IWL_UEFI_PUNCTURING_REV0_MASK; 779 IWL_DEBUG_RADIO(fwrt, "Loaded puncturing bits from UEFI: %d\n", 780 puncturing); 781 } 782 783 kfree(data); 784 return puncturing; 785 } 786 IWL_EXPORT_SYMBOL(iwl_uefi_get_puncturing); 787 788 int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value) 789 { 790 struct uefi_cnv_wlan_dsbr_data *data; 791 int ret = 0; 792 793 data = iwl_uefi_get_verified_variable_guid(fwrt->trans, 794 &IWL_EFI_WIFI_BT_GUID, 795 IWL_UEFI_DSBR_NAME, "DSBR", 796 sizeof(*data), NULL); 797 if (IS_ERR(data)) 798 return -EINVAL; 799 800 if (data->revision != IWL_UEFI_DSBR_REVISION) { 801 ret = -EINVAL; 802 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSBR revision:%d\n", 803 data->revision); 804 goto out; 805 } 806 *value = data->config; 807 IWL_DEBUG_RADIO(fwrt, "Loaded DSBR config from UEFI value: 0x%x\n", 808 *value); 809 out: 810 kfree(data); 811 return ret; 812 } 813