]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: interpret STEP URM BIOS configuration
authorSomashekhar(Som) <somashekhar.puttagangaiah@intel.com>
Fri, 27 Dec 2024 08:01:02 +0000 (10:01 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 13 Jan 2025 14:26:38 +0000 (15:26 +0100)
For certain platforms, it may necessary to use the STEP in URM
(ultra reliable mode.) Read the necessary flags from the BIOS
(ACPI or UEFI) and indicate the chosen mode to the firmware in
the context info. Whether or not URM really was configured is
already read back later, to adjust capabilities accordingly.

Signed-off-by: Somashekhar(Som) <somashekhar.puttagangaiah@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Reviewed-by: Daniel Gabay <daniel.gabay@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20241227095718.b30024905de3.If3c578af2c15f8005bbe71499bc4091348ed7bb0@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/uefi.c
drivers/net/wireless/intel/iwlwifi/fw/uefi.h
drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c

index 7d6e6c80b892ec47dfa577ca4e948c72c6db2f1d..d3ab40fc8ab09ec30bd99c9f8b495c2d71f910e1 100644 (file)
@@ -1023,3 +1023,37 @@ out_free:
        kfree(data);
        return ret;
 }
+
+int iwl_acpi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+       union acpi_object *wifi_pkg, *data;
+       int ret = -ENOENT;
+       int tbl_rev;
+
+       data = iwl_acpi_get_object(fwrt->dev, ACPI_DSBR_METHOD);
+       if (IS_ERR(data))
+               return ret;
+
+       wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
+                                        ACPI_DSBR_WIFI_DATA_SIZE,
+                                        &tbl_rev);
+       if (IS_ERR(wifi_pkg))
+               goto out_free;
+
+       if (tbl_rev != ACPI_DSBR_WIFI_DATA_REV) {
+               IWL_DEBUG_RADIO(fwrt, "Unsupported ACPI DSBR revision:%d\n",
+                               tbl_rev);
+               goto out_free;
+       }
+
+       if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
+               goto out_free;
+
+       *value = wifi_pkg->package.elements[1].integer.value;
+       IWL_DEBUG_RADIO(fwrt, "Loaded DSBR config from ACPI value: 0x%x\n",
+                       *value);
+       ret = 0;
+out_free:
+       kfree(data);
+       return ret;
+}
index bb88398a69876435c227c911ab0882224911f978..e153c44d5c1dd158db0ad1bd84e2e731a9b4abe7 100644 (file)
@@ -28,6 +28,7 @@
 #define ACPI_WPFC_METHOD       "WPFC"
 #define ACPI_GLAI_METHOD       "GLAI"
 #define ACPI_WBEM_METHOD       "WBEM"
+#define ACPI_DSBR_METHOD       "DSBR"
 
 #define ACPI_WIFI_DOMAIN       (0x07)
 
  * and one for enablement of Wi-Fi 320MHz per MCC
  */
 #define ACPI_WBEM_WIFI_DATA_SIZE       2
+/*
+ * One element for domain type,
+ * and one for DSBR response data
+ */
+#define ACPI_DSBR_WIFI_DATA_SIZE       2
+#define ACPI_DSBR_WIFI_DATA_REV                1
+
 /*
  * One element for domain type,
  * and one for the status
@@ -153,6 +161,9 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt,
                     enum iwl_dsm_funcs func, u32 *value);
 
 int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value);
+
+int iwl_acpi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value);
+
 #else /* CONFIG_ACPI */
 
 static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev,
@@ -221,6 +232,11 @@ static inline int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
 {
        return -ENOENT;
 }
+
+static inline int iwl_acpi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+       return -ENOENT;
+}
 #endif /* CONFIG_ACPI */
 
 #endif /* __iwl_fw_acpi__ */
index c89ff380b86d7eafaf7666164d89d03c620d1ab8..bc359a336fd60c475c84b9a95b547514529afeb4 100644 (file)
@@ -39,6 +39,7 @@ IWL_BIOS_TABLE_LOADER_DATA(pwr_limit, u64);
 IWL_BIOS_TABLE_LOADER_DATA(mcc, char);
 IWL_BIOS_TABLE_LOADER_DATA(eckv, u32);
 IWL_BIOS_TABLE_LOADER_DATA(wbem, u32);
