wifi: iwlwifi: pcie: give up mem read if HW is dead
authorJohannes Berg <johannes.berg@intel.com>
Wed, 13 Sep 2023 11:56:38 +0000 (14:56 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 13 Sep 2023 14:11:39 +0000 (16:11 +0200)
If the hardware is not responding, as indicated by (currently)
five consecutive HW errors during reading, then just give up
and fail, rather than attempting forever and forever for this
to not return any useful data anyway.

Even though we no longer completely deadlock the machine if it
takes a long time, we still make it pretty much unusable since
we'll eventually hold the RTNL while waiting for this process
to finish.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230913145231.345af79f431c.I5ecde6b76b1e3a1572bd59d3cf8f827e767cedeb@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/pcie/trans.c

index 51012435e39b5b082193d3ace87748a43eef323d..93e10d7d12fb5159e0fb5cdd1a558f238d88c47d 100644 (file)
@@ -2288,6 +2288,8 @@ out:
 static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
                                   void *buf, int dwords)
 {
+#define IWL_MAX_HW_ERRS 5
+       unsigned int num_consec_hw_errors = 0;
        int offs = 0;
        u32 *vals = buf;
 
@@ -2303,6 +2305,17 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
                        while (offs < dwords) {
                                vals[offs] = iwl_read32(trans,
                                                        HBUS_TARG_MEM_RDAT);
+
+                               if (iwl_trans_is_hw_error_value(vals[offs]))
+                                       num_consec_hw_errors++;
+                               else
+                                       num_consec_hw_errors = 0;
+
+                               if (num_consec_hw_errors >= IWL_MAX_HW_ERRS) {
+                                       iwl_trans_release_nic_access(trans);
+                                       return -EIO;
+                               }
+
                                offs++;
 
                                if (time_after(jiffies, end)) {