Commit 8ae3e231 authored by Gregory Greenman's avatar Gregory Greenman Committed by Johannes Berg

wifi: iwlwifi: fw: don't use constant size with efi.get_variable

Use efi.get_variable() with NULL pointer for data in order to
obtain entry size and then call it again with the correct size
to get the entry itself.
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230606103519.ef95a8055a50.Iae5389baaf0a9a3c89469f7502275ee119d378b6@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 875d035f
......@@ -17,38 +17,53 @@
0xb2, 0xec, 0xf5, 0xa3, \
0x59, 0x4f, 0x4a, 0xea)
void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid,
unsigned long *data_size)
{
void *data;
unsigned long package_size;
efi_status_t status;
void *data;
*len = 0;
if (!data_size)
return ERR_PTR(-EINVAL);
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
return ERR_PTR(-ENODEV);
/*
* TODO: we hardcode a maximum length here, because reading
* from the UEFI is not working. To implement this properly,
* we have to call efivar_entry_size().
*/
package_size = IWL_HARDCODED_PNVM_SIZE;
/* first call with NULL data to get the exact entry size */
*data_size = 0;
status = efi.get_variable(name, guid, NULL, data_size, NULL);
if (status != EFI_BUFFER_TOO_SMALL || !*data_size)
return ERR_PTR(-EIO);
data = kmalloc(package_size, GFP_KERNEL);
data = kmalloc(*data_size, GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
status = efi.get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID,
NULL, &package_size, data);
status = efi.get_variable(name, guid, NULL, data_size, data);
if (status != EFI_SUCCESS) {
IWL_DEBUG_FW(trans,
"PNVM UEFI variable not found 0x%lx (len %lu)\n",
status, package_size);
kfree(data);
return ERR_PTR(-ENOENT);
}
return data;
}
void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
{
unsigned long package_size;
void *data;
*len = 0;
data = iwl_uefi_get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID,
&package_size);
if (IS_ERR(data)) {
IWL_DEBUG_FW(trans,
"PNVM UEFI variable not found 0x%lx (len %lu)\n",
PTR_ERR(data), package_size);
return data;
}
IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %lu\n", package_size);
*len = package_size;
......@@ -185,31 +200,24 @@ u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
{
struct pnvm_sku_package *package;
unsigned long package_size;
efi_status_t status;
u8 *data;
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
return ERR_PTR(-ENODEV);
/*
* TODO: we hardcode a maximum length here, because reading
* from the UEFI is not working. To implement this properly,
* we have to call efivar_entry_size().
*/
package_size = IWL_HARDCODED_REDUCE_POWER_SIZE;
package = iwl_uefi_get_variable(IWL_UEFI_REDUCED_POWER_NAME,
&IWL_EFI_VAR_GUID, &package_size);
package = kmalloc(package_size, GFP_KERNEL);
if (!package)
return ERR_PTR(-ENOMEM);
status = efi.get_variable(IWL_UEFI_REDUCED_POWER_NAME, &IWL_EFI_VAR_GUID,
NULL, &package_size, package);
if (status != EFI_SUCCESS) {
if (IS_ERR(package)) {
IWL_DEBUG_FW(trans,
"Reduced Power UEFI variable not found 0x%lx (len %lu)\n",
status, package_size);
PTR_ERR(package), package_size);
return ERR_CAST(package);
}
if (package_size < sizeof(*package)) {
IWL_DEBUG_FW(trans,
"Invalid Reduced Power UEFI variable len (%lu)\n",
package_size);
kfree(package);
return ERR_PTR(-ENOENT);
return ERR_PTR(-EINVAL);
}
IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n",
......@@ -220,8 +228,11 @@ u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
*len = package_size - sizeof(*package);
data = kmemdup(package->data, *len, GFP_KERNEL);
if (!data)
if (!data) {
kfree(package);
return ERR_PTR(-ENOMEM);
}
kfree(package);
return data;
......@@ -245,31 +256,27 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans)
{
struct uefi_cnv_common_step_data *data;
unsigned long package_size;
efi_status_t status;
int ret;
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
return;
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
return;
data = iwl_uefi_get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID,
&package_size);
/* TODO: we hardcode a maximum length here, because reading
* from the UEFI is not working. To implement this properly,
* we have to call efivar_entry_size().
*/
package_size = IWL_HARDCODED_STEP_SIZE;
data = kmalloc(package_size, GFP_KERNEL);
if (!data)
if (IS_ERR(data)) {
IWL_DEBUG_FW(trans,
"STEP UEFI variable not found 0x%lx\n",
PTR_ERR(data));
return;
}
status = efi.get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID,
NULL, &package_size, data);
if (status != EFI_SUCCESS) {
if (package_size < sizeof(*data)) {
IWL_DEBUG_FW(trans,
"STEP UEFI variable not found 0x%lx\n", status);
goto out_free;
"Invalid STEP table UEFI variable len (%lu)\n",
package_size);
kfree(data);
return;
}
IWL_DEBUG_FW(trans, "Read STEP from UEFI with size %lu\n",
......@@ -279,7 +286,6 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans)
if (ret < 0)
IWL_DEBUG_FW(trans, "Cannot read STEP tables. rev is invalid\n");
out_free:
kfree(data);
}
IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table);
......@@ -322,29 +328,26 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans,
{
struct uefi_cnv_wlan_sgom_data *data;
unsigned long package_size;
efi_status_t status;
int ret;
if (!fwrt->geo_enabled ||
!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
if (!fwrt->geo_enabled)
return;
/* TODO: we hardcode a maximum length here, because reading
* from the UEFI is not working. To implement this properly,
* we have to call efivar_entry_size().
*/
package_size = IWL_HARDCODED_SGOM_SIZE;
data = kmalloc(package_size, GFP_KERNEL);
if (!data)
data = iwl_uefi_get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID,
&package_size);
if (IS_ERR(data)) {
IWL_DEBUG_FW(trans,
"SGOM UEFI variable not found 0x%lx\n",
PTR_ERR(data));
return;
}
status = efi.get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID,
NULL, &package_size, data);
if (status != EFI_SUCCESS) {
if (package_size < sizeof(*data)) {
IWL_DEBUG_FW(trans,
"SGOM UEFI variable not found 0x%lx\n", status);
goto out_free;
"Invalid SGOM table UEFI variable len (%lu)\n",
package_size);
kfree(data);
return;
}
IWL_DEBUG_FW(trans, "Read SGOM from UEFI with size %lu\n",
......@@ -354,9 +357,7 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans,
if (ret < 0)
IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n");
out_free:
kfree(data);
}
IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table);
#endif /* CONFIG_ACPI */
......@@ -10,16 +10,7 @@
#define IWL_UEFI_SGOM_NAME L"UefiCnvWlanSarGeoOffsetMapping"
#define IWL_UEFI_STEP_NAME L"UefiCnvCommonSTEP"
/*
* TODO: we have these hardcoded values that the caller must pass,
* because reading from the UEFI is not working. To implement this
* properly, we have to change iwl_pnvm_get_from_uefi() to call
* efivar_entry_size() and return the value to the caller instead.
*/
#define IWL_HARDCODED_PNVM_SIZE 4096
#define IWL_HARDCODED_REDUCE_POWER_SIZE 32768
#define IWL_HARDCODED_SGOM_SIZE 339
#define IWL_HARDCODED_STEP_SIZE 6
#define IWL_SGOM_MAP_SIZE 339
struct pnvm_sku_package {
u8 rev;
......@@ -31,7 +22,7 @@ struct pnvm_sku_package {
struct uefi_cnv_wlan_sgom_data {
u8 revision;
u8 offset_map[IWL_HARDCODED_SGOM_SIZE - 1];
u8 offset_map[IWL_SGOM_MAP_SIZE - 1];
} __packed;
struct uefi_cnv_common_step_data {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment