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") Signed-off-by: Cole Leavitt --- 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(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 3414b04a6953..1bd8411965f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -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 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c index 7c6a4b4e5523..fbb672f4d8c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c @@ -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. -- 2.52.0