1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright(c) 2021-2024 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 return 0; 406 } 407 408 int iwl_uefi_get_uats_table(struct iwl_trans *trans, 409 struct iwl_fw_runtime *fwrt) 410 { 411 struct uefi_cnv_wlan_uats_data *data; 412 int ret; 413 414 data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UATS_NAME, 415 "UATS", sizeof(*data), NULL); 416 if (IS_ERR(data)) 417 return -EINVAL; 418 419 ret = iwl_uefi_uats_parse(data, fwrt); 420 if (ret < 0) { 421 IWL_DEBUG_FW(trans, "Cannot read UATS table. rev is invalid\n"); 422 kfree(data); 423 return ret; 424 } 425 426 kfree(data); 427 return 0; 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_ver = data->revision; 558 fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes, 559 fwrt->ppag_ver); 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 out: 565 kfree(data); 566 return ret; 567 } 568 569 int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, 570 struct iwl_tas_data *tas_data) 571 { 572 struct uefi_cnv_var_wtas *uefi_tas; 573 int ret, enabled; 574 575 uefi_tas = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WTAS_NAME, 576 "WTAS", sizeof(*uefi_tas), NULL); 577 if (IS_ERR(uefi_tas)) 578 return -EINVAL; 579 580 if (uefi_tas->revision < IWL_UEFI_MIN_WTAS_REVISION || 581 uefi_tas->revision > IWL_UEFI_MAX_WTAS_REVISION) { 582 ret = -EINVAL; 583 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WTAS revision:%d\n", 584 uefi_tas->revision); 585 goto out; 586 } 587 588 IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n", 589 uefi_tas->tas_selection); 590 591 enabled = uefi_tas->tas_selection & IWL_WTAS_ENABLED_MSK; 592 tas_data->table_source = BIOS_SOURCE_UEFI; 593 tas_data->table_revision = uefi_tas->revision; 594 tas_data->tas_selection = uefi_tas->tas_selection; 595 596 IWL_DEBUG_RADIO(fwrt, "TAS %s enabled\n", 597 enabled ? "is" : "not"); 598 599 IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", 600 uefi_tas->revision); 601 if (uefi_tas->black_list_size > IWL_WTAS_BLACK_LIST_MAX) { 602 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %d\n", 603 uefi_tas->black_list_size); 604 ret = -EINVAL; 605 goto out; 606 } 607 608 tas_data->block_list_size = uefi_tas->black_list_size; 609 IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", uefi_tas->black_list_size); 610 611 for (u8 i = 0; i < uefi_tas->black_list_size; i++) { 612 tas_data->block_list_array[i] = uefi_tas->black_list[i]; 613 IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", 614 uefi_tas->black_list[i]); 615 } 616 ret = enabled; 617 out: 618 kfree(uefi_tas); 619 return ret; 620 } 621 622 int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, 623 u64 *dflt_pwr_limit) 624 { 625 struct uefi_cnv_var_splc *data; 626 int ret = 0; 627 628 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_SPLC_NAME, 629 "SPLC", sizeof(*data), NULL); 630 if (IS_ERR(data)) 631 return -EINVAL; 632 633 if (data->revision != IWL_UEFI_SPLC_REVISION) { 634 ret = -EINVAL; 635 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI SPLC revision:%d\n", 636 data->revision); 637 goto out; 638 } 639 *dflt_pwr_limit = data->default_pwr_limit; 640 out: 641 kfree(data); 642 return ret; 643 } 644 645 int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) 646 { 647 struct uefi_cnv_var_wrdd *data; 648 int ret = 0; 649 650 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDD_NAME, 651 "WRDD", sizeof(*data), NULL); 652 if (IS_ERR(data)) 653 return -EINVAL; 654 655 if (data->revision != IWL_UEFI_WRDD_REVISION) { 656 ret = -EINVAL; 657 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n", 658 data->revision); 659 goto out; 660 } 661 662 if (data->mcc != BIOS_MCC_CHINA) { 663 ret = -EINVAL; 664 IWL_DEBUG_RADIO(fwrt, "UEFI WRDD is supported only for CN\n"); 665 goto out; 666 } 667 668 mcc[0] = (data->mcc >> 8) & 0xff; 669 mcc[1] = data->mcc & 0xff; 670 mcc[2] = '\0'; 671 out: 672 kfree(data); 673 return ret; 674 } 675 676 int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) 677 { 678 struct uefi_cnv_var_eckv *data; 679 int ret = 0; 680 681 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_ECKV_NAME, 682 "ECKV", sizeof(*data), NULL); 683 if (IS_ERR(data)) 684 return -EINVAL; 685 686 if (data->revision != IWL_UEFI_ECKV_REVISION) { 687 ret = -EINVAL; 688 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n", 689 data->revision); 690 goto out; 691 } 692 *extl_clk = data->ext_clock_valid; 693 out: 694 kfree(data); 695 return ret; 696 } 697 698 int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value) 699 { 700 struct uefi_cnv_wlan_wbem_data *data; 701 int ret = 0; 702 703 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WBEM_NAME, 704 "WBEM", sizeof(*data), NULL); 705 if (IS_ERR(data)) 706 return -EINVAL; 707 708 if (data->revision != IWL_UEFI_WBEM_REVISION) { 709 ret = -EINVAL; 710 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WBEM revision:%d\n", 711 data->revision); 712 goto out; 713 } 714 *value = data->wbem_320mhz_per_mcc & IWL_UEFI_WBEM_REV0_MASK; 715 IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from UEFI\n"); 716 out: 717 kfree(data); 718 return ret; 719 } 720 721 int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, 722 u32 *value) 723 { 724 struct uefi_cnv_var_general_cfg *data; 725 int ret = -EINVAL; 726 727 /* Not supported function index */ 728 if (func >= DSM_FUNC_NUM_FUNCS || func == 5) 729 return -EOPNOTSUPP; 730 731 data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME, 732 "DSM", sizeof(*data), NULL); 733 if (IS_ERR(data)) 734 return -EINVAL; 735 736 if (data->revision != IWL_UEFI_DSM_REVISION) { 737 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSM revision:%d\n", 738 data->revision); 739 goto out; 740 } 741 742 if (ARRAY_SIZE(data->functions) != UEFI_MAX_DSM_FUNCS) { 743 IWL_DEBUG_RADIO(fwrt, "Invalid size of DSM functions array\n"); 744 goto out; 745 } 746 747 *value = data->functions[func]; 748 ret = 0; 749 out: 750 kfree(data); 751 return ret; 752 } 753 754 int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt) 755 { 756 struct uefi_cnv_var_puncturing_data *data; 757 /* default value is not enabled if there is any issue in reading 758 * uefi variable or revision is not supported 759 */ 760 int puncturing = 0; 761 762 data = iwl_uefi_get_verified_variable(fwrt->trans, 763 IWL_UEFI_PUNCTURING_NAME, 764 "UefiCnvWlanPuncturing", 765 sizeof(*data), NULL); 766 if (IS_ERR(data)) 767 return puncturing; 768 769 if (data->revision != IWL_UEFI_PUNCTURING_REVISION) { 770 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PUNCTURING rev:%d\n", 771 data->revision); 772 } else { 773 puncturing = data->puncturing & IWL_UEFI_PUNCTURING_REV0_MASK; 774 IWL_DEBUG_RADIO(fwrt, "Loaded puncturing bits from UEFI: %d\n", 775 puncturing); 776 } 777 778 kfree(data); 779 return puncturing; 780 } 781 IWL_EXPORT_SYMBOL(iwl_uefi_get_puncturing); 782 783 int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value) 784 { 785 struct uefi_cnv_wlan_dsbr_data *data; 786 int ret = 0; 787 788 data = iwl_uefi_get_verified_variable_guid(fwrt->trans, 789 &IWL_EFI_WIFI_BT_GUID, 790 IWL_UEFI_DSBR_NAME, "DSBR", 791 sizeof(*data), NULL); 792 if (IS_ERR(data)) 793 return -EINVAL; 794 795 if (data->revision != IWL_UEFI_DSBR_REVISION) { 796 ret = -EINVAL; 797 IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSBR revision:%d\n", 798 data->revision); 799 goto out; 800 } 801 *value = data->config; 802 IWL_DEBUG_RADIO(fwrt, "Loaded DSBR config from UEFI value: 0x%x\n", 803 *value); 804 out: 805 kfree(data); 806 return ret; 807 } 808