]> www.infradead.org Git - nvme.git/commitdiff
wifi: iwlwifi: read SAR tables from UEFI
authorMiri Korenblit <miriam.rachel.korenblit@intel.com>
Wed, 31 Jan 2024 08:24:39 +0000 (10:24 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 2 Feb 2024 13:15:14 +0000 (14:15 +0100)
All the regulatory tables will be read from UEFI, and
only if it doesn't exist - they will be read from ACPI.
Read SAR tables (WRDS, EWRD and WGDS) from UEFI.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240131091413.533b687e1efb.Icb316291e593c8d53f41fdea2d083367dc97e3c4@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/acpi.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.h
drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
drivers/net/wireless/intel/iwlwifi/fw/runtime.h
drivers/net/wireless/intel/iwlwifi/fw/uefi.c
drivers/net/wireless/intel/iwlwifi/fw/uefi.h
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c

index 401aca31704c58040551d17ea35f05c8afe22cdb..4e638287e9a410b0f34a7e6d8608e9d76b26f948 100644 (file)
@@ -622,7 +622,6 @@ out_free:
        kfree(data);
        return ret;
 }
-IWL_EXPORT_SYMBOL(iwl_acpi_get_wrds_table);
 
 int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
 {
@@ -731,7 +730,6 @@ out_free:
        kfree(data);
        return ret;
 }
-IWL_EXPORT_SYMBOL(iwl_acpi_get_ewrd_table);
 
 int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt)
 {
@@ -748,7 +746,7 @@ int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt)
                        .revisions = BIT(3),
                        .bands = ACPI_GEO_NUM_BANDS_REV2,
                        .profiles = ACPI_NUM_GEO_PROFILES_REV3,
-                       .min_profiles = 3,
+                       .min_profiles = BIOS_GEO_MIN_PROFILE_NUM,
                },
                {
                        .revisions = BIT(2),
@@ -886,7 +884,6 @@ out_free:
        kfree(data);
        return ret;
 }
-IWL_EXPORT_SYMBOL(iwl_acpi_get_wgds_table);
 
 __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
 {
index ba7626543b70a8b614ed5f6901188ee0230190b4..3498deec58a55517dcf655ee550a7dfb864c9436 100644 (file)
 #define IWL_SAR_ENABLE_MSK             BIT(0)
 #define IWL_REDUCE_POWER_FLAGS_POS     1
 
+/* The Inidcator whether UEFI WIFI GUID tables are locked is read from ACPI */
+#define UEFI_WIFI_GUID_UNLOCKED                0
+
 /*
  * The profile for revision 2 is a superset of revision 1, which is in
  * turn a superset of revision 0.  So we can store all revisions
index 58290bf64f4219df0dfdc6a9a03126c9a30eac6f..862d8b8b0fc9b0829fac268f75482627aa161de5 100644 (file)
@@ -6,6 +6,23 @@
 #include "iwl-debug.h"
 #include "regulatory.h"
 #include "fw/runtime.h"
+#include "fw/uefi.h"
+
+#define IWL_BIOS_TABLE_LOADER(__name)                                  \
+int iwl_bios_get_ ## __name ## _table(struct iwl_fw_runtime *fwrt)     \
+{                                                                      \
+       int ret = -ENOENT;                                              \
+       if (fwrt->uefi_tables_lock_status > UEFI_WIFI_GUID_UNLOCKED)    \
+               ret = iwl_uefi_get_ ## __name ## _table(fwrt);          \
+       if (ret < 0)                                                    \
+               ret = iwl_acpi_get_ ## __name ## _table(fwrt);          \
+       return ret;                                                     \
+}                                                                      \
+IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name ## _table)
+
+IWL_BIOS_TABLE_LOADER(wrds);
+IWL_BIOS_TABLE_LOADER(ewrd);
+IWL_BIOS_TABLE_LOADER(wgds);
 
 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
 {
index 650430f21510ff068450118043e98ae0d3d9cb5f..73c6122e76267bc9b542b213640935ce96d2c03e 100644 (file)
@@ -87,4 +87,10 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,
                         __le16 *per_chain, u32 n_tables, u32 n_subbands,
                         int prof_a, int prof_b);
 
+int iwl_bios_get_wrds_table(struct iwl_fw_runtime *fwrt);
+
+int iwl_bios_get_ewrd_table(struct iwl_fw_runtime *fwrt);
+
+int iwl_bios_get_wgds_table(struct iwl_fw_runtime *fwrt);
+
 #endif /* __fw_regulatory_h__ */
index 08734f48443ede038b41cf0b4424e35c84496ab0..e55248b6b4c2d5548765c765dc2703c810017e34 100644 (file)
@@ -164,21 +164,21 @@ struct iwl_fw_runtime {
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        bool tpc_enabled;
 #endif /* CONFIG_IWLWIFI_DEBUGFS */
-#ifdef CONFIG_ACPI
        struct iwl_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM];
        u8 sar_chain_a_profile;
        u8 sar_chain_b_profile;
+       u8 reduced_power_flags;
        struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM];
        u32 geo_rev;
        u32 geo_num_profiles;
        bool geo_enabled;
