1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright(c) 2021-2024 Intel Corporation
12 #include "fw/api/alive.h"
13 #include <linux/efi.h>
14 #include "fw/runtime.h"
16 #define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \
17 0xb2, 0xec, 0xf5, 0xa3, \
18 0x59, 0x4f, 0x4a, 0xea)
20 struct iwl_uefi_pnvm_mem_desc
{
26 static void *iwl_uefi_get_variable(efi_char16_t
*name
, efi_guid_t
*guid
,
27 unsigned long *data_size
)
33 return ERR_PTR(-EINVAL
);
35 if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE
))
36 return ERR_PTR(-ENODEV
);
38 /* first call with NULL data to get the exact entry size */
40 status
= efi
.get_variable(name
, guid
, NULL
, data_size
, NULL
);
41 if (status
!= EFI_BUFFER_TOO_SMALL
|| !*data_size
)
44 data
= kmalloc(*data_size
, GFP_KERNEL
);
46 return ERR_PTR(-ENOMEM
);
48 status
= efi
.get_variable(name
, guid
, NULL
, data_size
, data
);
49 if (status
!= EFI_SUCCESS
) {
51 return ERR_PTR(-ENOENT
);
57 void *iwl_uefi_get_pnvm(struct iwl_trans
*trans
, size_t *len
)
59 unsigned long package_size
;
64 data
= iwl_uefi_get_variable(IWL_UEFI_OEM_PNVM_NAME
, &IWL_EFI_VAR_GUID
,
68 "PNVM UEFI variable not found 0x%lx (len %lu)\n",
69 PTR_ERR(data
), package_size
);
73 IWL_DEBUG_FW(trans
, "Read PNVM from UEFI with size %lu\n", package_size
);
80 void *iwl_uefi_get_verified_variable(struct iwl_trans
*trans
,
81 efi_char16_t
*uefi_var_name
,
83 unsigned int expected_size
,
87 unsigned long var_size
;
89 var
= iwl_uefi_get_variable(uefi_var_name
, &IWL_EFI_VAR_GUID
,
93 IWL_DEBUG_RADIO(trans
,
94 "%s UEFI variable not found 0x%lx\n", var_name
,
99 if (var_size
< expected_size
) {
100 IWL_DEBUG_RADIO(trans
,
101 "Invalid %s UEFI variable len (%lu)\n",
104 return ERR_PTR(-EINVAL
);
107 IWL_DEBUG_RADIO(trans
, "%s from UEFI with size %lu\n", var_name
,
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
)
118 const struct iwl_uefi_pnvm_mem_desc
*desc
= (const void *)data
;
121 if (tlv_len
< sizeof(*desc
)) {
122 IWL_DEBUG_FW(trans
, "TLV len (%d) is too small\n", tlv_len
);
126 data_len
= tlv_len
- sizeof(*desc
);
129 "Handle IWL_UCODE_TLV_MEM_DESC, len %d data_len %d\n",
132 if (le32_to_cpu(desc
->size
) != data_len
) {
133 IWL_DEBUG_FW(trans
, "invalid mem desc size %d\n", desc
->size
);
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");
142 IWL_DEBUG_FW(trans
, "Adding data (size %d)\n", data_len
);
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
++;
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
)
155 const struct iwl_ucode_tlv
*tlv
;
157 IWL_DEBUG_FW(trans
, "Handling REDUCE_POWER section\n");
158 memset(pnvm_data
, 0, sizeof(*pnvm_data
));
160 while (len
>= sizeof(*tlv
)) {
161 u32 tlv_len
, tlv_type
;
164 tlv
= (const void *)data
;
166 tlv_len
= le32_to_cpu(tlv
->length
);
167 tlv_type
= le32_to_cpu(tlv
->type
);
170 IWL_ERR(trans
, "invalid TLV len: %zd/%u\n",
175 data
+= sizeof(*tlv
);
178 case IWL_UCODE_TLV_MEM_DESC
:
179 if (iwl_uefi_handle_tlv_mem_desc(trans
, data
, tlv_len
,
183 case IWL_UCODE_TLV_PNVM_SKU
:
185 "New REDUCE_POWER section started, stop parsing.\n");
188 IWL_DEBUG_FW(trans
, "Found TLV 0x%0x, len %d\n",
193 len
-= ALIGN(tlv_len
, 4);
194 data
+= ALIGN(tlv_len
, 4);
198 if (!pnvm_data
->n_chunks
) {
199 IWL_DEBUG_FW(trans
, "Empty REDUCE_POWER, skipping.\n");
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
)
209 const struct iwl_ucode_tlv
*tlv
;
211 IWL_DEBUG_FW(trans
, "Parsing REDUCE_POWER data\n");
213 while (len
>= sizeof(*tlv
)) {
214 u32 tlv_len
, tlv_type
;
217 tlv
= (const void *)data
;
219 tlv_len
= le32_to_cpu(tlv
->length
);
220 tlv_type
= le32_to_cpu(tlv
->type
);
223 IWL_ERR(trans
, "invalid TLV len: %zd/%u\n",
228 if (tlv_type
== IWL_UCODE_TLV_PNVM_SKU
) {
229 const struct iwl_sku_id
*sku_id
=
230 (const void *)(data
+ sizeof(*tlv
));
233 "Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
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]));
240 data
+= sizeof(*tlv
) + ALIGN(tlv_len
, 4);
241 len
-= ALIGN(tlv_len
, 4);
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
,
252 IWL_DEBUG_FW(trans
, "SKU ID didn't match!\n");
255 data
+= sizeof(*tlv
) + ALIGN(tlv_len
, 4);
256 len
-= ALIGN(tlv_len
, 4);
263 u8
*iwl_uefi_get_reduced_power(struct iwl_trans
*trans
, size_t *len
)
265 struct pnvm_sku_package
*package
;
266 unsigned long package_size
;
269 package
= iwl_uefi_get_verified_variable(trans
,
270 IWL_UEFI_REDUCED_POWER_NAME
,
275 return ERR_CAST(package
);
277 IWL_DEBUG_FW(trans
, "rev %d, total_size %d, n_skus %d\n",
278 package
->rev
, package
->total_size
, package
->n_skus
);
280 *len
= package_size
- sizeof(*package
);
281 data
= kmemdup(package
->data
, *len
, GFP_KERNEL
);
284 return ERR_PTR(-ENOMEM
);
292 static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data
*common_step_data
,
293 struct iwl_trans
*trans
)
295 if (common_step_data
->revision
!= 1)
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
;
306 void iwl_uefi_get_step_table(struct iwl_trans
*trans
)
308 struct uefi_cnv_common_step_data
*data
;
311 if (trans
->trans_cfg
->device_family
< IWL_DEVICE_FAMILY_AX210
)
314 data
= iwl_uefi_get_verified_variable(trans
, IWL_UEFI_STEP_NAME
,
315 "STEP", sizeof(*data
), NULL
);
319 ret
= iwl_uefi_step_parse(data
, trans
);
321 IWL_DEBUG_FW(trans
, "Cannot read STEP tables. rev is invalid\n");
325 IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table
);
327 static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data
*sgom_data
,
328 struct iwl_fw_runtime
*fwrt
)
332 if (sgom_data
->revision
!= 1)
335 memcpy(fwrt
->sgom_table
.offset_map
, sgom_data
->offset_map
,
336 sizeof(fwrt
->sgom_table
.offset_map
));
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;
347 if (high
> fwrt
->geo_num_profiles
)
349 if (low
> fwrt
->geo_num_profiles
)
351 fwrt
->sgom_table
.offset_map
[i
][j
] = (high
<< 4) | low
;
355 fwrt
->sgom_enabled
= true;
359 void iwl_uefi_get_sgom_table(struct iwl_trans
*trans
,
360 struct iwl_fw_runtime
*fwrt
)
362 struct uefi_cnv_wlan_sgom_data
*data
;
365 if (!fwrt
->geo_enabled
)
368 data
= iwl_uefi_get_verified_variable(trans
, IWL_UEFI_SGOM_NAME
,
369 "SGOM", sizeof(*data
), NULL
);
373 ret
= iwl_uefi_sgom_parse(data
, fwrt
);
375 IWL_DEBUG_FW(trans
, "Cannot read SGOM tables. rev is invalid\n");
379 IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table
);
381 static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data
*uats_data
,
382 struct iwl_fw_runtime
*fwrt
)
384 if (uats_data
->revision
!= 1)
387 memcpy(fwrt
->uats_table
.offset_map
, uats_data
->offset_map
,
388 sizeof(fwrt
->uats_table
.offset_map
));
392 int iwl_uefi_get_uats_table(struct iwl_trans
*trans
,
393 struct iwl_fw_runtime
*fwrt
)
395 struct uefi_cnv_wlan_uats_data
*data
;
398 data
= iwl_uefi_get_verified_variable(trans
, IWL_UEFI_UATS_NAME
,
399 "UATS", sizeof(*data
), NULL
);
403 ret
= iwl_uefi_uats_parse(data
, fwrt
);
405 IWL_DEBUG_FW(trans
, "Cannot read UATS table. rev is invalid\n");
413 IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table
);
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
)
419 memcpy(&fwrt
->sar_profiles
[prof_index
].chains
, uefi_sar_prof
,
420 sizeof(struct uefi_sar_profile
));
422 fwrt
->sar_profiles
[prof_index
].enabled
= enabled
& IWL_SAR_ENABLE_MSK
;
425 int iwl_uefi_get_wrds_table(struct iwl_fw_runtime
*fwrt
)
427 struct uefi_cnv_var_wrds
*data
;
430 data
= iwl_uefi_get_verified_variable(fwrt
->trans
, IWL_UEFI_WRDS_NAME
,
431 "WRDS", sizeof(*data
), NULL
);
435 if (data
->revision
!= IWL_UEFI_WRDS_REVISION
) {
437 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI WRDS revision:%d\n",
442 /* The profile from WRDS is officially profile 1, but goes
443 * into sar_profiles[0] (because we don't have a profile 0).
445 iwl_uefi_set_sar_profile(fwrt
, &data
->sar_profile
, 0, data
->mode
);
451 int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime
*fwrt
)
453 struct uefi_cnv_var_ewrd
*data
;
456 data
= iwl_uefi_get_verified_variable(fwrt
->trans
, IWL_UEFI_EWRD_NAME
,
457 "EWRD", sizeof(*data
), NULL
);
461 if (data
->revision
!= IWL_UEFI_EWRD_REVISION
) {
463 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI EWRD revision:%d\n",
468 if (data
->num_profiles
>= BIOS_SAR_MAX_PROFILE_NUM
) {
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.
478 iwl_uefi_set_sar_profile(fwrt
, &data
->sar_profiles
[i
], i
+ 1,
486 int iwl_uefi_get_wgds_table(struct iwl_fw_runtime
*fwrt
)
488 struct uefi_cnv_var_wgds
*data
;
491 data
= iwl_uefi_get_verified_variable(fwrt
->trans
, IWL_UEFI_WGDS_NAME
,
492 "WGDS", sizeof(*data
), NULL
);
496 if (data
->revision
!= IWL_UEFI_WGDS_REVISION
) {
498 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI WGDS revision:%d\n",
503 if (data
->num_profiles
< BIOS_GEO_MIN_PROFILE_NUM
||
504 data
->num_profiles
> BIOS_GEO_MAX_PROFILE_NUM
) {
506 IWL_DEBUG_RADIO(fwrt
, "Invalid number of profiles in WGDS: %d\n",
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
));
516 fwrt
->geo_num_profiles
= data
->num_profiles
;
517 fwrt
->geo_enabled
= true;
523 int iwl_uefi_get_ppag_table(struct iwl_fw_runtime
*fwrt
)
525 struct uefi_cnv_var_ppag
*data
;
528 data
= iwl_uefi_get_verified_variable(fwrt
->trans
, IWL_UEFI_PPAG_NAME
,
529 "PPAG", sizeof(*data
), NULL
);
533 if (data
->revision
< IWL_UEFI_MIN_PPAG_REV
||
534 data
->revision
> IWL_UEFI_MAX_PPAG_REV
) {
536 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI PPAG revision:%d\n",
541 fwrt
->ppag_ver
= data
->revision
;
542 fwrt
->ppag_flags
= iwl_bios_get_ppag_flags(data
->ppag_modes
,
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
));
553 int iwl_uefi_get_tas_table(struct iwl_fw_runtime
*fwrt
,
554 struct iwl_tas_data
*tas_data
)
556 struct uefi_cnv_var_wtas
*uefi_tas
;
557 int ret
= 0, enabled
, i
;
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
))
564 if (uefi_tas
->revision
!= IWL_UEFI_WTAS_REVISION
) {
566 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI WTAS revision:%d\n",
571 enabled
= iwl_parse_tas_selection(fwrt
, tas_data
,
572 uefi_tas
->tas_selection
);
574 IWL_DEBUG_RADIO(fwrt
, "TAS not enabled\n");
579 IWL_DEBUG_RADIO(fwrt
, "Reading TAS table revision %d\n",
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
);
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
);
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
]);
601 int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime
*fwrt
,
604 struct uefi_cnv_var_splc
*data
;
607 data
= iwl_uefi_get_verified_variable(fwrt
->trans
, IWL_UEFI_SPLC_NAME
,
608 "SPLC", sizeof(*data
), NULL
);
612 if (data
->revision
!= IWL_UEFI_SPLC_REVISION
) {
614 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI SPLC revision:%d\n",
618 *dflt_pwr_limit
= data
->default_pwr_limit
;
624 int iwl_uefi_get_mcc(struct iwl_fw_runtime
*fwrt
, char *mcc
)
626 struct uefi_cnv_var_wrdd
*data
;
629 data
= iwl_uefi_get_verified_variable(fwrt
->trans
, IWL_UEFI_WRDD_NAME
,
630 "WRDD", sizeof(*data
), NULL
);
634 if (data
->revision
!= IWL_UEFI_WRDD_REVISION
) {
636 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI WRDD revision:%d\n",
641 if (data
->mcc
!= BIOS_MCC_CHINA
) {
643 IWL_DEBUG_RADIO(fwrt
, "UEFI WRDD is supported only for CN\n");
647 mcc
[0] = (data
->mcc
>> 8) & 0xff;
648 mcc
[1] = data
->mcc
& 0xff;
655 int iwl_uefi_get_eckv(struct iwl_fw_runtime
*fwrt
, u32
*extl_clk
)
657 struct uefi_cnv_var_eckv
*data
;
660 data
= iwl_uefi_get_verified_variable(fwrt
->trans
, IWL_UEFI_ECKV_NAME
,
661 "ECKV", sizeof(*data
), NULL
);
665 if (data
->revision
!= IWL_UEFI_ECKV_REVISION
) {
667 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI WRDD revision:%d\n",
671 *extl_clk
= data
->ext_clock_valid
;
677 int iwl_uefi_get_wbem(struct iwl_fw_runtime
*fwrt
, u32
*value
)
679 struct uefi_cnv_wlan_wbem_data
*data
;
682 data
= iwl_uefi_get_verified_variable(fwrt
->trans
, IWL_UEFI_WBEM_NAME
,
683 "WBEM", sizeof(*data
), NULL
);
687 if (data
->revision
!= IWL_UEFI_WBEM_REVISION
) {
689 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI WBEM revision:%d\n",
693 *value
= data
->wbem_320mhz_per_mcc
& IWL_UEFI_WBEM_REV0_MASK
;
694 IWL_DEBUG_RADIO(fwrt
, "Loaded WBEM config from UEFI\n");
700 int iwl_uefi_get_dsm(struct iwl_fw_runtime
*fwrt
, enum iwl_dsm_funcs func
,
703 struct uefi_cnv_var_general_cfg
*data
;
706 /* Not supported function index */
707 if (func
>= DSM_FUNC_NUM_FUNCS
|| func
== 5)
710 data
= iwl_uefi_get_verified_variable(fwrt
->trans
, IWL_UEFI_DSM_NAME
,
711 "DSM", sizeof(*data
), NULL
);
715 if (data
->revision
!= IWL_UEFI_DSM_REVISION
) {
716 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI DSM revision:%d\n",
721 if (ARRAY_SIZE(data
->functions
) != UEFI_MAX_DSM_FUNCS
) {
722 IWL_DEBUG_RADIO(fwrt
, "Invalid size of DSM functions array\n");
726 *value
= data
->functions
[func
];
733 int iwl_uefi_get_puncturing(struct iwl_fw_runtime
*fwrt
)
735 struct uefi_cnv_var_puncturing_data
*data
;
736 /* default value is not enabled if there is any issue in reading
737 * uefi variable or revision is not supported
741 data
= iwl_uefi_get_verified_variable(fwrt
->trans
,
742 IWL_UEFI_PUNCTURING_NAME
,
743 "UefiCnvWlanPuncturing",
744 sizeof(*data
), NULL
);
748 if (data
->revision
!= IWL_UEFI_PUNCTURING_REVISION
) {
749 IWL_DEBUG_RADIO(fwrt
, "Unsupported UEFI PUNCTURING rev:%d\n",
752 puncturing
= data
->puncturing
& IWL_UEFI_PUNCTURING_REV0_MASK
;
753 IWL_DEBUG_RADIO(fwrt
, "Loaded puncturing bits from UEFI: %d\n",
760 IWL_EXPORT_SYMBOL(iwl_uefi_get_puncturing
);