Skip to contentSkip to conversation

wifi: iwlwifi: mld: stop mac80211 TX queues on firmware error

PATCH In review Cole Leavitt 2 participants 4 messages Feb 14 – Feb 18

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 wifi: iwlwifi: mld: stop mac80211 TX queues on firmware error

When firmware encounters an error in the iwlmld driver, nothing prevents mac80211 from continuing to feed TX packets. The mvm driver uses atomic status bits (IWL_MVM_STATUS_HW_RESTART_REQUESTED) checked in its TX path to gate transmissions, but the mld driver has no equivalent check -- iwl_mld_tx_from_txq() only checks mld_txq->status.stop_full.

This allows TX to proceed while firmware is unresponsive, causing spinlock contention and soft lockups lasting 22-26 seconds.

Add ieee80211_stop_queues() in both iwl_mld_nic_error() and iwl_mld_sw_reset() to stop TX at the mac80211 level when a restart will follow, and add the corresponding ieee80211_wake_queues() in iwl_mld_restart_cleanup() to resume TX after recovery.

The stop in iwl_mld_nic_error() is placed inside the conditional that sets in_hw_restart to ensure queues are only stopped when a restart will actually follow, avoiding a permanent TX stall on error paths where no restart occurs (e.g. IWL_ERR_TYPE_RESET_HS_TIMEOUT with !fw_status.running). The stop in iwl_mld_sw_reset() is unconditional since that path always sets in_hw_restart.

Tested on ThinkPad P16 Gen3 with Intel BE200 (WiFi7) running kernel 6.19.0-rc8.

Fixes d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver")
---
 drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 2 ++
 drivers/net/wireless/intel/iwlwifi/mld/mld.c      | 5 ++++-
 2 files changed, 6 insertions(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +2 -0
index df8221277d51..552888538e16 100644
@@ -558,6 +558,8 @@ iwl_mld_restart_cleanup(struct iwl_mld *mld)
 					  iwl_mld_cleanup_sta, NULL);
 
 	iwl_mld_ftm_restart_cleanup(mld);
+
+	ieee80211_wake_queues(mld->hw);
 }
 
 static
