diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 446c8a2c4f9d..a3684514c904 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -21,7 +21,7 @@ */ #define BIOS_SAR_MAX_CHAINS_PER_PROFILE 4 #define BIOS_SAR_NUM_CHAINS 2 -#define BIOS_SAR_MAX_SUB_BANDS_NUM 11 +#define BIOS_SAR_MAX_SUB_BANDS_NUM 12 #define BIOS_PPAG_MAX_SUB_BANDS_NUM 12 #define BIOS_GEO_NUM_CHAINS 2 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 84b6f8b7eda9..3d3d698bacd0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -460,11 +460,30 @@ void iwl_uefi_get_uneb_table(struct iwl_trans *trans, IWL_EXPORT_SYMBOL(iwl_uefi_get_uneb_table); static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, - struct uefi_sar_profile *uefi_sar_prof, - u8 prof_index, bool enabled) + const u8 *vals, u8 prof_index, + u8 num_subbands, bool enabled) { - memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof, - sizeof(struct uefi_sar_profile)); + struct iwl_sar_profile *sar_prof = &fwrt->sar_profiles[prof_index]; + + /* + * Make sure fwrt has enough room to hold the data + * coming from the UEFI table + */ + if (WARN_ON(ARRAY_SIZE(sar_prof->chains) * + ARRAY_SIZE(sar_prof->chains[0].subbands) < + UEFI_SAR_MAX_CHAINS_PER_PROFILE * num_subbands)) + return; + + BUILD_BUG_ON(ARRAY_SIZE(sar_prof->chains) != + UEFI_SAR_MAX_CHAINS_PER_PROFILE); + + for (int chain = 0; + chain < UEFI_SAR_MAX_CHAINS_PER_PROFILE; + chain++) { + for (int subband = 0; subband < num_subbands; subband++) + sar_prof->chains[chain].subbands[subband] = + vals[chain * num_subbands + subband]; + } fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK; } @@ -472,24 +491,46 @@ static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) { struct uefi_cnv_var_wrds *data; + unsigned long size; + unsigned long expected_size; + int num_subbands; int ret = 0; data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME, - "WRDS", sizeof(*data), NULL); + "WRDS", + UEFI_SAR_WRDS_TABLE_SIZE_REV2, + &size); + if (IS_ERR(data)) return -EINVAL; - if (data->revision != IWL_UEFI_WRDS_REVISION) { - ret = -EINVAL; - IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n", + switch (data->revision) { + case 2: + expected_size = UEFI_SAR_WRDS_TABLE_SIZE_REV2; + num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV2; + break; + case 3: + expected_size = UEFI_SAR_WRDS_TABLE_SIZE_REV3; + num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV3; + break; + default: + IWL_DEBUG_RADIO(fwrt, + "Unsupported UEFI WRDS revision:%d\n", data->revision); + ret = -EINVAL; + goto out; + } + + if (size != expected_size) { + ret = -EINVAL; goto out; } /* The profile from WRDS is officially profile 1, but goes * into sar_profiles[0] (because we don't have a profile 0). */ - iwl_uefi_set_sar_profile(fwrt, &data->sar_profile, 0, data->mode); + iwl_uefi_set_sar_profile(fwrt, data->vals, 0, + num_subbands, data->mode); out: kfree(data); return ret; @@ -498,21 +539,40 @@ int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) { struct uefi_cnv_var_ewrd *data; + unsigned long expected_size; int i, ret = 0; + unsigned long size; + int num_subbands; + int profile_size; data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME, - "EWRD", sizeof(*data), NULL); + "EWRD", + UEFI_SAR_EWRD_TABLE_SIZE_REV2, + &size); if (IS_ERR(data)) return -EINVAL; - if (data->revision != IWL_UEFI_EWRD_REVISION) { - ret = -EINVAL; - IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n", + switch (data->revision) { + case 2: + expected_size = UEFI_SAR_EWRD_TABLE_SIZE_REV2; + num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV2; + profile_size = UEFI_SAR_PROFILE_SIZE_REV2; + break; + case 3: + expected_size = UEFI_SAR_EWRD_TABLE_SIZE_REV3; + num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV3; + profile_size = UEFI_SAR_PROFILE_SIZE_REV3; + break; + default: + IWL_DEBUG_RADIO(fwrt, + "Unsupported UEFI EWRD revision:%d\n", data->revision); + ret = -EINVAL; goto out; } - if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { + if (size != expected_size || + data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { ret = -EINVAL; goto out; } @@ -522,8 +582,8 @@ int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) * save them in sar_profiles[1-3] (because we don't * have profile 0). So in the array we start from 1. */ - iwl_uefi_set_sar_profile(fwrt, &data->sar_profiles[i], i + 1, - data->mode); + iwl_uefi_set_sar_profile(fwrt, &data->vals[i * profile_size], + i + 1, num_subbands, data->mode); out: kfree(data); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 5046b6a45419..aa5a4c5a7392 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -31,8 +31,6 @@ #define IWL_SGOM_MAP_SIZE 339 #define IWL_UATS_MAP_SIZE 339 -#define IWL_UEFI_WRDS_REVISION 2 -#define IWL_UEFI_EWRD_REVISION 2 #define IWL_UEFI_WGDS_REVISION 3 #define IWL_UEFI_MIN_WTAS_REVISION 1 #define IWL_UEFI_MAX_WTAS_REVISION 2 @@ -74,56 +72,74 @@ struct uefi_cnv_common_step_data { u8 radio2; } __packed; -#define UEFI_SAR_MAX_SUB_BANDS_NUM 11 #define UEFI_PPAG_SUB_BANDS_NUM_REV4 11 #define UEFI_PPAG_SUB_BANDS_NUM_REV5 12 #define UEFI_PPAG_NUM_CHAINS 2 + +#define UEFI_SAR_SUB_BANDS_NUM_REV2 11 +#define UEFI_SAR_SUB_BANDS_NUM_REV3 12 + #define UEFI_SAR_MAX_CHAINS_PER_PROFILE 4 -/* - * struct uefi_sar_profile_chain - per-chain values of a SAR profile - * @subbands: the SAR value for each subband - */ -struct uefi_sar_profile_chain { - u8 subbands[UEFI_SAR_MAX_SUB_BANDS_NUM]; -}; - -/* - * struct uefi_sar_profile - a SAR profile as defined in UEFI - * - * @chains: a per-chain table of SAR values - */ -struct uefi_sar_profile { - struct uefi_sar_profile_chain chains[UEFI_SAR_MAX_CHAINS_PER_PROFILE]; -} __packed; - /* * struct uefi_cnv_var_wrds - WRDS table as defined in UEFI * * @revision: the revision of the table * @mode: is WRDS enbaled/disabled - * @sar_profile: sar profile #1 + * @vals: values for sar profile #1 as an array: + * vals[chain * num_of_subbands + subband] will return the right value. + * num_of_subbands depends on the revision. For revision 3, it is + * %UEFI_SAR_SUB_BANDS_NUM_REV3, for earlier revision, it is + * %UEFI_SAR_SUB_BANDS_NUM_REV2. + * The max number of chains is currently 2 */ struct uefi_cnv_var_wrds { u8 revision; u32 mode; - struct uefi_sar_profile sar_profile; + u8 vals[]; } __packed; +#define UEFI_SAR_PROFILE_SIZE_REV2 \ + (sizeof(u8) * UEFI_SAR_MAX_CHAINS_PER_PROFILE * \ + UEFI_SAR_SUB_BANDS_NUM_REV2) + +#define UEFI_SAR_PROFILE_SIZE_REV3 \ + (sizeof(u8) * UEFI_SAR_MAX_CHAINS_PER_PROFILE * \ + UEFI_SAR_SUB_BANDS_NUM_REV3) + +#define UEFI_SAR_WRDS_TABLE_SIZE_REV2 \ + (offsetof(struct uefi_cnv_var_wrds, vals) + \ + UEFI_SAR_PROFILE_SIZE_REV2) + +#define UEFI_SAR_WRDS_TABLE_SIZE_REV3 \ + (offsetof(struct uefi_cnv_var_wrds, vals) + \ + UEFI_SAR_PROFILE_SIZE_REV3) + /* * struct uefi_cnv_var_ewrd - EWRD table as defined in UEFI * @revision: the revision of the table * @mode: is WRDS enbaled/disabled * @num_profiles: how many additional profiles we have in this table (0-3) - * @sar_profiles: the additional SAR profiles (#2-#4) + * @vals: the additional SAR profiles (#2-#4) as an array of SAR profiles. + * A SAR profile is defined the &struct uefi_cnv_var_wrds::vals. The size + * of each profile depends on the number of subbands which depends on the + * revision. This is explained in &struct uefi_cnv_var_wrds. */ struct uefi_cnv_var_ewrd { u8 revision; u32 mode; u32 num_profiles; - struct uefi_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM - 1]; + u8 vals[]; } __packed; +#define UEFI_SAR_EWRD_TABLE_SIZE_REV2 \ + (offsetof(struct uefi_cnv_var_ewrd, vals) + \ + UEFI_SAR_PROFILE_SIZE_REV2 * (BIOS_SAR_MAX_PROFILE_NUM - 1)) + +#define UEFI_SAR_EWRD_TABLE_SIZE_REV3 \ + (offsetof(struct uefi_cnv_var_ewrd, vals) + \ + UEFI_SAR_PROFILE_SIZE_REV3 * (BIOS_SAR_MAX_PROFILE_NUM - 1)) + /* * struct uefi_cnv_var_wgds - WGDS table as defined in UEFI * @revision: the revision of the table