Path: blob/main/sys/contrib/dev/iwlwifi/fw/uefi.c
108396 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright(c) 2021-2025 Intel Corporation3*/45#include "iwl-drv.h"6#include "pnvm.h"7#include "iwl-prph.h"8#include "iwl-io.h"910#include "fw/uefi.h"11#include "fw/api/alive.h"12#include <linux/efi.h>13#include "fw/runtime.h"1415#define IWL_EFI_WIFI_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \160xb2, 0xec, 0xf5, 0xa3, \170x59, 0x4f, 0x4a, 0xea)18#define IWL_EFI_WIFI_BT_GUID EFI_GUID(0xe65d8884, 0xd4af, 0x4b20, \190x8d, 0x03, 0x77, 0x2e, \200xcc, 0x3d, 0xa5, 0x31)2122struct iwl_uefi_pnvm_mem_desc {23__le32 addr;24__le32 size;25const u8 data[];26} __packed;2728static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid,29unsigned long *data_size)30{31efi_status_t status;32void *data;3334if (!data_size)35return ERR_PTR(-EINVAL);3637if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))38return ERR_PTR(-ENODEV);3940/* first call with NULL data to get the exact entry size */41*data_size = 0;42status = efi.get_variable(name, guid, NULL, data_size, NULL);43if (status != EFI_BUFFER_TOO_SMALL || !*data_size)44return ERR_PTR(-EIO);4546data = kmalloc(*data_size, GFP_KERNEL);47if (!data)48return ERR_PTR(-ENOMEM);4950status = efi.get_variable(name, guid, NULL, data_size, data);51if (status != EFI_SUCCESS) {52kfree(data);53return ERR_PTR(-ENOENT);54}5556return data;57}5859void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)60{61unsigned long package_size;62void *data;6364*len = 0;6566data = iwl_uefi_get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_WIFI_GUID,67&package_size);68if (IS_ERR(data)) {69IWL_DEBUG_FW(trans,70"PNVM UEFI variable not found 0x%lx (len %lu)\n",71PTR_ERR(data), package_size);72return data;73}7475IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %lu\n", package_size);76*len = package_size;7778return data;79}8081static void *82iwl_uefi_get_verified_variable_guid(struct iwl_trans *trans,83efi_guid_t *guid,84efi_char16_t *uefi_var_name,85char *var_name,86unsigned int expected_size,87unsigned long *size)88{89void *var;90unsigned long var_size;9192var = iwl_uefi_get_variable(uefi_var_name, guid, &var_size);9394if (IS_ERR(var)) {95IWL_DEBUG_RADIO(trans,96"%s UEFI variable not found 0x%lx\n", var_name,97PTR_ERR(var));98return var;99}100101if (var_size < expected_size) {102IWL_DEBUG_RADIO(trans,103"Invalid %s UEFI variable len (%lu)\n",104var_name, var_size);105kfree(var);106return ERR_PTR(-EINVAL);107}108109IWL_DEBUG_RADIO(trans, "%s from UEFI with size %lu\n", var_name,110var_size);111112if (size)113*size = var_size;114return var;115}116117static void *118iwl_uefi_get_verified_variable(struct iwl_trans *trans,119efi_char16_t *uefi_var_name,120char *var_name,121unsigned int expected_size,122unsigned long *size)123{124return iwl_uefi_get_verified_variable_guid(trans, &IWL_EFI_WIFI_GUID,125uefi_var_name, var_name,126expected_size, size);127}128129int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data,130u32 tlv_len, struct iwl_pnvm_image *pnvm_data)131{132const struct iwl_uefi_pnvm_mem_desc *desc = (const void *)data;133u32 data_len;134135if (tlv_len < sizeof(*desc)) {136IWL_DEBUG_FW(trans, "TLV len (%d) is too small\n", tlv_len);137return -EINVAL;138}139140data_len = tlv_len - sizeof(*desc);141142IWL_DEBUG_FW(trans,143"Handle IWL_UCODE_TLV_MEM_DESC, len %d data_len %d\n",144tlv_len, data_len);145146if (le32_to_cpu(desc->size) != data_len) {147IWL_DEBUG_FW(trans, "invalid mem desc size %d\n", desc->size);148return -EINVAL;149}150151if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) {152IWL_DEBUG_FW(trans, "too many payloads to allocate in DRAM.\n");153return -EINVAL;154}155156IWL_DEBUG_FW(trans, "Adding data (size %d)\n", data_len);157158pnvm_data->chunks[pnvm_data->n_chunks].data = desc->data;159pnvm_data->chunks[pnvm_data->n_chunks].len = data_len;160pnvm_data->n_chunks++;161162return 0;163}164165static int iwl_uefi_reduce_power_section(struct iwl_trans *trans,166const u8 *data, size_t len,167struct iwl_pnvm_image *pnvm_data)168{169const struct iwl_ucode_tlv *tlv;170171IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n");172memset(pnvm_data, 0, sizeof(*pnvm_data));173174while (len >= sizeof(*tlv)) {175u32 tlv_len, tlv_type;176177len -= sizeof(*tlv);178tlv = (const void *)data;179180tlv_len = le32_to_cpu(tlv->length);181tlv_type = le32_to_cpu(tlv->type);182183if (len < tlv_len) {184IWL_ERR(trans, "invalid TLV len: %zd/%u\n",185len, tlv_len);186return -EINVAL;187}188189data += sizeof(*tlv);190191switch (tlv_type) {192case IWL_UCODE_TLV_MEM_DESC:193if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len,194pnvm_data))195return -EINVAL;196break;197case IWL_UCODE_TLV_PNVM_SKU:198IWL_DEBUG_FW(trans,199"New REDUCE_POWER section started, stop parsing.\n");200goto done;201default:202IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n",203tlv_type, tlv_len);204break;205}206207len -= ALIGN(tlv_len, 4);208data += ALIGN(tlv_len, 4);209}210211done:212if (!pnvm_data->n_chunks) {213IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n");214return -ENOENT;215}216return 0;217}218219int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,220const u8 *data, size_t len,221struct iwl_pnvm_image *pnvm_data,222__le32 sku_id[3])223{224const struct iwl_ucode_tlv *tlv;225226IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n");227228while (len >= sizeof(*tlv)) {229u32 tlv_len, tlv_type;230231len -= sizeof(*tlv);232tlv = (const void *)data;233234tlv_len = le32_to_cpu(tlv->length);235tlv_type = le32_to_cpu(tlv->type);236237if (len < tlv_len) {238IWL_ERR(trans, "invalid TLV len: %zd/%u\n",239len, tlv_len);240return -EINVAL;241}242243if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) {244const struct iwl_sku_id *tlv_sku_id =245(const void *)(data + sizeof(*tlv));246247IWL_DEBUG_FW(trans,248"Got IWL_UCODE_TLV_PNVM_SKU len %d\n",249tlv_len);250IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",251le32_to_cpu(tlv_sku_id->data[0]),252le32_to_cpu(tlv_sku_id->data[1]),253le32_to_cpu(tlv_sku_id->data[2]));254255data += sizeof(*tlv) + ALIGN(tlv_len, 4);256len -= ALIGN(tlv_len, 4);257258if (sku_id[0] == tlv_sku_id->data[0] &&259sku_id[1] == tlv_sku_id->data[1] &&260sku_id[2] == tlv_sku_id->data[2]) {261int ret = iwl_uefi_reduce_power_section(trans,262data, len,263pnvm_data);264if (!ret)265return 0;266} else {267IWL_DEBUG_FW(trans, "SKU ID didn't match!\n");268}269} else {270data += sizeof(*tlv) + ALIGN(tlv_len, 4);271len -= ALIGN(tlv_len, 4);272}273}274275return -ENOENT;276}277278u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)279{280struct pnvm_sku_package *package;281unsigned long package_size;282u8 *data;283284package = iwl_uefi_get_verified_variable(trans,285IWL_UEFI_REDUCED_POWER_NAME,286"Reduced Power",287sizeof(*package),288&package_size);289if (IS_ERR(package))290return ERR_CAST(package);291292IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n",293package->rev, package->total_size, package->n_skus);294295*len = package_size - sizeof(*package);296data = kmemdup(package->data, *len, GFP_KERNEL);297if (!data) {298kfree(package);299return ERR_PTR(-ENOMEM);300}301302kfree(package);303304return data;305}306307static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_data,308struct iwl_trans *trans)309{310if (common_step_data->revision != 1)311return -EINVAL;312313trans->conf.mbx_addr_0_step =314(u32)common_step_data->revision |315(u32)common_step_data->cnvi_eq_channel << 8 |316(u32)common_step_data->cnvr_eq_channel << 16 |317(u32)common_step_data->radio1 << 24;318trans->conf.mbx_addr_1_step = (u32)common_step_data->radio2;319return 0;320}321322void iwl_uefi_get_step_table(struct iwl_trans *trans)323{324struct uefi_cnv_common_step_data *data;325int ret;326327if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210)328return;329330data = iwl_uefi_get_verified_variable_guid(trans, &IWL_EFI_WIFI_BT_GUID,331IWL_UEFI_STEP_NAME,332"STEP", sizeof(*data), NULL);333if (IS_ERR(data))334return;335336ret = iwl_uefi_step_parse(data, trans);337if (ret < 0)338IWL_DEBUG_FW(trans, "Cannot read STEP tables. rev is invalid\n");339340kfree(data);341}342IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table);343344static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data,345struct iwl_fw_runtime *fwrt)346{347int i, j;348349if (sgom_data->revision != 1)350return -EINVAL;351352memcpy(fwrt->sgom_table.offset_map, sgom_data->offset_map,353sizeof(fwrt->sgom_table.offset_map));354355for (i = 0; i < MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE; i++) {356for (j = 0; j < MCC_TO_SAR_OFFSET_TABLE_COL_SIZE; j++) {357/* since each byte is composed of to values, */358/* one for each letter, */359/* extract and check each of them separately */360u8 value = fwrt->sgom_table.offset_map[i][j];361u8 low = value & 0xF;362u8 high = (value & 0xF0) >> 4;363364if (high > fwrt->geo_num_profiles)365high = 0;366if (low > fwrt->geo_num_profiles)367low = 0;368fwrt->sgom_table.offset_map[i][j] = (high << 4) | low;369}370}371372fwrt->sgom_enabled = true;373return 0;374}375376void iwl_uefi_get_sgom_table(struct iwl_trans *trans,377struct iwl_fw_runtime *fwrt)378{379struct uefi_cnv_wlan_sgom_data *data;380int ret;381382if (!fwrt->geo_enabled)383return;384385data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_SGOM_NAME,386"SGOM", sizeof(*data), NULL);387if (IS_ERR(data))388return;389390ret = iwl_uefi_sgom_parse(data, fwrt);391if (ret < 0)392IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n");393394kfree(data);395}396IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table);397398static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data,399struct iwl_fw_runtime *fwrt)400{401if (uats_data->revision != 1)402return -EINVAL;403404memcpy(fwrt->uats_table.offset_map, uats_data->offset_map,405sizeof(fwrt->uats_table.offset_map));406407fwrt->uats_valid = true;408409return 0;410}411412void iwl_uefi_get_uats_table(struct iwl_trans *trans,413struct iwl_fw_runtime *fwrt)414{415struct uefi_cnv_wlan_uats_data *data;416int ret;417418data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UATS_NAME,419"UATS", sizeof(*data), NULL);420if (IS_ERR(data))421return;422423ret = iwl_uefi_uats_parse(data, fwrt);424if (ret < 0)425IWL_DEBUG_FW(trans, "Cannot read UATS table. rev is invalid\n");426kfree(data);427}428IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table);429430static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt,431struct uefi_sar_profile *uefi_sar_prof,432u8 prof_index, bool enabled)433{434memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof,435sizeof(struct uefi_sar_profile));436437fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK;438}439440int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt)441{442struct uefi_cnv_var_wrds *data;443int ret = 0;444445data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME,446"WRDS", sizeof(*data), NULL);447if (IS_ERR(data))448return -EINVAL;449450if (data->revision != IWL_UEFI_WRDS_REVISION) {451ret = -EINVAL;452IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n",453data->revision);454goto out;455}456457/* The profile from WRDS is officially profile 1, but goes458* into sar_profiles[0] (because we don't have a profile 0).459*/460iwl_uefi_set_sar_profile(fwrt, &data->sar_profile, 0, data->mode);461out:462kfree(data);463return ret;464}465466int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt)467{468struct uefi_cnv_var_ewrd *data;469int i, ret = 0;470471data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME,472"EWRD", sizeof(*data), NULL);473if (IS_ERR(data))474return -EINVAL;475476if (data->revision != IWL_UEFI_EWRD_REVISION) {477ret = -EINVAL;478IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n",479data->revision);480goto out;481}482483if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) {484ret = -EINVAL;485goto out;486}487488for (i = 0; i < data->num_profiles; i++)489/* The EWRD profiles officially go from 2 to 4, but we490* save them in sar_profiles[1-3] (because we don't491* have profile 0). So in the array we start from 1.492*/493iwl_uefi_set_sar_profile(fwrt, &data->sar_profiles[i], i + 1,494data->mode);495496out:497kfree(data);498return ret;499}500501int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt)502{503struct uefi_cnv_var_wgds *data;504int i, ret = 0;505506data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME,507"WGDS", sizeof(*data), NULL);508if (IS_ERR(data))509return -EINVAL;510511if (data->revision != IWL_UEFI_WGDS_REVISION) {512ret = -EINVAL;513IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n",514data->revision);515goto out;516}517518if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM ||519data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) {520ret = -EINVAL;521IWL_DEBUG_RADIO(fwrt, "Invalid number of profiles in WGDS: %d\n",522data->num_profiles);523goto out;524}525526fwrt->geo_rev = data->revision;527for (i = 0; i < data->num_profiles; i++)528memcpy(&fwrt->geo_profiles[i], &data->geo_profiles[i],529sizeof(struct iwl_geo_profile));530531fwrt->geo_num_profiles = data->num_profiles;532fwrt->geo_enabled = true;533out:534kfree(data);535return ret;536}537538int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)539{540struct uefi_cnv_var_ppag *data;541int ret = 0;542543data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME,544"PPAG", sizeof(*data), NULL);545if (IS_ERR(data))546return -EINVAL;547548if (data->revision < IWL_UEFI_MIN_PPAG_REV ||549data->revision > IWL_UEFI_MAX_PPAG_REV) {550ret = -EINVAL;551IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PPAG revision:%d\n",552data->revision);553goto out;554}555556fwrt->ppag_bios_rev = data->revision;557fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes,558fwrt->ppag_bios_rev);559560BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains));561memcpy(&fwrt->ppag_chains, &data->ppag_chains,562sizeof(data->ppag_chains));563fwrt->ppag_bios_source = BIOS_SOURCE_UEFI;564out:565kfree(data);566return ret;567}568569int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt,570struct iwl_tas_data *tas_data)571{572struct uefi_cnv_var_wtas *uefi_tas;573int ret, enabled;574575uefi_tas = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WTAS_NAME,576"WTAS", sizeof(*uefi_tas), NULL);577if (IS_ERR(uefi_tas))578return -EINVAL;579580if (uefi_tas->revision < IWL_UEFI_MIN_WTAS_REVISION ||581uefi_tas->revision > IWL_UEFI_MAX_WTAS_REVISION) {582ret = -EINVAL;583IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WTAS revision:%d\n",584uefi_tas->revision);585goto out;586}587588IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n",589uefi_tas->tas_selection);590591enabled = uefi_tas->tas_selection & IWL_WTAS_ENABLED_MSK;592tas_data->table_source = BIOS_SOURCE_UEFI;593tas_data->table_revision = uefi_tas->revision;594tas_data->tas_selection = uefi_tas->tas_selection;595596IWL_DEBUG_RADIO(fwrt, "TAS %s enabled\n",597enabled ? "is" : "not");598599IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n",600uefi_tas->revision);601if (uefi_tas->black_list_size > IWL_WTAS_BLACK_LIST_MAX) {602IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %d\n",603uefi_tas->black_list_size);604ret = -EINVAL;605goto out;606}607608tas_data->block_list_size = uefi_tas->black_list_size;609IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", uefi_tas->black_list_size);610611for (u8 i = 0; i < uefi_tas->black_list_size; i++) {612tas_data->block_list_array[i] = uefi_tas->black_list[i];613IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n",614uefi_tas->black_list[i]);615}616ret = enabled;617out:618kfree(uefi_tas);619return ret;620}621622int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt,623u64 *dflt_pwr_limit)624{625struct uefi_cnv_var_splc *data;626int ret = 0;627628data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_SPLC_NAME,629"SPLC", sizeof(*data), NULL);630if (IS_ERR(data))631return -EINVAL;632633if (data->revision != IWL_UEFI_SPLC_REVISION) {634ret = -EINVAL;635IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI SPLC revision:%d\n",636data->revision);637goto out;638}639*dflt_pwr_limit = data->default_pwr_limit;640out:641kfree(data);642return ret;643}644645int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)646{647struct uefi_cnv_var_wrdd *data;648int ret = 0;649650data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDD_NAME,651"WRDD", sizeof(*data), NULL);652if (IS_ERR(data))653return -EINVAL;654655if (data->revision != IWL_UEFI_WRDD_REVISION) {656ret = -EINVAL;657IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n",658data->revision);659goto out;660}661662if (data->mcc != BIOS_MCC_CHINA) {663ret = -EINVAL;664IWL_DEBUG_RADIO(fwrt, "UEFI WRDD is supported only for CN\n");665goto out;666}667668mcc[0] = (data->mcc >> 8) & 0xff;669mcc[1] = data->mcc & 0xff;670mcc[2] = '\0';671out:672kfree(data);673return ret;674}675676int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk)677{678struct uefi_cnv_var_eckv *data;679int ret = 0;680681data = iwl_uefi_get_verified_variable_guid(fwrt->trans,682&IWL_EFI_WIFI_BT_GUID,683IWL_UEFI_ECKV_NAME,684"ECKV", sizeof(*data), NULL);685if (IS_ERR(data))686return -EINVAL;687688if (data->revision != IWL_UEFI_ECKV_REVISION) {689ret = -EINVAL;690IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI ECKV revision:%d\n",691data->revision);692goto out;693}694*extl_clk = data->ext_clock_valid;695out:696kfree(data);697return ret;698}699700int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)701{702struct uefi_cnv_wlan_wbem_data *data;703int ret = 0;704705data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WBEM_NAME,706"WBEM", sizeof(*data), NULL);707if (IS_ERR(data))708return -EINVAL;709710if (data->revision != IWL_UEFI_WBEM_REVISION) {711ret = -EINVAL;712IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WBEM revision:%d\n",713data->revision);714goto out;715}716*value = data->wbem_320mhz_per_mcc & IWL_UEFI_WBEM_REV0_MASK;717IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from UEFI\n");718out:719kfree(data);720return ret;721}722723int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,724u32 *value)725{726struct uefi_cnv_var_general_cfg *data;727int ret = -EINVAL;728729/* Not supported function index */730if (func >= DSM_FUNC_NUM_FUNCS || func == 5)731return -EOPNOTSUPP;732733data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME,734"DSM", sizeof(*data), NULL);735if (IS_ERR(data))736return -EINVAL;737738if (data->revision != IWL_UEFI_DSM_REVISION) {739IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSM revision:%d\n",740data->revision);741goto out;742}743744if (ARRAY_SIZE(data->functions) != UEFI_MAX_DSM_FUNCS) {745IWL_DEBUG_RADIO(fwrt, "Invalid size of DSM functions array\n");746goto out;747}748749if (!(data->functions[DSM_FUNC_QUERY] & BIT(func))) {750IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n",751func, data->functions[DSM_FUNC_QUERY]);752goto out;753}754755*value = data->functions[func];756757IWL_DEBUG_RADIO(fwrt,758"UEFI: DSM func=%d: value=%d\n", func, *value);759760ret = 0;761out:762kfree(data);763return ret;764}765766int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt)767{768struct uefi_cnv_var_puncturing_data *data;769/* default value is not enabled if there is any issue in reading770* uefi variable or revision is not supported771*/772int puncturing = 0;773774data = iwl_uefi_get_verified_variable(fwrt->trans,775IWL_UEFI_PUNCTURING_NAME,776"UefiCnvWlanPuncturing",777sizeof(*data), NULL);778if (IS_ERR(data))779return puncturing;780781if (data->revision != IWL_UEFI_PUNCTURING_REVISION) {782IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PUNCTURING rev:%d\n",783data->revision);784} else {785puncturing = data->puncturing & IWL_UEFI_PUNCTURING_REV0_MASK;786IWL_DEBUG_RADIO(fwrt, "Loaded puncturing bits from UEFI: %d\n",787puncturing);788}789790kfree(data);791return puncturing;792}793IWL_EXPORT_SYMBOL(iwl_uefi_get_puncturing);794795int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value)796{797struct uefi_cnv_wlan_dsbr_data *data;798int ret = 0;799800data = iwl_uefi_get_verified_variable_guid(fwrt->trans,801&IWL_EFI_WIFI_BT_GUID,802IWL_UEFI_DSBR_NAME, "DSBR",803sizeof(*data), NULL);804if (IS_ERR(data))805return -EINVAL;806807if (data->revision != IWL_UEFI_DSBR_REVISION) {808ret = -EINVAL;809IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSBR revision:%d\n",810data->revision);811goto out;812}813*value = data->config;814IWL_DEBUG_RADIO(fwrt, "Loaded DSBR config from UEFI value: 0x%x\n",815*value);816out:817kfree(data);818return ret;819}820821int iwl_uefi_get_phy_filters(struct iwl_fw_runtime *fwrt)822{823struct uefi_cnv_wpfc_data *data __free(kfree);824struct iwl_phy_specific_cfg *filters = &fwrt->phy_filters;825826data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WPFC_NAME,827"WPFC", sizeof(*data), NULL);828if (IS_ERR(data))829return -EINVAL;830831if (data->revision != 0) {832IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WPFC revision:%d\n",833data->revision);834return -EINVAL;835}836837BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) !=838ARRAY_SIZE(data->chains));839840for (int i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) {841filters->filter_cfg_chains[i] = cpu_to_le32(data->chains[i]);842IWL_DEBUG_RADIO(fwrt, "WPFC: chain %d: %u\n", i, data->chains[i]);843}844845IWL_DEBUG_RADIO(fwrt, "Loaded WPFC config from UEFI\n");846return 0;847}848849850