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