+#ifdef CONFIG_ACPI
        struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS];
        u32 ppag_flags;
        u32 ppag_ver;
        bool ppag_table_valid;
        struct iwl_sar_offset_mapping_cmd sgom_table;
        bool sgom_enabled;
-       u8 reduced_power_flags;
        struct iwl_uats_table_cmd uats_table;
        u8 uefi_tables_lock_status;
 #endif
index 9c432d7b3674fc7562627e9fc7e2259b25e129c7..a777cd4c70f7c6b862aae7fc6034a554ec04e566 100644 (file)
@@ -413,3 +413,111 @@ int iwl_uefi_get_uats_table(struct iwl_trans *trans,
 }
 IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table);
 #endif /* CONFIG_ACPI */
+
+static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt,
+                                    struct uefi_sar_profile *uefi_sar_prof,
+                                    u8 prof_index, bool enabled)
+{
+       memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof,
+              sizeof(struct uefi_sar_profile));
+
+       fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK;
+}
+
+int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt)
+{
+       struct uefi_cnv_var_wrds *data;
+       int ret = 0;
+
+       data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME,
+                                             "WRDS", sizeof(*data), NULL);
+       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",
+                               data->revision);
+               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);
+out:
+       kfree(data);
+       return ret;
+}
+
+int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
+{
+       struct uefi_cnv_var_ewrd *data;
+       int i, ret = 0;
+
+       data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME,
+                                             "EWRD", sizeof(*data), NULL);
+       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",
+                               data->revision);
+               goto out;
+       }
+
+       if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       for (i = 0; i < data->num_profiles; i++)
+               /* The EWRD profiles officially go from 2 to 4, but we
+                * 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);
+
+out:
+       kfree(data);
+       return ret;
+}
+
+int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt)
+{
+       struct uefi_cnv_var_wgds *data;
+       int i, ret = 0;
+
+       data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME,
+                                             "WGDS", sizeof(*data), NULL);
+       if (IS_ERR(data))
+               return -EINVAL;
+
+       if (data->revision != IWL_UEFI_WGDS_REVISION) {
+               ret = -EINVAL;
+               IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n",
+                               data->revision);
+               goto out;
+       }
+
+       if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM ||
+           data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) {
+               ret = -EINVAL;
+               IWL_DEBUG_RADIO(fwrt, "Invalid number of profiles in WGDS: %d\n",
+                               data->num_profiles);
+               goto out;
+       }
+
+       fwrt->geo_rev = data->revision;
+       for (i = 0; i < data->num_profiles; i++)
+               memcpy(&fwrt->geo_profiles[i], &data->geo_profiles[i],
+                      sizeof(struct iwl_geo_profile));
+
+       fwrt->geo_num_profiles = data->num_profiles;
+       fwrt->geo_enabled = true;
+out:
+       kfree(data);
+       return ret;
+}
index bf61a8df12250b720aae9c99e4a719bf762ef9fd..3141fca047c657622be940148b3e788681259488 100644 (file)
@@ -5,15 +5,24 @@
 #ifndef __iwl_fw_uefi__
 #define __iwl_fw_uefi__
 
+#include "fw/regulatory.h"
+
 #define IWL_UEFI_OEM_PNVM_NAME         L"UefiCnvWlanOemSignedPnvm"
 #define IWL_UEFI_REDUCED_POWER_NAME    L"UefiCnvWlanReducedPower"
 #define IWL_UEFI_SGOM_NAME             L"UefiCnvWlanSarGeoOffsetMapping"
 #define IWL_UEFI_STEP_NAME             L"UefiCnvCommonSTEP"
 #define IWL_UEFI_UATS_NAME             L"CnvUefiWlanUATS"
+#define IWL_UEFI_WRDS_NAME             L"UefiCnvWlanWRDS"
+#define IWL_UEFI_EWRD_NAME             L"UefiCnvWlanEWRD"
+#define IWL_UEFI_WGDS_NAME             L"UefiCnvWlanWGDS"
 
 #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
+
 struct pnvm_sku_package {
        u8 rev;
        u32 total_size;
@@ -41,6 +50,55 @@ struct uefi_cnv_common_step_data {
        u8 radio2;
 } __packed;
 
+/*
+ * struct uefi_sar_profile - a SAR profile as defined in UEFI
+ *
+ * @chains: a per-chain table of SAR values
+ */
+struct uefi_sar_profile {
+       struct iwl_sar_profile_chain chains[BIOS_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
+ */
+struct uefi_cnv_var_wrds {
+       u8 revision;
+       u32 mode;
+       struct uefi_sar_profile sar_profile;
+} __packed;
+
+/*
+ * 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)
+ */
+struct uefi_cnv_var_ewrd {
+       u8 revision;
+       u32 mode;
+       u32 num_profiles;
+       struct uefi_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM - 1];
+} __packed;
+
+/*
+ * struct uefi_cnv_var_wgds - WGDS table as defined in UEFI
+ * @revision: the revision of the table
+ * @num_profiles: the number of geo profiles we have in the table.
+ *     The first 3 are mandatory, and can have up to 8.
+ * @geo_profiles: a per-profile table of the offsets to add to SAR values.
+ */
+struct uefi_cnv_var_wgds {
+       u8 revision;
+       u8 num_profiles;
+       struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM];
+} __packed;
+
 /*
  * This is known to be broken on v4.19 and to work on v5.4.  Until we
  * figure out why this is the case and how to make it work, simply
@@ -55,6 +113,9 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
 void iwl_uefi_get_step_table(struct iwl_trans *trans);
 int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data,
                                 u32 tlv_len, struct iwl_pnvm_image *pnvm_data);
+int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt);
+int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt);
+int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt);
 #else /* CONFIG_EFI */
 static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
 {
@@ -85,6 +146,21 @@ iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data,
 {
        return 0;
 }
+
+static inline int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt)
+{
+       return -ENOENT;
+}
+
+static inline int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
+{
+       return -ENOENT;
+}
+
+static inline int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt)
+{
+       return -ENOENT;
+}
 #endif /* CONFIG_EFI */
 
 #if defined(CONFIG_EFI) && defined(CONFIG_ACPI)
