]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: don't warn if the NIC is gone in resume
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 20 Apr 2025 07:00:00 +0000 (10:00 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 23 Apr 2025 12:45:29 +0000 (14:45 +0200)
Some BIOSes decide to power gate the WLAN device during S3. Since
iwlwifi doesn't expect this, it gets very noisy reporting that the
device is no longer available. Wifi is still available because iwlwifi
recovers, but it spews scary prints in the log.

Fix that by failing gracefully.

Fixes: e8bb19c1d590 ("wifi: iwlwifi: support fast resume")
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219597
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250420095642.d8d58146c829.I569ca15eaaa774d633038a749cc6ec7448419714@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-trans.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/internal.h
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c

index 6125fe70ce7288f0cae3bfb87a2d19c2e1048d4d..e7b2e08645efa7b6fc9f4d6d181adfecdcc6b9f4 100644 (file)
@@ -555,7 +555,6 @@ void __releases(nic_access)
 iwl_trans_release_nic_access(struct iwl_trans *trans)
 {
        iwl_trans_pcie_release_nic_access(trans);
-       __release(nic_access);
 }
 IWL_EXPORT_SYMBOL(iwl_trans_release_nic_access);
 
index 6c22c95f28d5edc4172a1bd14ce3100cbb186e72..3a605e7c070e43f3c16d3d1defeec75be3cc01fd 100644 (file)
@@ -1737,10 +1737,24 @@ static int _iwl_pci_resume(struct device *device, bool restore)
         * need to reset it completely.
         * Note: MAC (bits 0:7) will be cleared upon suspend even with wowlan,
         * so assume that any bits there mean that the device is usable.
+        * For older devices, just try silently to grab the NIC.
         */
-       if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ &&
-           !iwl_read32(trans, CSR_FUNC_SCRATCH))
-               device_was_powered_off = true;
+       if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) {
+               if (!iwl_read32(trans, CSR_FUNC_SCRATCH))
+                       device_was_powered_off = true;
+       } else {
+               /*
+                * bh are re-enabled by iwl_trans_pcie_release_nic_access,
+                * so re-enable them if _iwl_trans_pcie_grab_nic_access fails.
+                */
+               local_bh_disable();
+               if (_iwl_trans_pcie_grab_nic_access(trans, true)) {
+                       iwl_trans_pcie_release_nic_access(trans);
+               } else {
+                       device_was_powered_off = true;
+                       local_bh_enable();
+               }
+       }
 
        if (restore || device_was_powered_off) {
                trans->state = IWL_TRANS_NO_FW;
index 45460f93d24add5c41520db20ef68aef33d6866d..114a9195ad7f74fd70cac144404a02b0be9e62c0 100644 (file)
@@ -558,10 +558,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans);
 void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions,
                                           struct device *dev);
 
-bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans);
-#define _iwl_trans_pcie_grab_nic_access(trans)                 \
+bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent);
+#define _iwl_trans_pcie_grab_nic_access(trans, silent)         \
        __cond_lock(nic_access_nobh,                            \
-                   likely(__iwl_trans_pcie_grab_nic_access(trans)))
+                   likely(__iwl_trans_pcie_grab_nic_access(trans, silent)))
 
 void iwl_trans_pcie_check_product_reset_status(struct pci_dev *pdev);
 void iwl_trans_pcie_check_product_reset_mode(struct pci_dev *pdev);
@@ -1105,7 +1105,8 @@ void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
 int iwl_trans_pcie_read_config32(struct iwl_trans *trans, u32 ofs,
                                 u32 *val);
 bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans);
-void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans);
+void __releases(nic_access_nobh)
+iwl_trans_pcie_release_nic_access(struct iwl_trans *trans);
 
 /* transport gen 1 exported functions */
 void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr);
index b1ccace7377fbc24e2be6f89ec86cad8b14b2e2e..102a6123bba0e44affcab4d33dbe5773b9eff668 100644 (file)
@@ -2406,7 +2406,7 @@ EXPORT_SYMBOL(iwl_trans_pcie_reset);
  * This version doesn't disable BHs but rather assumes they're
  * already disabled.
  */
-bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
+bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent)
 {
        int ret;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -2458,6 +2458,11 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
        if (unlikely(ret < 0)) {
                u32 cntrl = iwl_read32(trans, CSR_GP_CNTRL);
 
+               if (silent) {
+                       spin_unlock(&trans_pcie->reg_lock);
+                       return false;
+               }
+
                WARN_ONCE(1,
                          "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
                          cntrl);
@@ -2489,7 +2494,7 @@ bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
        bool ret;
 
        local_bh_disable();
-       ret = __iwl_trans_pcie_grab_nic_access(trans);
+       ret = __iwl_trans_pcie_grab_nic_access(trans, false);
        if (ret) {
                /* keep BHs disabled until iwl_trans_pcie_release_nic_access */
                return ret;
@@ -2498,7 +2503,8 @@ bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
        return false;
 }
 
-void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
+void __releases(nic_access_nobh)
+iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
@@ -2525,6 +2531,7 @@ void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
         * scheduled on different CPUs (after we drop reg_lock).
         */
 out:
+       __release(nic_access_nobh);
        spin_unlock_bh(&trans_pcie->reg_lock);
 }
 
index bb90bcfc676399db27767d4ae63c3910ec997696..9fc4e98693ebf85ec99eea03c83cb5e29b14ec24 100644 (file)
@@ -1021,7 +1021,7 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
         * returned. This needs to be done only on NICs that have
         * apmg_wake_up_wa set (see above.)
         */
-       if (!_iwl_trans_pcie_grab_nic_access(trans))
+       if (!_iwl_trans_pcie_grab_nic_access(trans, false))
                return -EIO;
 
        /*