+IWL_BIOS_TABLE_LOADER_DATA(dsbr, u32);
 
 
 static const struct dmi_system_id dmi_ppag_approved_list[] = {
index f247d31ebdd6e2491d1e6bf122e049ddc345f885..afdc0ec75ba5674ba326992d4f816c250c06b8b4 100644 (file)
@@ -222,4 +222,27 @@ static inline u32 iwl_bios_get_ppag_flags(const u32 ppag_modes,
 }
 
 bool iwl_puncturing_is_allowed_in_bios(u32 puncturing, u16 mcc);
+
+#define IWL_DSBR_FW_MODIFIED_URM_MASK  BIT(8)
+#define IWL_DSBR_PERMANENT_URM_MASK    BIT(9)
+
+int iwl_bios_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value);
+
+static inline void iwl_bios_setup_step(struct iwl_trans *trans,
+                                      struct iwl_fw_runtime *fwrt)
+{
+       u32 dsbr;
+
+       if (!trans->trans_cfg->integrated)
+               return;
+
+       if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ)
+               return;
+
+       if (iwl_bios_get_dsbr(fwrt, &dsbr))
+               dsbr = 0;
+
+       trans->dsbr_urm_fw_dependent = !!(dsbr & IWL_DSBR_FW_MODIFIED_URM_MASK);
+       trans->dsbr_urm_permanent = !!(dsbr & IWL_DSBR_PERMANENT_URM_MASK);
+}
 #endif /* __fw_regulatory_h__ */
index 02df96c3aa51076d933902c5ae8e19ffab73909a..cc7659d59cf05e1ade71cea3fa43776a3538eadc 100644 (file)
@@ -777,3 +777,29 @@ int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt)
        return puncturing;
 }
 IWL_EXPORT_SYMBOL(iwl_uefi_get_puncturing);
+
+int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+       struct uefi_cnv_wlan_dsbr_data *data;
+       int ret = 0;
+
+       data = iwl_uefi_get_verified_variable_guid(fwrt->trans,
+                                                  &IWL_EFI_WIFI_BT_GUID,
+                                                  IWL_UEFI_DSBR_NAME, "DSBR",
+                                                  sizeof(*data), NULL);
+       if (IS_ERR(data))
+               return -EINVAL;
+
+       if (data->revision != IWL_UEFI_DSBR_REVISION) {
+               ret = -EINVAL;
+               IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSBR revision:%d\n",
+                               data->revision);
+               goto out;
+       }
+       *value = data->config;
+       IWL_DEBUG_RADIO(fwrt, "Loaded DSBR config from UEFI value: 0x%x\n",
+                       *value);
+out:
+       kfree(data);
+       return ret;
+}
index 4e98f752b3d2109da6399f827bd9f387de4c38c2..0c8943a8bd01155f02d135b3939e0bc38476ded5 100644 (file)
@@ -23,6 +23,7 @@
 #define IWL_UEFI_DSM_NAME              L"UefiCnvWlanGeneralCfg"
 #define IWL_UEFI_WBEM_NAME             L"UefiCnvWlanWBEM"
 #define IWL_UEFI_PUNCTURING_NAME       L"UefiCnvWlanPuncturing"
+#define IWL_UEFI_DSBR_NAME             L"UefiCnvCommonDSBR"
 
 
 #define IWL_SGOM_MAP_SIZE              339
@@ -41,6 +42,7 @@
 #define IWL_UEFI_WBEM_REVISION         0
 #define IWL_UEFI_DSM_REVISION          4
 #define IWL_UEFI_PUNCTURING_REVISION   0
+#define IWL_UEFI_DSBR_REVISION         1
 
 struct pnvm_sku_package {
        u8 rev;
@@ -214,6 +216,20 @@ struct uefi_cnv_var_puncturing_data {
        u32 puncturing;
 } __packed;
 
+/**
+ * struct uefi_cnv_wlan_dsbr_data - BIOS STEP configuration information
+ * @revision: the revision of the table
+ * @config: STEP configuration flags:
+ *     bit 8, switch to URM depending on FW setting
+ *     bit 9, switch to URM
+ *
+ * Platform information for STEP configuration/workarounds.
+ */
+struct uefi_cnv_wlan_dsbr_data {
+       u8 revision;
+       u32 config;
+} __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
@@ -245,6 +261,7 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwr
 int iwl_uefi_get_uats_table(struct iwl_trans *trans,
                            struct iwl_fw_runtime *fwrt);
 int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt);
+int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value);
 #else /* CONFIG_EFI */
 static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
 {
@@ -347,5 +364,11 @@ int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt)
 {
        return 0;
 }
+
+static inline
+int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+       return -ENOENT;
+}
 #endif /* CONFIG_EFI */
 #endif /* __iwl_fw_uefi__ */
