]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: transport: add memory read under NIC access
authorJohannes Berg <johannes.berg@intel.com>
Sun, 17 May 2026 07:59:59 +0000 (10:59 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 26 May 2026 12:17:13 +0000 (15:17 +0300)
Add functions to be able to do memory read under NIC access,
in order to use them later during firmware dump. These may
drop and re-acquire the spinlock, but will not acquire and
release the NIC access.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Link: https://patch.msgid.link/20260517100550.7bb1ea51c347.I91420a24fb0c481c75a2600d60e1365c15c1c5a9@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-trans.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h
drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c

index 5b44e15fe64d599e7de9239caa0f25fcf0029cc6..0009488ca51b132f4fc759c74141cb6b7521e80d 100644 (file)
@@ -459,6 +459,12 @@ int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr,
 }
 IWL_EXPORT_SYMBOL(iwl_trans_read_mem);
 
+int iwl_trans_read_mem_no_grab(struct iwl_trans *trans, u32 addr,
+                              void *buf, u32 dwords)
+{
+       return iwl_trans_pcie_read_mem_no_grab(trans, addr, buf, dwords);
+}
+
 int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr,
                        const void *buf, int dwords)
 {
index 1ed6bcb7882c8ccdbe4080204f68476b527b0939..3ae840e546e8211212382f38b7eb7c687ba0753a 100644 (file)
@@ -919,6 +919,14 @@ void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, u32 val);
 int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr,
                       void *buf, int dwords);
 
+/*
+ * Note the special calling convention - it's allowed to drop the
+ * internal transport lock and re-enable BHs temporarily, but will
+ * not release NIC access.
+ */
+int iwl_trans_read_mem_no_grab(struct iwl_trans *trans, u32 addr,
+                              void *buf, u32 dwords);
+
 int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs,
                            u32 *val);
 
@@ -934,6 +942,14 @@ void iwl_trans_debugfs_cleanup(struct iwl_trans *trans);
                                   (bufsize) / sizeof(u32));    \
        })
 
+static inline int
+iwl_trans_read_mem_bytes_no_grab(struct iwl_trans *trans,
+                                u32 addr, void *buf, u32 bufsize)
+{
+       return iwl_trans_read_mem_no_grab(trans, addr, buf,
+                                         bufsize / sizeof(u32));
+}
+
 int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr,
                            u64 src_addr, u32 byte_cnt);
 
index 24f8714eae9f10a92fd92bfa3b81ab4f4caaa283..abc0c831d1ca73e910eb7aab0d9f963f384c7268 100644 (file)
@@ -1186,6 +1186,8 @@ u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg);
 void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr, u32 val);
 int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
                            void *buf, int dwords);
+int iwl_trans_pcie_read_mem_no_grab(struct iwl_trans *trans, u32 addr,
+                                   void *buf, u32 dwords);
 int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, bool retake_ownership);
 struct iwl_trans_dump_data *
 iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 dump_mask,
index 50342604491de72beb625a1a03acb46775d108ae..1c4ee76d8387731c14047fef973501b4c30cc764 100644 (file)
@@ -2424,6 +2424,15 @@ bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
        return false;
 }
 
+static void iwl_trans_pcie_resched_with_nic_access(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       spin_unlock_bh(&trans_pcie->reg_lock);
+       cond_resched();
+       spin_lock_bh(&trans_pcie->reg_lock);
+}
+
 void __releases(nic_access_nobh)
 iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
 {
@@ -2506,6 +2515,51 @@ int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
        return 0;
 }
 
+int iwl_trans_pcie_read_mem_no_grab(struct iwl_trans *trans, u32 addr,
+                                   void *buf, u32 dwords)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+#define IWL_MAX_HW_ERRS 5
+       unsigned int num_consec_hw_errors = 0;
+       u32 offs = 0;
+       u32 *vals = buf;
+
+       lockdep_assert_held(&trans_pcie->reg_lock);
+
+       while (offs < dwords) {
+               /* limit the time we spin here under lock to 1/2s */
+               unsigned long end = jiffies + HZ / 2;
+               bool resched = false;
+
+               iwl_write32(trans, HBUS_TARG_MEM_RADDR,
+                           addr + 4 * offs);
+
+               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)
+                               return -EIO;
+
+                       offs++;
+
+                       if (time_after(jiffies, end)) {
+                               resched = true;
+                               break;
+                       }
+               }
+
+               if (resched)
+                       iwl_trans_pcie_resched_with_nic_access(trans);
+       }
+
+       return 0;
+}
+
 int iwl_trans_pcie_read_config32(struct iwl_trans *trans, u32 ofs,
                                 u32 *val)
 {