@@ -103,6 +179,5 @@ int iwl_uefi_get_uats_table(struct iwl_trans *trans,
 {
        return 0;
 }
-
 #endif
 #endif /* __iwl_fw_uefi__ */
index f964452ba433c6d9db554b4b483b336579abbbe9..c2267e0bd08ea30250cf40916adeac39545146af 100644 (file)
@@ -16,6 +16,7 @@
 #include "fw/acpi.h"
 #include "fw/pnvm.h"
 #include "fw/uefi.h"
+#include "fw/regulatory.h"
 
 #include "mvm.h"
 #include "fw/dbg.h"
@@ -895,7 +896,6 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
                                    sizeof(cmd), &cmd);
 }
 
-#ifdef CONFIG_ACPI
 int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
 {
        u32 cmd_id = REDUCE_TX_POWER_CMD;
@@ -1078,6 +1078,8 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
        return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd);
 }
 
+#ifdef CONFIG_ACPI
+
 int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
 {
        union iwl_ppag_table_cmd cmd;
@@ -1385,7 +1387,39 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
                mvm->fwrt.uats_enabled = TRUE;
 }
 
-void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm)
+#else /* CONFIG_ACPI */
+
+int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
+{
+       return -ENOENT;
+}
+
+static int iwl_mvm_ppag_init(struct iwl_mvm *mvm)
+{
+       return 0;
+}
+
+static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
+{
+}
+
+static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
+{
+}
+
+bool iwl_mvm_is_vendor_in_approved_list(void)
+{
+       return false;
+}
+
+static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm)
+{
+       return DSM_VALUE_RFI_DISABLE;
+}
+
+#endif /* CONFIG_ACPI */
+
+void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm)
 {
        int ret;
 
@@ -1400,7 +1434,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm)
        }
 
        /* read SAR tables */