index 5b62933134cf4658e64a2e8ff315c1dbfca60e41..6b246ec3ff03e43758664ebfda0d150686cb19f0 100644 (file)
@@ -76,6 +76,16 @@ enum iwl_prph_scratch_flags {
        IWL_PRPH_SCRATCH_SCU_FORCE_ACTIVE       = BIT(29),
 };
 
+/**
+ * enum iwl_prph_scratch_ext_flags - PRPH scratch control ext flags
+ * @IWL_PRPH_SCRATCH_EXT_URM_FW: switch to URM mode based on fw setting
+ * @IWL_PRPH_SCRATCH_EXT_URM_PERM: switch to permanent URM mode
+ */
+enum iwl_prph_scratch_ext_flags {
+       IWL_PRPH_SCRATCH_EXT_URM_FW     = BIT(4),
+       IWL_PRPH_SCRATCH_EXT_URM_PERM   = BIT(5),
+};
+
 /*
  * struct iwl_prph_scratch_version - version structure
  * @mac_id: SKU and revision id
@@ -93,11 +103,12 @@ struct iwl_prph_scratch_version {
 /*
  * struct iwl_prph_scratch_control - control structure
  * @control_flags: context information flags see &enum iwl_prph_scratch_flags
- * @reserved: reserved
+ * @control_flags_ext: context information for extended flags,
+ *     see &enum iwl_prph_scratch_ext_flags
  */
 struct iwl_prph_scratch_control {
        __le32 control_flags;
-       __le32 reserved;
+       __le32 control_flags_ext;
 } __packed; /* PERIPH_SCRATCH_CONTROL_S */
 
 /*
index 56b551fd215622ec9029bd44495d5a6cf18ed321..22c0864b5704be24b9ad58faf7f142c75cf2e1b1 100644 (file)
@@ -878,6 +878,8 @@ struct iwl_txq {
  * @no_160: device not supporting 160 MHz
  * @step_urm: STEP is in URM, no support for MCS>9 in 320 MHz
  * @trans_specific: data for the specific transport this is allocated for/with
+ * @dsbr_urm_fw_dependent: switch to URM based on fw settings
+ * @dsbr_urm_permanent: switch to URM permanently
  */
 struct iwl_trans {
        bool csme_own;
@@ -902,6 +904,9 @@ struct iwl_trans {
        bool reduced_cap_sku;
        u8 no_160:1, step_urm:1;
 
+       u8 dsbr_urm_fw_dependent:1,
+          dsbr_urm_permanent:1;
+
        u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size;
 
        bool pm_support;
index e21199313278e3c389d6a4aece71b68361c57f78..06b05e076cd230ba89f1d09abf6336af2c8a293e 100644 (file)
@@ -1331,6 +1331,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        iwl_mvm_get_bios_tables(mvm);
        iwl_uefi_get_sgom_table(trans, &mvm->fwrt);
        iwl_uefi_get_step_table(trans);
+       iwl_bios_setup_step(trans, &mvm->fwrt);
 
        mvm->init_status = 0;
 
index ae93a72542b28199fa985c1a7c075eb586820981..838c426db7f05397f1dcc28a62c3b7be5f303fc5 100644 (file)
@@ -106,6 +106,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
        struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl;
        struct iwl_prph_info *prph_info;
        u32 control_flags = 0;
+       u32 control_flags_ext = 0;
        int ret;
        int cmdq_size = max_t(u32, IWL_CMD_QUEUE_SIZE,
                              trans->cfg->min_txq_size);
@@ -130,6 +131,12 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
                break;
        }
 
+       if (trans->dsbr_urm_fw_dependent)
+               control_flags_ext |= IWL_PRPH_SCRATCH_EXT_URM_FW;
+
+       if (trans->dsbr_urm_permanent)
+               control_flags_ext |= IWL_PRPH_SCRATCH_EXT_URM_PERM;
+
        /* Allocate prph scratch */
        prph_scratch = dma_alloc_coherent(trans->dev, sizeof(*prph_scratch),
                                          &trans_pcie->prph_scratch_dma_addr,
@@ -165,6 +172,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
        iwl_pcie_ctxt_info_dbg_enable(trans, &prph_sc_ctrl->hwm_cfg,
                                      &control_flags);
        prph_sc_ctrl->control.control_flags = cpu_to_le32(control_flags);
+       prph_sc_ctrl->control.control_flags_ext = cpu_to_le32(control_flags_ext);
 
        /* initialize the Step equalizer data */
        prph_sc_ctrl->step_cfg.mbx_addr_0 = cpu_to_le32(trans->mbx_addr_0_step);