]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: uefi: support the new WRDS and EWRD tables
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 19 Mar 2026 18:48:44 +0000 (20:48 +0200)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Wed, 25 Mar 2026 09:31:56 +0000 (11:31 +0200)
Those tables now have support for UNII-9 subband.
Refactor iwl_uefi_set_sar_profile to get an array of values that makes
it easier to use when the number of subbands can vary.
Revamp a bit the code that fetches the tables to ask for the smaller
table, then we can check the size of the object that we got and compare
to the expected sizes to determine what revision to expect.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260319204647.6948f69e6ae4.Icf990e13de6905c35a8de69f1445f8eb4aa43ee4@changeid
drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
drivers/net/wireless/intel/iwlwifi/fw/uefi.c
drivers/net/wireless/intel/iwlwifi/fw/uefi.h

index 446c8a2c4f9d68bb6f1b432dc2ac9f19ceb5a770..a3684514c904d4c6aaff34013bb207bbfc78568f 100644 (file)
@@ -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
index 84b6f8b7eda95fe0f269c624efe6ed5686026230..3d3d698bacd0c01e5efcccb1380e5d335679cd5a 100644 (file)
@@ -460,11 +460,30 @@ out:
 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 @@ out:
 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);
index 5046b6a454199c39a2f21f9e207ccf8e975d2f42..aa5a4c5a73922ee9878690692847462380f18dec 100644 (file)
@@ -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_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];
-};
+#define UEFI_SAR_SUB_BANDS_NUM_REV2    11
+#define UEFI_SAR_SUB_BANDS_NUM_REV3    12
 
-/*
- * 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;
+#define UEFI_SAR_MAX_CHAINS_PER_PROFILE        4
 
 /*
  * 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