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 --- drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 4 ++++ drivers/net/wireless/intel/iwlwifi/mld/tx.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 71a9a72c9ac0..0df3be3089c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -519,6 +519,10 @@ 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 8af58aabcd68..33bd2e336166 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c @@ -962,6 +962,9 @@ void iwl_mld_tx_from_txq(struct iwl_mld *mld, struct ieee80211_txq *txq) struct sk_buff *skb = NULL; u8 zero_addr[ETH_ALEN] = {}; + 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