]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: iwlwifi: pcie: check for WiAMT/CSME presence
authorJohannes Berg <johannes.berg@intel.com>
Tue, 31 Dec 2024 11:59:01 +0000 (13:59 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 13 Jan 2025 14:34:06 +0000 (15:34 +0100)
In order to know whether or not a product reset can safely
be done (without risking locking up the system completely),
check for ME presence with the known methods.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20241231135726.0ac9173f1f37.Id83b80b61548b8f4f01e96a356dafe063543c4ac@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-csr.h
drivers/net/wireless/intel/iwlwifi/iwl-prph.h
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/pcie/drv.c

index c2cd5c24646bffd01133ba396e1a63d01da81ec3..b4462bc1cf229d0b0840cd9a752655c567e08aeb 100644 (file)
 /* NOTE: EEPROM_OWN_SEM is no longer defined for new HW */
 #define CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM            0x00200000
 #define CSR_HW_IF_CONFIG_REG_PCI_OWN_SET               0x00400000
+#define CSR_HW_IF_CONFIG_REG_IAMT_UP                   0x01000000
 #define CSR_HW_IF_CONFIG_REG_ME_OWN                    0x02000000
 #define CSR_HW_IF_CONFIG_REG_WAKE_ME                   0x08000000
 #define CSR_HW_IF_CONFIG_REG_WAKE_ME_PCIE_OWNER_EN     0x10000000
index 8d4ff42da35a8c690645139f9bc43f3148590b61..23b2009fbb28b76620badfa9663a5022324ede13 100644 (file)
@@ -381,6 +381,10 @@ enum {
 #define CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR     0xA29938
 #define CNVI_SCU_SEQ_DATA_DW9                          0xA27488
 
+#define CNVI_SCU_REG_FOR_ECO_1                         0xA26EF8
+#define   CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN           BIT(4)
+#define   CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT         BIT(5)
+
 #define CNVI_PMU_STEP_FLOW                             0xA2D588
 #define CNVI_PMU_STEP_FLOW_FORCE_URM                   BIT(2)
 
index 45c5245136a7bc237c466a921ba8b46e636056b3..c342a4d6ca6c737228f1a6db0fcb33c56c7e38f9 100644 (file)
@@ -882,6 +882,9 @@ struct iwl_txq {
  * @restart.wk: restart worker
  * @restart.mode: reset/restart error mode information
  * @restart.during_reset: error occurred during previous software reset
+ * @me_recheck_wk: worker to recheck WiAMT/CSME presence
+ * @me_present: WiAMT/CSME is detected as present (1), not present (0)
+ *     or unknown (-1, so can still use it as a boolean safely)
  * @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
@@ -960,6 +963,9 @@ struct iwl_trans {
                bool during_reset;
        } restart;
 
+       struct delayed_work me_recheck_wk;
+       s8 me_present;
+
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
        char trans_specific[] __aligned(sizeof(void *));
index 69cf349e76f6c1888ece38818cbada2468c06c78..c0b249c1ea8cf2ebd03f61befbdd831e90fe4f67 100644 (file)
@@ -1410,6 +1410,47 @@ iwl_pci_find_dev_info(u16 device, u16 subsystem_device,
 }
 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_pci_find_dev_info);
 
+static void iwl_pcie_recheck_me_status(struct work_struct *wk)
+{
+       struct iwl_trans *trans = container_of(wk, typeof(*trans),
+                                              me_recheck_wk.work);
+       u32 val;
+
+       val = iwl_read32(trans, CSR_HW_IF_CONFIG_REG);
+       trans->me_present = !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP);
+}
+
+static void iwl_pcie_check_me_status(struct iwl_trans *trans)
+{
+       u32 val;
+
+       trans->me_present = -1;
+
+       INIT_DELAYED_WORK(&trans->me_recheck_wk,
+                         iwl_pcie_recheck_me_status);
+
+       /* we don't have a good way of determining this until BZ */
+       if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ)
+               return;
+
+       val = iwl_read_prph(trans, CNVI_SCU_REG_FOR_ECO_1);
+       if (val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN) {
+               trans->me_present =
+                       !!(val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT);
+               return;
+       }
+
+       val = iwl_read32(trans, CSR_HW_IF_CONFIG_REG);
+       if (val & (CSR_HW_IF_CONFIG_REG_ME_OWN |
+                  CSR_HW_IF_CONFIG_REG_IAMT_UP)) {
+               trans->me_present = 1;
+               return;
+       }
+
+       /* recheck again later, ME might still be initializing */
+       schedule_delayed_work(&trans->me_recheck_wk, HZ);
+}
+
 static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        const struct iwl_cfg_trans_params *trans;
@@ -1585,6 +1626,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_drvdata(pdev, iwl_trans);
 
+       iwl_pcie_check_me_status(iwl_trans);
+
        /* try to get ownership so that we'll know if we don't own it */
        iwl_pcie_prepare_card_hw(iwl_trans);
 
@@ -1612,6 +1655,8 @@ static void iwl_pci_remove(struct pci_dev *pdev)
        if (!trans)
                return;
 
+       cancel_delayed_work_sync(&trans->me_recheck_wk);
+
        iwl_drv_stop(trans->drv);
 
        iwl_trans_pcie_free(trans);