184c3c995SLuca Coelho // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
284c3c995SLuca Coelho /*
374f4cd71SMiri Korenblit * Copyright(c) 2021-2024 Intel Corporation
484c3c995SLuca Coelho */
584c3c995SLuca Coelho
684c3c995SLuca Coelho #include "iwl-drv.h"
784c3c995SLuca Coelho #include "pnvm.h"
884c3c995SLuca Coelho #include "iwl-prph.h"
984c3c995SLuca Coelho #include "iwl-io.h"
1084c3c995SLuca Coelho
1184c3c995SLuca Coelho #include "fw/uefi.h"
129dad325fSLuca Coelho #include "fw/api/alive.h"
1384c3c995SLuca Coelho #include <linux/efi.h>
14c593d2faSAyala Barazani #include "fw/runtime.h"
1584c3c995SLuca Coelho
1684c3c995SLuca Coelho #define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \
1784c3c995SLuca Coelho 0xb2, 0xec, 0xf5, 0xa3, \
1884c3c995SLuca Coelho 0x59, 0x4f, 0x4a, 0xea)
1984c3c995SLuca Coelho
20372a7148SGregory Greenman struct iwl_uefi_pnvm_mem_desc {
21372a7148SGregory Greenman __le32 addr;
22372a7148SGregory Greenman __le32 size;
23372a7148SGregory Greenman const u8 data[];
24372a7148SGregory Greenman } __packed;
25372a7148SGregory Greenman
iwl_uefi_get_variable(efi_char16_t * name,efi_guid_t * guid,unsigned long * data_size)268ae3e231SGregory Greenman static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid,
278ae3e231SGregory Greenman unsigned long *data_size)
2884c3c995SLuca Coelho {
290c4bad7fSArd Biesheuvel efi_status_t status;
308ae3e231SGregory Greenman void *data;
3184c3c995SLuca Coelho
328ae3e231SGregory Greenman if (!data_size)
338ae3e231SGregory Greenman return ERR_PTR(-EINVAL);
349dad325fSLuca Coelho
350c4bad7fSArd Biesheuvel if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
360c4bad7fSArd Biesheuvel return ERR_PTR(-ENODEV);
3784c3c995SLuca Coelho
388ae3e231SGregory Greenman /* first call with NULL data to get the exact entry size */
398ae3e231SGregory Greenman *data_size = 0;
408ae3e231SGregory Greenman status = efi.get_variable(name, guid, NULL, data_size, NULL);
418ae3e231SGregory Greenman if (status != EFI_BUFFER_TOO_SMALL || !*data_size)
428ae3e231SGregory Greenman return ERR_PTR(-EIO);
4384c3c995SLuca Coelho
448ae3e231SGregory Greenman data = kmalloc(*data_size, GFP_KERNEL);
450c4bad7fSArd Biesheuvel if (!data)
460c4bad7fSArd Biesheuvel return ERR_PTR(-ENOMEM);
4784c3c995SLuca Coelho
488ae3e231SGregory Greenman status = efi.get_variable(name, guid, NULL, data_size, data);
490c4bad7fSArd Biesheuvel if (status != EFI_SUCCESS) {
5084c3c995SLuca Coelho kfree(data);
510c4bad7fSArd Biesheuvel return ERR_PTR(-ENOENT);
5284c3c995SLuca Coelho }
5384c3c995SLuca Coelho
548ae3e231SGregory Greenman return data;
558ae3e231SGregory Greenman }
568ae3e231SGregory Greenman
iwl_uefi_get_pnvm(struct iwl_trans * trans,size_t * len)578ae3e231SGregory Greenman void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
588ae3e231SGregory Greenman {
598ae3e231SGregory Greenman unsigned long package_size;
608ae3e231SGregory Greenman void *data;
618ae3e231SGregory Greenman
628ae3e231SGregory Greenman *len = 0;
638ae3e231SGregory Greenman
648ae3e231SGregory Greenman data = iwl_uefi_get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID,
658ae3e231SGregory Greenman &package_size);
668ae3e231SGregory Greenman if (IS_ERR(data)) {
678ae3e231SGregory Greenman IWL_DEBUG_FW(trans,
688ae3e231SGregory Greenman "PNVM UEFI variable not found 0x%lx (len %lu)\n",
698ae3e231SGregory Greenman PTR_ERR(data), package_size);
708ae3e231SGregory Greenman return data;
718ae3e231SGregory Greenman }
728ae3e231SGregory Greenman
731476ff21SLinus Torvalds IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %lu\n", package_size);
7484c3c995SLuca Coelho *len = package_size;
7584c3c995SLuca Coelho
7684c3c995SLuca Coelho return data;
7784c3c995SLuca Coelho }
789dad325fSLuca Coelho
79a6dfe1e7SMiri Korenblit static
iwl_uefi_get_verified_variable(struct iwl_trans * trans,efi_char16_t * uefi_var_name,char * var_name,unsigned int expected_size,unsigned long * size)80a6dfe1e7SMiri Korenblit void *iwl_uefi_get_verified_variable(struct iwl_trans *trans,
81a6dfe1e7SMiri Korenblit efi_char16_t *uefi_var_name,
82a6dfe1e7SMiri Korenblit char *var_name,
83a6dfe1e7SMiri Korenblit unsigned int expected_size,
84a6dfe1e7SMiri Korenblit unsigned long *size)
85a6dfe1e7SMiri Korenblit {
86a6dfe1e7SMiri Korenblit void *var;
87a6dfe1e7SMiri Korenblit unsigned long var_size;
88a6dfe1e7SMiri Korenblit
89a6dfe1e7SMiri Korenblit var = iwl_uefi_get_variable(uefi_var_name, &IWL_EFI_VAR_GUID,
90a6dfe1e7SMiri Korenblit &var_size);
91a6dfe1e7SMiri Korenblit
92a6dfe1e7SMiri Korenblit if (IS_ERR(var)) {
93a6dfe1e7SMiri Korenblit IWL_DEBUG_RADIO(trans,
94a6dfe1e7SMiri Korenblit "%s UEFI variable not found 0x%lx\n", var_name,
95a6dfe1e7SMiri Korenblit PTR_ERR(var));
96a6dfe1e7SMiri Korenblit return var;
97a6dfe1e7SMiri Korenblit }
98a6dfe1e7SMiri Korenblit
99a6dfe1e7SMiri Korenblit if (var_size < expected_size) {
100a6dfe1e7SMiri Korenblit IWL_DEBUG_RADIO(trans,
101a6dfe1e7SMiri Korenblit "Invalid %s UEFI variable len (%lu)\n",
102a6dfe1e7SMiri Korenblit var_name, var_size);
103a6dfe1e7SMiri Korenblit kfree(var);
104a6dfe1e7SMiri Korenblit return ERR_PTR(-EINVAL);
105a6dfe1e7SMiri Korenblit }
106a6dfe1e7SMiri Korenblit
107a6dfe1e7SMiri Korenblit IWL_DEBUG_RADIO(trans, "%s from UEFI with size %lu\n", var_name,
108a6dfe1e7SMiri Korenblit var_size);
109a6dfe1e7SMiri Korenblit
110a6dfe1e7SMiri Korenblit if (size)
111a6dfe1e7SMiri Korenblit *size = var_size;
112a6dfe1e7SMiri Korenblit return var;
113a6dfe1e7SMiri Korenblit }
114a6dfe1e7SMiri Korenblit
iwl_uefi_handle_tlv_mem_desc(struct iwl_trans * trans,const u8 * data,u32 tlv_len,struct iwl_pnvm_image * pnvm_data)115372a7148SGregory Greenman int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data,
116372a7148SGregory Greenman u32 tlv_len, struct iwl_pnvm_image *pnvm_data)
117372a7148SGregory Greenman {
118372a7148SGregory Greenman const struct iwl_uefi_pnvm_mem_desc *desc = (const void *)data;
119372a7148SGregory Greenman u32 data_len;
120372a7148SGregory Greenman
121372a7148SGregory Greenman if (tlv_len < sizeof(*desc)) {
122372a7148SGregory Greenman IWL_DEBUG_FW(trans, "TLV len (%d) is too small\n", tlv_len);
123372a7148SGregory Greenman return -EINVAL;
124372a7148SGregory Greenman }
125372a7148SGregory Greenman
126372a7148SGregory Greenman data_len = tlv_len - sizeof(*desc);
127372a7148SGregory Greenman
128372a7148SGregory Greenman IWL_DEBUG_FW(trans,
129372a7148SGregory Greenman "Handle IWL_UCODE_TLV_MEM_DESC, len %d data_len %d\n",
130372a7148SGregory Greenman tlv_len, data_len);
131372a7148SGregory Greenman
132372a7148SGregory Greenman if (le32_to_cpu(desc->size) != data_len) {
133372a7148SGregory Greenman IWL_DEBUG_FW(trans, "invalid mem desc size %d\n", desc->size);
134372a7148SGregory Greenman return -EINVAL;
135372a7148SGregory Greenman }
136372a7148SGregory Greenman
137372a7148SGregory Greenman if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) {
138372a7148SGregory Greenman IWL_DEBUG_FW(trans, "too many payloads to allocate in DRAM.\n");
139372a7148SGregory Greenman return -EINVAL;
140372a7148SGregory Greenman }
141372a7148SGregory Greenman
142372a7148SGregory Greenman IWL_DEBUG_FW(trans, "Adding data (size %d)\n", data_len);
143372a7148SGregory Greenman
144372a7148SGregory Greenman pnvm_data->chunks[pnvm_data->n_chunks].data = desc->data;
145372a7148SGregory Greenman pnvm_data->chunks[pnvm_data->n_chunks].len = data_len;
146372a7148SGregory Greenman pnvm_data->n_chunks++;
147372a7148SGregory Greenman
148372a7148SGregory Greenman return 0;
149372a7148SGregory Greenman }
150372a7148SGregory Greenman
iwl_uefi_reduce_power_section(struct iwl_trans * trans,const u8 * data,size_t len,struct iwl_pnvm_image * pnvm_data)151ea3571f4SAlon Giladi static int iwl_uefi_reduce_power_section(struct iwl_trans *trans,
152ea3571f4SAlon Giladi const u8 *data, size_t len,
153ea3571f4SAlon Giladi struct iwl_pnvm_image *pnvm_data)
1549dad325fSLuca Coelho {
15586e8e657SJohannes Berg const struct iwl_ucode_tlv *tlv;
1569dad325fSLuca Coelho
1579dad325fSLuca Coelho IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n");
158ea3571f4SAlon Giladi memset(pnvm_data, 0, sizeof(*pnvm_data));
1599dad325fSLuca Coelho
1609dad325fSLuca Coelho while (len >= sizeof(*tlv)) {
1619dad325fSLuca Coelho u32 tlv_len, tlv_type;
1629dad325fSLuca Coelho
1639dad325fSLuca Coelho len -= sizeof(*tlv);
16486e8e657SJohannes Berg tlv = (const void *)data;
1659dad325fSLuca Coelho
1669dad325fSLuca Coelho tlv_len = le32_to_cpu(tlv->length);
1679dad325fSLuca Coelho tlv_type = le32_to_cpu(tlv->type);
1689dad325fSLuca Coelho
1699dad325fSLuca Coelho if (len < tlv_len) {
1709dad325fSLuca Coelho IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
1719dad325fSLuca Coelho len, tlv_len);
172ea3571f4SAlon Giladi return -EINVAL;
1739dad325fSLuca Coelho }
1749dad325fSLuca Coelho
1759dad325fSLuca Coelho data += sizeof(*tlv);
1769dad325fSLuca Coelho
1779dad325fSLuca Coelho switch (tlv_type) {
178372a7148SGregory Greenman case IWL_UCODE_TLV_MEM_DESC:
179372a7148SGregory Greenman if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len,
180372a7148SGregory Greenman pnvm_data))
181ea3571f4SAlon Giladi return -EINVAL;
1829dad325fSLuca Coelho break;
1839dad325fSLuca Coelho case IWL_UCODE_TLV_PNVM_SKU:
1849dad325fSLuca Coelho IWL_DEBUG_FW(trans,
1859dad325fSLuca Coelho "New REDUCE_POWER section started, stop parsing.\n");
1869dad325fSLuca Coelho goto done;
1879dad325fSLuca Coelho default:
1889dad325fSLuca Coelho IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n",
1899dad325fSLuca Coelho tlv_type, tlv_len);
1909dad325fSLuca Coelho break;
1919dad325fSLuca Coelho }
1929dad325fSLuca Coelho
1939dad325fSLuca Coelho len -= ALIGN(tlv_len, 4);
1949dad325fSLuca Coelho data += ALIGN(tlv_len, 4);
1959dad325fSLuca Coelho }
1969dad325fSLuca Coelho
1979dad325fSLuca Coelho done:
198ea3571f4SAlon Giladi if (!pnvm_data->n_chunks) {
1999dad325fSLuca Coelho IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n");
200ea3571f4SAlon Giladi return -ENOENT;
201ea3571f4SAlon Giladi }
202ea3571f4SAlon Giladi return 0;
2039dad325fSLuca Coelho }
2049dad325fSLuca Coelho
iwl_uefi_reduce_power_parse(struct iwl_trans * trans,const u8 * data,size_t len,struct iwl_pnvm_image * pnvm_data)205380bf72dSAlon Giladi int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
206ea3571f4SAlon Giladi const u8 *data, size_t len,
207ea3571f4SAlon Giladi struct iwl_pnvm_image *pnvm_data)
2089dad325fSLuca Coelho {
20986e8e657SJohannes Berg const struct iwl_ucode_tlv *tlv;
2109dad325fSLuca Coelho
2119dad325fSLuca Coelho IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n");
2129dad325fSLuca Coelho
2139dad325fSLuca Coelho while (len >= sizeof(*tlv)) {
2149dad325fSLuca Coelho u32 tlv_len, tlv_type;
2159dad325fSLuca Coelho
2169dad325fSLuca Coelho len -= sizeof(*tlv);
21786e8e657SJohannes Berg tlv = (const void *)data;
2189dad325fSLuca Coelho
2199dad325fSLuca Coelho tlv_len = le32_to_cpu(tlv->length);
2209dad325fSLuca Coelho tlv_type = le32_to_cpu(tlv->type);
2219dad325fSLuca Coelho
2229dad325fSLuca Coelho if (len < tlv_len) {
2239dad325fSLuca Coelho IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
2249dad325fSLuca Coelho len, tlv_len);
225ea3571f4SAlon Giladi return -EINVAL;
2269dad325fSLuca Coelho }
2279dad325fSLuca Coelho
2289dad325fSLuca Coelho if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) {
22986e8e657SJohannes Berg const struct iwl_sku_id *sku_id =
23086e8e657SJohannes Berg (const void *)(data + sizeof(*tlv));
2319dad325fSLuca Coelho
2329dad325fSLuca Coelho IWL_DEBUG_FW(trans,
2339dad325fSLuca Coelho "Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
2349dad325fSLuca Coelho tlv_len);
2359dad325fSLuca Coelho IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
2369dad325fSLuca Coelho le32_to_cpu(sku_id->data[0]),
2379dad325fSLuca Coelho le32_to_cpu(sku_id->data[1]),
2389dad325fSLuca Coelho le32_to_cpu(sku_id->data[2]));
2399dad325fSLuca Coelho
2409dad325fSLuca Coelho data += sizeof(*tlv) + ALIGN(tlv_len, 4);
2419dad325fSLuca Coelho len -= ALIGN(tlv_len, 4);
2429dad325fSLuca Coelho
2439dad325fSLuca Coelho if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) &&
2449dad325fSLuca Coelho trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) &&
2459dad325fSLuca Coelho trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) {
246ea3571f4SAlon Giladi int ret = iwl_uefi_reduce_power_section(trans,
247ea3571f4SAlon Giladi data, len,
248ea3571f4SAlon Giladi pnvm_data);
249ea3571f4SAlon Giladi if (!ret)
250ea3571f4SAlon Giladi return 0;
2519dad325fSLuca Coelho } else {
2529dad325fSLuca Coelho IWL_DEBUG_FW(trans, "SKU ID didn't match!\n");
2539dad325fSLuca Coelho }
2549dad325fSLuca Coelho } else {
2559dad325fSLuca Coelho data += sizeof(*tlv) + ALIGN(tlv_len, 4);
2569dad325fSLuca Coelho len -= ALIGN(tlv_len, 4);
2579dad325fSLuca Coelho }
2589dad325fSLuca Coelho }
2599dad325fSLuca Coelho
260ea3571f4SAlon Giladi return -ENOENT;
2619dad325fSLuca Coelho }
2629dad325fSLuca Coelho
iwl_uefi_get_reduced_power(struct iwl_trans * trans,size_t * len)263380bf72dSAlon Giladi u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
2649dad325fSLuca Coelho {
2659dad325fSLuca Coelho struct pnvm_sku_package *package;
2669dad325fSLuca Coelho unsigned long package_size;
267380bf72dSAlon Giladi u8 *data;
2689dad325fSLuca Coelho
269a6dfe1e7SMiri Korenblit package = iwl_uefi_get_verified_variable(trans,
270a6dfe1e7SMiri Korenblit IWL_UEFI_REDUCED_POWER_NAME,
271a6dfe1e7SMiri Korenblit "Reduced Power",
272a6dfe1e7SMiri Korenblit sizeof(*package),
273a6dfe1e7SMiri Korenblit &package_size);
274a6dfe1e7SMiri Korenblit if (IS_ERR(package))
2758ae3e231SGregory Greenman return ERR_CAST(package);
2769dad325fSLuca Coelho
2779dad325fSLuca Coelho IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n",
2789dad325fSLuca Coelho package->rev, package->total_size, package->n_skus);
2799dad325fSLuca Coelho
280380bf72dSAlon Giladi *len = package_size - sizeof(*package);
281380bf72dSAlon Giladi data = kmemdup(package->data, *len, GFP_KERNEL);
2828ae3e231SGregory Greenman if (!data) {
2838ae3e231SGregory Greenman kfree(package);
284380bf72dSAlon Giladi return ERR_PTR(-ENOMEM);
2858ae3e231SGregory Greenman }
2868ae3e231SGregory Greenman
2879dad325fSLuca Coelho kfree(package);
2889dad325fSLuca Coelho
289380bf72dSAlon Giladi return data;
2909dad325fSLuca Coelho }
291c593d2faSAyala Barazani
iwl_uefi_step_parse(struct uefi_cnv_common_step_data * common_step_data,struct iwl_trans * trans)29209b4c35dSAyala Barazani static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_data,
29309b4c35dSAyala Barazani struct iwl_trans *trans)
29409b4c35dSAyala Barazani {
29509b4c35dSAyala Barazani if (common_step_data->revision != 1)
29609b4c35dSAyala Barazani return -EINVAL;
29709b4c35dSAyala Barazani
29809b4c35dSAyala Barazani trans->mbx_addr_0_step = (u32)common_step_data->revision |
29909b4c35dSAyala Barazani (u32)common_step_data->cnvi_eq_channel << 8 |
30009b4c35dSAyala Barazani (u32)common_step_data->cnvr_eq_channel << 16 |
30109b4c35dSAyala Barazani (u32)common_step_data->radio1 << 24;
30209b4c35dSAyala Barazani trans->mbx_addr_1_step = (u32)common_step_data->radio2;
30309b4c35dSAyala Barazani return 0;
30409b4c35dSAyala Barazani }
30509b4c35dSAyala Barazani
iwl_uefi_get_step_table(struct iwl_trans * trans)30609b4c35dSAyala Barazani void iwl_uefi_get_step_table(struct iwl_trans *trans)
30709b4c35dSAyala Barazani {
30809b4c35dSAyala Barazani struct uefi_cnv_common_step_data *data;
30909b4c35dSAyala Barazani int ret;
31009b4c35dSAyala Barazani
31109b4c35dSAyala Barazani if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
31209b4c35dSAyala Barazani return;
31309b4c35dSAyala Barazani
314a6dfe1e7SMiri Korenblit data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_STEP_NAME,
315a6dfe1e7SMiri Korenblit "STEP", sizeof(*data), NULL);
316a6dfe1e7SMiri Korenblit if (IS_ERR(data))
3178ae3e231SGregory Greenman return;
31809b4c35dSAyala Barazani
31909b4c35dSAyala Barazani ret = iwl_uefi_step_parse(data, trans);
32009b4c35dSAyala Barazani if (ret < 0)
32109b4c35dSAyala Barazani IWL_DEBUG_FW(trans, "Cannot read STEP tables. rev is invalid\n");
32209b4c35dSAyala Barazani
32309b4c35dSAyala Barazani kfree(data);
32409b4c35dSAyala Barazani }
32509b4c35dSAyala Barazani IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table);
32609b4c35dSAyala Barazani
iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data * sgom_data,struct iwl_fw_runtime * fwrt)327c593d2faSAyala Barazani static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data,
328c593d2faSAyala Barazani struct iwl_fw_runtime *fwrt)
329c593d2faSAyala Barazani {
330c593d2faSAyala Barazani int i, j;
331c593d2faSAyala Barazani
332c593d2faSAyala Barazani if (sgom_data->revision != 1)
333c593d2faSAyala Barazani return -EINVAL;
334c593d2faSAyala Barazani
335c593d2faSAyala Barazani memcpy(fwrt->sgom_table.offset_map, sgom_data->offset_map,
336c593d2faSAyala Barazani sizeof(fwrt->sgom_table.offset_map));
337c593d2faSAyala Barazani
338c593d2faSAyala Barazani for (i = 0; i < MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE; i++) {
339c593d2faSAyala Barazani for (j = 0; j < MCC_TO_SAR_OFFSET_TABLE_COL_SIZE; j++) {
340c593d2faSAyala Barazani /* since each byte is composed of to values, */
341c593d2faSAyala Barazani /* one for each letter, */
342c593d2faSAyala Barazani /* extract and check each of them separately */
343c593d2faSAyala Barazani u8 value = fwrt->sgom_table.offset_map[i][j];
344c593d2faSAyala Barazani u8 low = value & 0xF;
345c593d2faSAyala Barazani u8 high = (value & 0xF0) >> 4;
346c593d2faSAyala Barazani
347c593d2faSAyala Barazani if (high > fwrt->geo_num_profiles)
348c593d2faSAyala Barazani high = 0;
349c593d2faSAyala Barazani if (low > fwrt->geo_num_profiles)
350c593d2faSAyala Barazani low = 0;
351c593d2faSAyala Barazani fwrt->sgom_table.offset_map[i][j] = (high << 4) | low;
352c593d2faSAyala Barazani }
353c593d2faSAyala Barazani }
354c593d2faSAyala Barazani
355c593d2faSAyala Barazani fwrt->sgom_enabled = true;
356c593d2faSAyala Barazani return 0;
357c593d2faSAyala Barazani }
358c593d2faSAyala Barazani
iwl_uefi_get_sgom_table(struct iwl_trans * trans,struct iwl_fw_runtime * fwrt)359c593d2faSAyala Barazani void iwl_uefi_get_sgom_table(struct iwl_trans *trans,
360c593d2faSAyala Barazani struct iwl_fw_runtime *fwrt)
361c593d2faSAyala Barazani {
362c593d2faSAyala Barazani struct uefi_cnv_wlan_sgom_data *data;
3630c4bad7fSArd Biesheuvel int ret;
364c593d2faSAyala Barazani
3658ae3e231SGregory Greenman if (!fwrt->geo_enabled)
366c593d2faSAyala Barazani return;
367c593d2faSAyala Barazani
368a6dfe1e7SMiri Korenblit data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_SGOM_NAME,
369a6dfe1e7SMiri Korenblit "SGOM", sizeof(*data), NULL);
370a6dfe1e7SMiri Korenblit if (IS_ERR(data))
3718ae3e231SGregory Greenman return;
372c593d2faSAyala Barazani
373c593d2faSAyala Barazani ret = iwl_uefi_sgom_parse(data, fwrt);
374c593d2faSAyala Barazani if (ret < 0)
375c593d2faSAyala Barazani IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n");
376c593d2faSAyala Barazani
377c593d2faSAyala Barazani kfree(data);
378c593d2faSAyala Barazani }
379c593d2faSAyala Barazani IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table);
3804a9bb5b4SMukesh Sisodiya
iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data * uats_data,struct iwl_fw_runtime * fwrt)3814a9bb5b4SMukesh Sisodiya static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data,
3824a9bb5b4SMukesh Sisodiya struct iwl_fw_runtime *fwrt)
3834a9bb5b4SMukesh Sisodiya {
3844a9bb5b4SMukesh Sisodiya if (uats_data->revision != 1)
3854a9bb5b4SMukesh Sisodiya return -EINVAL;
3864a9bb5b4SMukesh Sisodiya
3874a9bb5b4SMukesh Sisodiya memcpy(fwrt->uats_table.offset_map, uats_data->offset_map,
3884a9bb5b4SMukesh Sisodiya sizeof(fwrt->uats_table.offset_map));
3894a9bb5b4SMukesh Sisodiya return 0;
3904a9bb5b4SMukesh Sisodiya }
3914a9bb5b4SMukesh Sisodiya
iwl_uefi_get_uats_table(struct iwl_trans * trans,struct iwl_fw_runtime * fwrt)3924a9bb5b4SMukesh Sisodiya int iwl_uefi_get_uats_table(struct iwl_trans *trans,
3934a9bb5b4SMukesh Sisodiya struct iwl_fw_runtime *fwrt)
3944a9bb5b4SMukesh Sisodiya {
3954a9bb5b4SMukesh Sisodiya struct uefi_cnv_wlan_uats_data *data;
3964a9bb5b4SMukesh Sisodiya int ret;
3974a9bb5b4SMukesh Sisodiya
398a6dfe1e7SMiri Korenblit data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UATS_NAME,
399a6dfe1e7SMiri Korenblit "UATS", sizeof(*data), NULL);
400a6dfe1e7SMiri Korenblit if (IS_ERR(data))
4014a9bb5b4SMukesh Sisodiya return -EINVAL;
4024a9bb5b4SMukesh Sisodiya
4034a9bb5b4SMukesh Sisodiya ret = iwl_uefi_uats_parse(data, fwrt);
4044a9bb5b4SMukesh Sisodiya if (ret < 0) {
4054a9bb5b4SMukesh Sisodiya IWL_DEBUG_FW(trans, "Cannot read UATS table. rev is invalid\n");
4064a9bb5b4SMukesh Sisodiya kfree(data);
4074a9bb5b4SMukesh Sisodiya return ret;
4084a9bb5b4SMukesh Sisodiya }
4094a9bb5b4SMukesh Sisodiya
4104a9bb5b4SMukesh Sisodiya kfree(data);
4114a9bb5b4SMukesh Sisodiya return 0;
4124a9bb5b4SMukesh Sisodiya }
4134a9bb5b4SMukesh Sisodiya IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table);
414427661e4SMiri Korenblit
iwl_uefi_set_sar_profile(struct iwl_fw_runtime * fwrt,struct uefi_sar_profile * uefi_sar_prof,u8 prof_index,bool enabled)415427661e4SMiri Korenblit static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt,
416427661e4SMiri Korenblit struct uefi_sar_profile *uefi_sar_prof,
417427661e4SMiri Korenblit u8 prof_index, bool enabled)
418427661e4SMiri Korenblit {
419427661e4SMiri Korenblit memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof,
420427661e4SMiri Korenblit sizeof(struct uefi_sar_profile));
421427661e4SMiri Korenblit
422427661e4SMiri Korenblit fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK;
423427661e4SMiri Korenblit }
424427661e4SMiri Korenblit
iwl_uefi_get_wrds_table(struct iwl_fw_runtime * fwrt)425427661e4SMiri Korenblit int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt)
426427661e4SMiri Korenblit {
427427661e4SMiri Korenblit struct uefi_cnv_var_wrds *data;
428427661e4SMiri Korenblit int ret = 0;
429427661e4SMiri Korenblit
430427661e4SMiri Korenblit data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME,
431427661e4SMiri Korenblit "WRDS", sizeof(*data), NULL);
432427661e4SMiri Korenblit if (IS_ERR(data))
433427661e4SMiri Korenblit return -EINVAL;
434427661e4SMiri Korenblit
435427661e4SMiri Korenblit if (data->revision != IWL_UEFI_WRDS_REVISION) {
436427661e4SMiri Korenblit ret = -EINVAL;
437427661e4SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n",
438427661e4SMiri Korenblit data->revision);
439427661e4SMiri Korenblit goto out;
440427661e4SMiri Korenblit }
441427661e4SMiri Korenblit
442427661e4SMiri Korenblit /* The profile from WRDS is officially profile 1, but goes
443427661e4SMiri Korenblit * into sar_profiles[0] (because we don't have a profile 0).
444427661e4SMiri Korenblit */
445427661e4SMiri Korenblit iwl_uefi_set_sar_profile(fwrt, &data->sar_profile, 0, data->mode);
446427661e4SMiri Korenblit out:
447427661e4SMiri Korenblit kfree(data);
448427661e4SMiri Korenblit return ret;
449427661e4SMiri Korenblit }
450427661e4SMiri Korenblit
iwl_uefi_get_ewrd_table(struct iwl_fw_runtime * fwrt)451427661e4SMiri Korenblit int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
452427661e4SMiri Korenblit {
453427661e4SMiri Korenblit struct uefi_cnv_var_ewrd *data;
454427661e4SMiri Korenblit int i, ret = 0;
455427661e4SMiri Korenblit
456427661e4SMiri Korenblit data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME,
457427661e4SMiri Korenblit "EWRD", sizeof(*data), NULL);
458427661e4SMiri Korenblit if (IS_ERR(data))
459427661e4SMiri Korenblit return -EINVAL;
460427661e4SMiri Korenblit
461427661e4SMiri Korenblit if (data->revision != IWL_UEFI_EWRD_REVISION) {
462427661e4SMiri Korenblit ret = -EINVAL;
463427661e4SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n",
464427661e4SMiri Korenblit data->revision);
465427661e4SMiri Korenblit goto out;
466427661e4SMiri Korenblit }
467427661e4SMiri Korenblit
468427661e4SMiri Korenblit if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) {
469427661e4SMiri Korenblit ret = -EINVAL;
470427661e4SMiri Korenblit goto out;
471427661e4SMiri Korenblit }
472427661e4SMiri Korenblit
473427661e4SMiri Korenblit for (i = 0; i < data->num_profiles; i++)
474427661e4SMiri Korenblit /* The EWRD profiles officially go from 2 to 4, but we
475427661e4SMiri Korenblit * save them in sar_profiles[1-3] (because we don't
476427661e4SMiri Korenblit * have profile 0). So in the array we start from 1.
477427661e4SMiri Korenblit */
478427661e4SMiri Korenblit iwl_uefi_set_sar_profile(fwrt, &data->sar_profiles[i], i + 1,
479427661e4SMiri Korenblit data->mode);
480427661e4SMiri Korenblit
481427661e4SMiri Korenblit out:
482427661e4SMiri Korenblit kfree(data);
483427661e4SMiri Korenblit return ret;
484427661e4SMiri Korenblit }
485427661e4SMiri Korenblit
iwl_uefi_get_wgds_table(struct iwl_fw_runtime * fwrt)486427661e4SMiri Korenblit int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt)
487427661e4SMiri Korenblit {
488427661e4SMiri Korenblit struct uefi_cnv_var_wgds *data;
489427661e4SMiri Korenblit int i, ret = 0;
490427661e4SMiri Korenblit
491427661e4SMiri Korenblit data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME,
492427661e4SMiri Korenblit "WGDS", sizeof(*data), NULL);
493427661e4SMiri Korenblit if (IS_ERR(data))
494427661e4SMiri Korenblit return -EINVAL;
495427661e4SMiri Korenblit
496427661e4SMiri Korenblit if (data->revision != IWL_UEFI_WGDS_REVISION) {
497427661e4SMiri Korenblit ret = -EINVAL;
498427661e4SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n",
499427661e4SMiri Korenblit data->revision);
500427661e4SMiri Korenblit goto out;
501427661e4SMiri Korenblit }
502427661e4SMiri Korenblit
503427661e4SMiri Korenblit if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM ||
504427661e4SMiri Korenblit data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) {
505427661e4SMiri Korenblit ret = -EINVAL;
506427661e4SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Invalid number of profiles in WGDS: %d\n",
507427661e4SMiri Korenblit data->num_profiles);
508427661e4SMiri Korenblit goto out;
509427661e4SMiri Korenblit }
510427661e4SMiri Korenblit
511427661e4SMiri Korenblit fwrt->geo_rev = data->revision;
512427661e4SMiri Korenblit for (i = 0; i < data->num_profiles; i++)
513427661e4SMiri Korenblit memcpy(&fwrt->geo_profiles[i], &data->geo_profiles[i],
514427661e4SMiri Korenblit sizeof(struct iwl_geo_profile));
515427661e4SMiri Korenblit
516427661e4SMiri Korenblit fwrt->geo_num_profiles = data->num_profiles;
517427661e4SMiri Korenblit fwrt->geo_enabled = true;
518427661e4SMiri Korenblit out:
519427661e4SMiri Korenblit kfree(data);
520427661e4SMiri Korenblit return ret;
521427661e4SMiri Korenblit }
522bc8d0a45SMiri Korenblit
iwl_uefi_get_ppag_table(struct iwl_fw_runtime * fwrt)523bc8d0a45SMiri Korenblit int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
524bc8d0a45SMiri Korenblit {
525bc8d0a45SMiri Korenblit struct uefi_cnv_var_ppag *data;
526bc8d0a45SMiri Korenblit int ret = 0;
527bc8d0a45SMiri Korenblit
528bc8d0a45SMiri Korenblit data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME,
529bc8d0a45SMiri Korenblit "PPAG", sizeof(*data), NULL);
530bc8d0a45SMiri Korenblit if (IS_ERR(data))
531bc8d0a45SMiri Korenblit return -EINVAL;
532bc8d0a45SMiri Korenblit
533bc8d0a45SMiri Korenblit if (data->revision < IWL_UEFI_MIN_PPAG_REV ||
534bc8d0a45SMiri Korenblit data->revision > IWL_UEFI_MAX_PPAG_REV) {
535bc8d0a45SMiri Korenblit ret = -EINVAL;
536bc8d0a45SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PPAG revision:%d\n",
537bc8d0a45SMiri Korenblit data->revision);
538bc8d0a45SMiri Korenblit goto out;
539bc8d0a45SMiri Korenblit }
540bc8d0a45SMiri Korenblit
541bc8d0a45SMiri Korenblit fwrt->ppag_ver = data->revision;
5423d801a75SAnjaneyulu fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes,
5433d801a75SAnjaneyulu fwrt->ppag_ver);
544bc8d0a45SMiri Korenblit
545bc8d0a45SMiri Korenblit BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains));
546bc8d0a45SMiri Korenblit memcpy(&fwrt->ppag_chains, &data->ppag_chains,
547bc8d0a45SMiri Korenblit sizeof(data->ppag_chains));
548bc8d0a45SMiri Korenblit out:
549bc8d0a45SMiri Korenblit kfree(data);
550bc8d0a45SMiri Korenblit return ret;
551bc8d0a45SMiri Korenblit }
552084e0452SMiri Korenblit
iwl_uefi_get_tas_table(struct iwl_fw_runtime * fwrt,struct iwl_tas_data * tas_data)553084e0452SMiri Korenblit int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt,
554084e0452SMiri Korenblit struct iwl_tas_data *tas_data)
555084e0452SMiri Korenblit {
556084e0452SMiri Korenblit struct uefi_cnv_var_wtas *uefi_tas;
557084e0452SMiri Korenblit int ret = 0, enabled, i;
558084e0452SMiri Korenblit
559084e0452SMiri Korenblit uefi_tas = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WTAS_NAME,
560084e0452SMiri Korenblit "WTAS", sizeof(*uefi_tas), NULL);
561084e0452SMiri Korenblit if (IS_ERR(uefi_tas))
562084e0452SMiri Korenblit return -EINVAL;
563084e0452SMiri Korenblit
564084e0452SMiri Korenblit if (uefi_tas->revision != IWL_UEFI_WTAS_REVISION) {
565084e0452SMiri Korenblit ret = -EINVAL;
566084e0452SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WTAS revision:%d\n",
567084e0452SMiri Korenblit uefi_tas->revision);
568084e0452SMiri Korenblit goto out;
569084e0452SMiri Korenblit }
570084e0452SMiri Korenblit
571084e0452SMiri Korenblit enabled = iwl_parse_tas_selection(fwrt, tas_data,
572084e0452SMiri Korenblit uefi_tas->tas_selection);
573084e0452SMiri Korenblit if (!enabled) {
574084e0452SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n");
575084e0452SMiri Korenblit ret = 0;
576084e0452SMiri Korenblit goto out;
577084e0452SMiri Korenblit }
578084e0452SMiri Korenblit
579084e0452SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n",
580084e0452SMiri Korenblit uefi_tas->revision);
581084e0452SMiri Korenblit if (uefi_tas->black_list_size > IWL_WTAS_BLACK_LIST_MAX) {
582084e0452SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %d\n",
583084e0452SMiri Korenblit uefi_tas->black_list_size);
584084e0452SMiri Korenblit ret = -EINVAL;
585084e0452SMiri Korenblit goto out;
586084e0452SMiri Korenblit }
587084e0452SMiri Korenblit tas_data->block_list_size = cpu_to_le32(uefi_tas->black_list_size);
588084e0452SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", uefi_tas->black_list_size);
589084e0452SMiri Korenblit
590084e0452SMiri Korenblit for (i = 0; i < uefi_tas->black_list_size; i++) {
591084e0452SMiri Korenblit tas_data->block_list_array[i] =
592084e0452SMiri Korenblit cpu_to_le32(uefi_tas->black_list[i]);
593084e0452SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n",
594084e0452SMiri Korenblit uefi_tas->black_list[i]);
595084e0452SMiri Korenblit }
596084e0452SMiri Korenblit out:
597084e0452SMiri Korenblit kfree(uefi_tas);
598084e0452SMiri Korenblit return ret;
599084e0452SMiri Korenblit }
60018f52365SMiri Korenblit
iwl_uefi_get_pwr_limit(struct iwl_fw_runtime * fwrt,u64 * dflt_pwr_limit)60118f52365SMiri Korenblit int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt,
60218f52365SMiri Korenblit u64 *dflt_pwr_limit)
60318f52365SMiri Korenblit {
60418f52365SMiri Korenblit struct uefi_cnv_var_splc *data;
60518f52365SMiri Korenblit int ret = 0;
60618f52365SMiri Korenblit
60718f52365SMiri Korenblit data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_SPLC_NAME,
60818f52365SMiri Korenblit "SPLC", sizeof(*data), NULL);
60918f52365SMiri Korenblit if (IS_ERR(data))
61018f52365SMiri Korenblit return -EINVAL;
61118f52365SMiri Korenblit
61218f52365SMiri Korenblit if (data->revision != IWL_UEFI_SPLC_REVISION) {
61318f52365SMiri Korenblit ret = -EINVAL;
61418f52365SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI SPLC revision:%d\n",
61518f52365SMiri Korenblit data->revision);
61618f52365SMiri Korenblit goto out;
61718f52365SMiri Korenblit }
61818f52365SMiri Korenblit *dflt_pwr_limit = data->default_pwr_limit;
61918f52365SMiri Korenblit out:
62018f52365SMiri Korenblit kfree(data);
62118f52365SMiri Korenblit return ret;
62218f52365SMiri Korenblit }
623669761e8SMiri Korenblit
iwl_uefi_get_mcc(struct iwl_fw_runtime * fwrt,char * mcc)624669761e8SMiri Korenblit int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)
625669761e8SMiri Korenblit {
626669761e8SMiri Korenblit struct uefi_cnv_var_wrdd *data;
627669761e8SMiri Korenblit int ret = 0;
628669761e8SMiri Korenblit
629669761e8SMiri Korenblit data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDD_NAME,
630669761e8SMiri Korenblit "WRDD", sizeof(*data), NULL);
631669761e8SMiri Korenblit if (IS_ERR(data))
632669761e8SMiri Korenblit return -EINVAL;
633669761e8SMiri Korenblit
634669761e8SMiri Korenblit if (data->revision != IWL_UEFI_WRDD_REVISION) {
635669761e8SMiri Korenblit ret = -EINVAL;
636669761e8SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n",
637669761e8SMiri Korenblit data->revision);
638669761e8SMiri Korenblit goto out;
639669761e8SMiri Korenblit }
640669761e8SMiri Korenblit
641*ff5aabe7SAnjaneyulu if (data->mcc != BIOS_MCC_CHINA) {
642669761e8SMiri Korenblit ret = -EINVAL;
643669761e8SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "UEFI WRDD is supported only for CN\n");
644669761e8SMiri Korenblit goto out;
645669761e8SMiri Korenblit }
646669761e8SMiri Korenblit
647669761e8SMiri Korenblit mcc[0] = (data->mcc >> 8) & 0xff;
648669761e8SMiri Korenblit mcc[1] = data->mcc & 0xff;
649669761e8SMiri Korenblit mcc[2] = '\0';
650669761e8SMiri Korenblit out:
651669761e8SMiri Korenblit kfree(data);
652669761e8SMiri Korenblit return ret;
653669761e8SMiri Korenblit }
65420935f3eSMiri Korenblit
iwl_uefi_get_eckv(struct iwl_fw_runtime * fwrt,u32 * extl_clk)65520935f3eSMiri Korenblit int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk)
65620935f3eSMiri Korenblit {
65720935f3eSMiri Korenblit struct uefi_cnv_var_eckv *data;
65820935f3eSMiri Korenblit int ret = 0;
65920935f3eSMiri Korenblit
66020935f3eSMiri Korenblit data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_ECKV_NAME,
66120935f3eSMiri Korenblit "ECKV", sizeof(*data), NULL);
66220935f3eSMiri Korenblit if (IS_ERR(data))
66320935f3eSMiri Korenblit return -EINVAL;
66420935f3eSMiri Korenblit
66520935f3eSMiri Korenblit if (data->revision != IWL_UEFI_ECKV_REVISION) {
66620935f3eSMiri Korenblit ret = -EINVAL;
66720935f3eSMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n",
66820935f3eSMiri Korenblit data->revision);
66920935f3eSMiri Korenblit goto out;
67020935f3eSMiri Korenblit }
67120935f3eSMiri Korenblit *extl_clk = data->ext_clock_valid;
67220935f3eSMiri Korenblit out:
67320935f3eSMiri Korenblit kfree(data);
67420935f3eSMiri Korenblit return ret;
67520935f3eSMiri Korenblit }
676fc7214c3SMiri Korenblit
iwl_uefi_get_wbem(struct iwl_fw_runtime * fwrt,u32 * value)677332ff432SAnjaneyulu int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
678332ff432SAnjaneyulu {
679332ff432SAnjaneyulu struct uefi_cnv_wlan_wbem_data *data;
680332ff432SAnjaneyulu int ret = 0;
681332ff432SAnjaneyulu
682332ff432SAnjaneyulu data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WBEM_NAME,
683332ff432SAnjaneyulu "WBEM", sizeof(*data), NULL);
684332ff432SAnjaneyulu if (IS_ERR(data))
685332ff432SAnjaneyulu return -EINVAL;
686332ff432SAnjaneyulu
687332ff432SAnjaneyulu if (data->revision != IWL_UEFI_WBEM_REVISION) {
688332ff432SAnjaneyulu ret = -EINVAL;
689332ff432SAnjaneyulu IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WBEM revision:%d\n",
690332ff432SAnjaneyulu data->revision);
691332ff432SAnjaneyulu goto out;
692332ff432SAnjaneyulu }
693332ff432SAnjaneyulu *value = data->wbem_320mhz_per_mcc & IWL_UEFI_WBEM_REV0_MASK;
694332ff432SAnjaneyulu IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from UEFI\n");
695332ff432SAnjaneyulu out:
696332ff432SAnjaneyulu kfree(data);
697332ff432SAnjaneyulu return ret;
698332ff432SAnjaneyulu }
699332ff432SAnjaneyulu
iwl_uefi_get_dsm(struct iwl_fw_runtime * fwrt,enum iwl_dsm_funcs func,u32 * value)700fc7214c3SMiri Korenblit int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
701fc7214c3SMiri Korenblit u32 *value)
702fc7214c3SMiri Korenblit {
703fc7214c3SMiri Korenblit struct uefi_cnv_var_general_cfg *data;
704f29a8be8SDan Carpenter int ret = -EINVAL;
705fc7214c3SMiri Korenblit
706fc7214c3SMiri Korenblit /* Not supported function index */
707fc7214c3SMiri Korenblit if (func >= DSM_FUNC_NUM_FUNCS || func == 5)
708fc7214c3SMiri Korenblit return -EOPNOTSUPP;
709fc7214c3SMiri Korenblit
710fc7214c3SMiri Korenblit data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME,
711fc7214c3SMiri Korenblit "DSM", sizeof(*data), NULL);
712fc7214c3SMiri Korenblit if (IS_ERR(data))
713fc7214c3SMiri Korenblit return -EINVAL;
714fc7214c3SMiri Korenblit
715fc7214c3SMiri Korenblit if (data->revision != IWL_UEFI_DSM_REVISION) {
716fc7214c3SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSM revision:%d\n",
717fc7214c3SMiri Korenblit data->revision);
718fc7214c3SMiri Korenblit goto out;
719fc7214c3SMiri Korenblit }
720fc7214c3SMiri Korenblit
721fc7214c3SMiri Korenblit if (ARRAY_SIZE(data->functions) != UEFI_MAX_DSM_FUNCS) {
722fc7214c3SMiri Korenblit IWL_DEBUG_RADIO(fwrt, "Invalid size of DSM functions array\n");
723fc7214c3SMiri Korenblit goto out;
724fc7214c3SMiri Korenblit }
725fc7214c3SMiri Korenblit
726fc7214c3SMiri Korenblit *value = data->functions[func];
727fc7214c3SMiri Korenblit ret = 0;
728fc7214c3SMiri Korenblit out:
729fc7214c3SMiri Korenblit kfree(data);
730fc7214c3SMiri Korenblit return ret;
731fc7214c3SMiri Korenblit }
732b312e357SSomashekhar(Som)
iwl_uefi_get_puncturing(struct iwl_fw_runtime * fwrt)733b312e357SSomashekhar(Som) int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt)
734b312e357SSomashekhar(Som) {
735b312e357SSomashekhar(Som) struct uefi_cnv_var_puncturing_data *data;
736b312e357SSomashekhar(Som) /* default value is not enabled if there is any issue in reading
737b312e357SSomashekhar(Som) * uefi variable or revision is not supported
738b312e357SSomashekhar(Som) */
739b312e357SSomashekhar(Som) int puncturing = 0;
740b312e357SSomashekhar(Som)
741b312e357SSomashekhar(Som) data = iwl_uefi_get_verified_variable(fwrt->trans,
742b312e357SSomashekhar(Som) IWL_UEFI_PUNCTURING_NAME,
743b312e357SSomashekhar(Som) "UefiCnvWlanPuncturing",
744b312e357SSomashekhar(Som) sizeof(*data), NULL);
745b312e357SSomashekhar(Som) if (IS_ERR(data))
746b312e357SSomashekhar(Som) return puncturing;
747b312e357SSomashekhar(Som)
748b312e357SSomashekhar(Som) if (data->revision != IWL_UEFI_PUNCTURING_REVISION) {
749b312e357SSomashekhar(Som) IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PUNCTURING rev:%d\n",
750b312e357SSomashekhar(Som) data->revision);
751b312e357SSomashekhar(Som) } else {
752b312e357SSomashekhar(Som) puncturing = data->puncturing & IWL_UEFI_PUNCTURING_REV0_MASK;
753b312e357SSomashekhar(Som) IWL_DEBUG_RADIO(fwrt, "Loaded puncturing bits from UEFI: %d\n",
754b312e357SSomashekhar(Som) puncturing);
755b312e357SSomashekhar(Som) }
756b312e357SSomashekhar(Som)
757b312e357SSomashekhar(Som) kfree(data);
758b312e357SSomashekhar(Som) return puncturing;
759b312e357SSomashekhar(Som) }
760b312e357SSomashekhar(Som) IWL_EXPORT_SYMBOL(iwl_uefi_get_puncturing);
761