drivers/net/wireless/intel/iwlwifi/mld/mld.c +4 -1
index 495e9d8f3af6..ed44c10c08a1 100644
@@ -672,8 +672,10 @@ iwl_mld_nic_error(struct iwl_op_mode *op_mode,
 	 * setting doesn't matter if we're going to be unbound either.
 	 */
 	if (type != IWL_ERR_TYPE_RESET_HS_TIMEOUT &&
-	    mld->fw_status.running)
+	    mld->fw_status.running) {
+		ieee80211_stop_queues(mld->hw);
 		mld->fw_status.in_hw_restart = true;
+	}
 }
 
 static void iwl_mld_dump_error(struct iwl_op_mode *op_mode,
@@ -703,6 +705,7 @@ static bool iwl_mld_sw_reset(struct iwl_op_mode *op_mode,
 	 * had a NIC error both were already done.
 	 */
 	iwl_mld_report_scan_aborted(mld);
+	ieee80211_stop_queues(mld->hw);
 	mld->fw_status.in_hw_restart = true;
 
 	/* Do restart only in the following conditions are met:

base-commit: 66af8ac52d10ea229d5755b8700e2fe86fc037f7

Signature · 1 line
2.52.0
#1 lore raw

PATCH 1/1 wifi: iwlwifi: mld: stop mac80211 TX queues on firmware error

When firmware encounters an error in the iwlmld driver, nothing prevents mac80211 from continuing to feed TX packets. The mvm driver uses atomic status bits (IWL_MVM_STATUS_HW_RESTART_REQUESTED) checked in its TX path to gate transmissions, but the mld driver has no equivalent check -- iwl_mld_tx_from_txq() only checks mld_txq->status.stop_full.

This allows TX to proceed while firmware is unresponsive, causing spinlock contention and soft lockups lasting 22-26 seconds.

Add ieee80211_stop_queues() in both iwl_mld_nic_error() and iwl_mld_sw_reset() to stop TX at the mac80211 level when a restart will follow, and add the corresponding ieee80211_wake_queues() in iwl_mld_restart_cleanup() to resume TX after recovery.

The stop in iwl_mld_nic_error() is placed inside the conditional that sets in_hw_restart to ensure queues are only stopped when a restart will actually follow, avoiding a permanent TX stall on error paths where no restart occurs (e.g. IWL_ERR_TYPE_RESET_HS_TIMEOUT with !fw_status.running). The stop in iwl_mld_sw_reset() is unconditional since that path always sets in_hw_restart.

Tested on ThinkPad P16 Gen3 with Intel BE200 (WiFi7) running kernel 6.19.0-rc8.

Fixes d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver")
---
 drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 2 ++
 drivers/net/wireless/intel/iwlwifi/mld/mld.c      | 5 ++++-
 2 files changed, 6 insertions(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +2 -0
index df8221277d51..552888538e16 100644
@@ -558,6 +558,8 @@ iwl_mld_restart_cleanup(struct iwl_mld *mld)
 					  iwl_mld_cleanup_sta, NULL);
 
 	iwl_mld_ftm_restart_cleanup(mld);
+
+	ieee80211_wake_queues(mld->hw);
 }
 
 static
drivers/net/wireless/intel/iwlwifi/mld/mld.c +4 -1
index 495e9d8f3af6..ed44c10c08a1 100644
@@ -672,8 +672,10 @@ iwl_mld_nic_error(struct iwl_op_mode *op_mode,
 	 * setting doesn't matter if we're going to be unbound either.
 	 */
 	if (type != IWL_ERR_TYPE_RESET_HS_TIMEOUT &&
-	    mld->fw_status.running)
+	    mld->fw_status.running) {
+		ieee80211_stop_queues(mld->hw);
 		mld->fw_status.in_hw_restart = true;
+	}
 }
 
 static void iwl_mld_dump_error(struct iwl_op_mode *op_mode,
@@ -703,6 +705,7 @@ static bool iwl_mld_sw_reset(struct iwl_op_mode *op_mode,
 	 * had a NIC error both were already done.
 	 */
 	iwl_mld_report_scan_aborted(mld);
+	ieee80211_stop_queues(mld->hw);
 	mld->fw_status.in_hw_restart = true;
 
 	/* Do restart only in the following conditions are met:

base-commit: 66af8ac52d10ea229d5755b8700e2fe86fc037f7

Signature · 1 line
2.52.0
#2 lore raw
In reply to Cole Leavitt
Quoted 10 lines · Cole Leavitt

When firmware encounters an error in the iwlmld driver, nothing prevents mac80211 from continuing to feed TX packets. The mvm driver uses atomic status bits (IWL_MVM_STATUS_HW_RESTART_REQUESTED) checked in its TX path to gate transmissions, but the mld driver has no equivalent check -- iwl_mld_tx_from_txq() only checks mld_txq->status.stop_full.

This allows TX to proceed while firmware is unresponsive, causing spinlock contention and soft lockups lasting 22-26 seconds.

Add ieee80211_stop_queues()

Using stop_queues()/wake_queues() seems a bit awkward, that API doesn't interact all that well with the TXQ-based APIs that we use in this driver. Shouldn't it just stop pulling from the TXQs in that case?

johannes

#3 lore raw

PATCH v2 1/1 wifi: iwlwifi: mld: skip TX when firmware is dead

In reply to Cole Leavitt

When firmware encounters an error, STATUS_FW_ERROR is set but the mac80211 TX path continues pulling frames from TXQs. Each frame fails at iwl_trans_tx() which checks STATUS_FW_ERROR and returns -EIO, but iwl_mld_tx_from_txq() keeps looping over every queued frame. This burns CPU in a tight loop on dead firmware and can cause soft lockups during firmware error recovery.

Add a STATUS_FW_ERROR check at the top of iwl_mld_tx_from_txq() to stop pulling frames from mac80211 TXQs when firmware is dead. Also guard iwl_mld_mac80211_tx() which bypasses the TXQ path entirely and would otherwise continue feeding frames to dead firmware.

Once STATUS_FW_ERROR is cleared during firmware restart, TX resumes naturally with no explicit wake needed.

Fixes d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver")

---
v2:
- Replace ieee80211_stop_queues()/wake_queues() with STATUS_FW_ERROR checks in the TX pull path, per Johannes Berg's feedback that stop/wake_queues doesn't interact well with TXQ-based APIs.
- Guard both iwl_mld_tx_from_txq() (TXQ pull path) and iwl_mld_mac80211_tx() (direct mac80211 TX path).
- Drop all changes to mld.c (no stop/wake in error/restart flows).

 drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 5 +++++
 drivers/net/wireless/intel/iwlwifi/mld/tx.c       | 8 ++++++++
 2 files changed, 13 insertions(+)
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +5 -0
index 3414b04a6953..1bd8411965f5 100644
@@ -519,6 +519,11 @@ iwl_mld_mac80211_tx(struct ieee80211_hw *hw,
 	u32 link_id = u32_get_bits(info->control.flags,
 				   IEEE80211_TX_CTRL_MLO_LINK);
 
+	if (unlikely(test_bit(STATUS_FW_ERROR, &mld->trans->status))) {
+		ieee80211_free_txskb(hw, skb);
+		return;
+	}
+
 	/* In AP mode, mgmt frames are sent on the bcast station,
 	 * so the FW can't translate the MLD addr to the link addr. Do it here
 	 */
drivers/net/wireless/intel/iwlwifi/mld/tx.c +8 -0
index 7c6a4b4e5523..fbb672f4d8c7 100644
@@ -970,6 +970,14 @@ void iwl_mld_tx_from_txq(struct iwl_mld *mld, struct ieee80211_txq *txq)
 	struct sk_buff *skb = NULL;
 	u8 zero_addr[ETH_ALEN] = {};
 
+	/* Firmware is dead - don't pull frames from mac80211 TXQs.
+	 * Packets dequeued here would fail at iwl_trans_tx() anyway,
+	 * but looping over every queued frame burns CPU and causes
+	 * soft lockups during firmware error recovery.
+	 */
+	if (unlikely(test_bit(STATUS_FW_ERROR, &mld->trans->status)))
+		return;
+
 	/*
 	 * No need for threads to be pending here, they can leave the first
 	 * taker all the work.
Signature · 1 line
2.52.0