wifi: iwlwifi: mvm: trigger PCI re-enumeration in case of PLDR sync
authorAvraham Stern <avraham.stern@intel.com>
Wed, 23 Nov 2022 21:02:07 +0000 (23:02 +0200)
committerGregory Greenman <gregory.greenman@intel.com>
Mon, 28 Nov 2022 15:53:58 +0000 (17:53 +0200)
When doing the PLDR flow, the fw goes through a re-read and needs
PCI re-enumeration in order to recover. In this case, skip the mac
start retry and fw dumps as all the fw and registers are invalid
until the PCI re-enumeration.

In addition, print the register that shows the re-read counter
when loading the fw.

Signed-off-by: Avraham Stern <avraham.stern@intel.com>
Link: https://lore.kernel.org/r/20221123225313.9ae77968961e.Ie06e886cef4b5921b65dacb7724db1276bed38cb@changeid
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-prph.h
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c

index 82cf904e0b6d956a73642c7695c0fffdc92e238a..62ce116d37834b318266ceef01b6012030f90ed8 100644 (file)
@@ -368,6 +368,7 @@ enum {
 #define CNVR_AUX_MISC_CHIP                             0xA2B800
 #define CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM         0xA29890
 #define CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR     0xA29938
+#define CNVI_SCU_SEQ_DATA_DW9                          0xA27488
 
 #define PREG_AUX_BUS_WPROT_0           0xA04CC0
 
index d659ccd065f78eab3c9f4cc24f4c8db1b499b0ef..32bd7f19f1d57cd98eb05780b783bc1bceb2e681 100644 (file)
@@ -1542,5 +1542,6 @@ void iwl_trans_free(struct iwl_trans *trans);
 ******************************************************/
 int __must_check iwl_pci_register_driver(void);
 void iwl_pci_unregister_driver(void);
+void iwl_trans_pcie_remove(struct iwl_trans *trans, bool rescan);
 
 #endif /* __iwl_trans_h__ */
index b3101d12a0a1a9e263722c4906e7ed654fbb9f91..74354d044db946578d7dcb8318b6456e260588c7 100644 (file)
@@ -364,6 +364,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
                         iwl_read_umac_prph(mvm->trans, WFPM_LMAC2_PD_NOTIFICATION));
                IWL_INFO(mvm, "WFPM_AUTH_KEY_0: 0x%x\n",
                         iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG));
+               IWL_INFO(mvm, "CNVI_SCU_SEQ_DATA_DW9: 0x%x\n",
+                        iwl_read_prph(mvm->trans, CNVI_SCU_SEQ_DATA_DW9));
        }
 
        if (ret) {
@@ -402,7 +404,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
                                                UREG_LMAC2_CURRENT_PC));
                }
 
-               if (ret == -ETIMEDOUT)
+               if (ret == -ETIMEDOUT && !mvm->pldr_sync)
                        iwl_fw_dbg_error_collect(&mvm->fwrt,
                                                 FW_DBG_TRIGGER_ALIVE_TIMEOUT);
 
@@ -1479,18 +1481,22 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
                return ret;
 
        sb_cfg = iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG);
-       if (!(sb_cfg & SB_CFG_RESIDES_IN_OTP_MASK) && iwl_mei_pldr_req())
+       mvm->pldr_sync = !(sb_cfg & SB_CFG_RESIDES_IN_OTP_MASK);
+       if (mvm->pldr_sync && iwl_mei_pldr_req())
                return ret;
 
        ret = iwl_mvm_load_rt_fw(mvm);
        if (ret) {
                IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret);
-               if (ret != -ERFKILL)
+               if (ret != -ERFKILL && !mvm->pldr_sync)
                        iwl_fw_dbg_error_collect(&mvm->fwrt,
                                                 FW_DBG_TRIGGER_DRIVER);
                goto error;
        }
 
+       /* FW loaded successfully */
+       mvm->pldr_sync = false;
+
        iwl_get_shared_mem_conf(&mvm->fwrt);
 
        ret = iwl_mvm_sf_update(mvm, NULL, false);
index 3fba69554f831d8a83cd9bb6ffe9101fb8869408..5273ade711176f2c58b96a31a93c680f91e4b2c0 100644 (file)
@@ -1068,6 +1068,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
                if (!ret)
                        break;
 
+               /*
+                * In PLDR sync PCI re-enumeration is needed. no point to retry
+                * mac start before that.
+                */
+               if (mvm->pldr_sync) {
+                       iwl_mei_alive_notif(false);
+                       iwl_trans_pcie_remove(mvm->trans, true);
+                       break;
+               }
+
                IWL_ERR(mvm, "mac start retry %d\n", retry);
        }
        clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status);
index 962e304fc2b1622ae51b0741befec14ed4d09361..ce6b701f3f4cd2ddc52c6e370199ac36fcd63e02 100644 (file)
@@ -1105,6 +1105,8 @@ struct iwl_mvm {
        unsigned long last_reset_or_resume_time_jiffies;
 
        bool sta_remove_requires_queue_remove;
+
+       bool pldr_sync;
 };
 
 /* Extract MVM priv from op_mode and _hw */
