summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2026-05-17 10:59:59 +0300
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>2026-05-26 15:17:13 +0300
commit4f479cbee68509ef56e4be310da93ec7883feb65 (patch)
treea89512e22521b8252c4fa1931b19f737f3c5f115
parent90b2f286bc7d4a5b7ed5f9892ec2d2a821c356fd (diff)
downloadlinux-4f479cbee68509ef56e4be310da93ec7883feb65.tar.xz
wifi: iwlwifi: transport: add memory read under NIC access
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>
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c54
4 files changed, 78 insertions, 0 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
index 5b44e15fe64d..0009488ca51b 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
@@ -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)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 1ed6bcb7882c..3ae840e546e8 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -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);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h
index 24f8714eae9f..abc0c831d1ca 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h
@@ -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,
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
index 50342604491d..1c4ee76d8387 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
@@ -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)
{