-       ret = iwl_acpi_get_wrds_table(&mvm->fwrt);
+       ret = iwl_bios_get_wrds_table(&mvm->fwrt);
        if (ret < 0) {
                IWL_DEBUG_RADIO(mvm,
                                "WRDS SAR BIOS table invalid or unavailable. (%d)\n",
@@ -1409,7 +1443,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm)
                 * If not available, don't fail and don't bother with EWRD and
                 * WGDS */
 
-               if (!iwl_acpi_get_wgds_table(&mvm->fwrt)) {
+               if (!iwl_bios_get_wgds_table(&mvm->fwrt)) {
                        /*
                         * If basic SAR is not available, we check for WGDS,
                         * which should *not* be available either.  If it is
@@ -1420,7 +1454,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm)
                }
 
        } else {
-               ret = iwl_acpi_get_ewrd_table(&mvm->fwrt);
+               ret = iwl_bios_get_ewrd_table(&mvm->fwrt);
                /* if EWRD is not available, we can still use
                * WRDS, so don't fail */
                if (ret < 0)
@@ -1430,7 +1464,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm)
 
                /* read geo SAR table */
                if (iwl_sar_geo_support(&mvm->fwrt)) {
-                       ret = iwl_acpi_get_wgds_table(&mvm->fwrt);
+                       ret = iwl_bios_get_wgds_table(&mvm->fwrt);
                        if (ret < 0)
                                IWL_DEBUG_RADIO(mvm,
                                                "Geo SAR BIOS table invalid or unavailable. (%d)\n",
@@ -1441,57 +1475,6 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm)
 
        iwl_acpi_get_phy_filters(&mvm->fwrt, &mvm->phy_filters);
 }
-#else /* CONFIG_ACPI */
-
-inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm,
-                                     int prof_a, int prof_b)
-{
-       return 1;
-}
-
-inline int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
-{
-       return -ENOENT;
-}
-
-static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
-{
-       return 0;
-}
-
-int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
-{
-       return -ENOENT;
-}
-
-static int iwl_mvm_ppag_init(struct iwl_mvm *mvm)
-{
-       return 0;
-}
-
-static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
-{
-}
-
-static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
-{
-}
-
-bool iwl_mvm_is_vendor_in_approved_list(void)
-{
-       return false;
-}
-
-static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm)
-{
-       return DSM_VALUE_RFI_DISABLE;
-}
-
-void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm)
-{
-}
-
-#endif /* CONFIG_ACPI */
 
 static void iwl_mvm_disconnect_iterator(void *data, u8 *mac,
                                        struct ieee80211_vif *vif)
index d414007c4755e482bcba2e9b0fe938a2c0424294..14f4cf8a67c7691081423ec1ff91bd2fa89e052c 100644 (file)
@@ -2381,7 +2381,7 @@ u64 iwl_mvm_ptp_get_adj_time(struct iwl_mvm *mvm, u64 base_time);
 int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b);
 int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm);
 int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm);
-void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm);
+void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 void iwl_mvm_link_sta_add_debugfs(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif,
index 20054a0c7892b40f246c0a8453187ca407a1e073..1b41318e1e5500e7fcba1f1e86edeb596d30362a 100644 (file)
@@ -1201,7 +1201,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm,
                            &iwl_mvm_sanitize_ops, mvm, dbgfs_dir);
 
-       iwl_mvm_get_acpi_tables(mvm);
+       iwl_mvm_get_bios_tables(mvm);
        iwl_uefi_get_sgom_table(trans, &mvm->fwrt);
        iwl_uefi_get_step_table(trans);