index 2a4db13c9dcfac3d8406f76ace9ac31b3eae8f1e..e78f5beaa2d0c8d99847a8c35a7414d8bd7e3c99 100644 (file)
@@ -1888,6 +1888,9 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, bool sync)
 {
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
 
+       if (mvm->pldr_sync)
+               return;
+
        if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status) &&
            !test_and_clear_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE,
                                &mvm->status))
index bd50f52a1aade1afb12f888ebc574a515f3b8dab..0a9af1ad1f2068a9bb3fc436ca7ad2fdce5e9f0a 100644 (file)
@@ -2052,6 +2052,7 @@ static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
 struct iwl_trans_pcie_removal {
        struct pci_dev *pdev;
        struct work_struct work;
+       bool rescan;
 };
 
 static void iwl_trans_pcie_removal_wk(struct work_struct *wk)
@@ -2060,18 +2061,61 @@ static void iwl_trans_pcie_removal_wk(struct work_struct *wk)
                container_of(wk, struct iwl_trans_pcie_removal, work);
        struct pci_dev *pdev = removal->pdev;
        static char *prop[] = {"EVENT=INACCESSIBLE", NULL};
+       struct pci_bus *bus = pdev->bus;
 
        dev_err(&pdev->dev, "Device gone - attempting removal\n");
        kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, prop);
        pci_lock_rescan_remove();
        pci_dev_put(pdev);
        pci_stop_and_remove_bus_device(pdev);
+       if (removal->rescan)
+               pci_rescan_bus(bus->parent);
        pci_unlock_rescan_remove();
 
        kfree(removal);
        module_put(THIS_MODULE);
 }
 
+void iwl_trans_pcie_remove(struct iwl_trans *trans, bool rescan)
+{
+       struct iwl_trans_pcie_removal *removal;
+
+       if (test_bit(STATUS_TRANS_DEAD, &trans->status))
+               return;
+
+       IWL_ERR(trans, "Device gone - scheduling removal!\n");
+
+       /*
+        * get a module reference to avoid doing this
+        * while unloading anyway and to avoid
+        * scheduling a work with code that's being
+        * removed.
+        */
+       if (!try_module_get(THIS_MODULE)) {
+               IWL_ERR(trans,
+                       "Module is being unloaded - abort\n");
+               return;
+       }
+
+       removal = kzalloc(sizeof(*removal), GFP_ATOMIC);
+       if (!removal) {
+               module_put(THIS_MODULE);
+               return;
+       }
+       /*
+        * we don't need to clear this flag, because
+        * the trans will be freed and reallocated.
+        */
+       set_bit(STATUS_TRANS_DEAD, &trans->status);
+
+       removal->pdev = to_pci_dev(trans->dev);
+       removal->rescan = rescan;
+       INIT_WORK(&removal->work, iwl_trans_pcie_removal_wk);
+       pci_dev_get(removal->pdev);
+       schedule_work(&removal->work);
+}
+EXPORT_SYMBOL(iwl_trans_pcie_remove);
+
 /*
  * This version doesn't disable BHs but rather assumes they're
  * already disabled.
@@ -2131,47 +2175,12 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
 
                iwl_trans_pcie_dump_regs(trans);
 
-               if (iwlwifi_mod_params.remove_when_gone && cntrl == ~0U) {
-                       struct iwl_trans_pcie_removal *removal;
-
-                       if (test_bit(STATUS_TRANS_DEAD, &trans->status))
-                               goto err;
-
-                       IWL_ERR(trans, "Device gone - scheduling removal!\n");
-
-                       /*
-                        * get a module reference to avoid doing this
-                        * while unloading anyway and to avoid
-                        * scheduling a work with code that's being
-                        * removed.
-                        */
-                       if (!try_module_get(THIS_MODULE)) {
-                               IWL_ERR(trans,
-                                       "Module is being unloaded - abort\n");
-                               goto err;
-                       }
-
-                       removal = kzalloc(sizeof(*removal), GFP_ATOMIC);
-                       if (!removal) {
-                               module_put(THIS_MODULE);
-                               goto err;
-                       }
-                       /*
-                        * we don't need to clear this flag, because
-                        * the trans will be freed and reallocated.
-                       */
-                       set_bit(STATUS_TRANS_DEAD, &trans->status);
-
-                       removal->pdev = to_pci_dev(trans->dev);
-                       INIT_WORK(&removal->work, iwl_trans_pcie_removal_wk);
-                       pci_dev_get(removal->pdev);
-                       schedule_work(&removal->work);
-               } else {
+               if (iwlwifi_mod_params.remove_when_gone && cntrl == ~0U)
+                       iwl_trans_pcie_remove(trans, false);
+               else
                        iwl_write32(trans, CSR_RESET,
                                    CSR_RESET_REG_FLAG_FORCE_NMI);
-               }
 
-err:
                spin_unlock(&trans_pcie->reg_lock);
                return false;
        }