diff options
author | Alexander Wetzel <alexander@wetzel-home.de> | 2022-12-30 13:18:49 +0100 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2023-01-10 13:24:12 +0100 |
commit | 4444bc2116aecdcde87dce80373540adc8bd478b (patch) | |
tree | 3dd34af4a436d1feca6c6f1045033bd54cfa1dda /net/mac80211/tx.c | |
parent | e66b7920aa5ac5b1a1997a454004ba9246a3c005 (diff) | |
download | linux-4444bc2116aecdcde87dce80373540adc8bd478b.tar.gz linux-4444bc2116aecdcde87dce80373540adc8bd478b.tar.bz2 linux-4444bc2116aecdcde87dce80373540adc8bd478b.zip |
wifi: mac80211: Proper mark iTXQs for resumption
When a running wake_tx_queue() call is aborted due to a hw queue stop
the corresponding iTXQ is not always correctly marked for resumption:
wake_tx_push_queue() can stops the queue run without setting
@IEEE80211_TXQ_STOP_NETIF_TX.
Without the @IEEE80211_TXQ_STOP_NETIF_TX flag __ieee80211_wake_txqs()
will not schedule a new queue run and remaining frames in the queue get
stuck till another frame is queued to it.
Fix the issue for all drivers - also the ones with custom wake_tx_queue
callbacks - by moving the logic into ieee80211_tx_dequeue() and drop the
redundant @txqs_stopped.
@IEEE80211_TXQ_STOP_NETIF_TX is also renamed to @IEEE80211_TXQ_DIRTY to
better describe the flag.
Fixes: c850e31f79f0 ("wifi: mac80211: add internal handler for wake_tx_queue")
Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
Link: https://lore.kernel.org/r/20221230121850.218810-1-alexander@wetzel-home.de
Cc: stable@vger.kernel.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2171cd1ca807..178043f84489 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3783,6 +3783,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, struct ieee80211_tx_data tx; ieee80211_tx_result r; struct ieee80211_vif *vif = txq->vif; + int q = vif->hw_queue[txq->ac]; + bool q_stopped; WARN_ON_ONCE(softirq_count() == 0); @@ -3790,16 +3792,20 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, return NULL; begin: - spin_lock_bh(&fq->lock); + spin_lock(&local->queue_stop_reason_lock); + q_stopped = local->queue_stop_reasons[q]; + spin_unlock(&local->queue_stop_reason_lock); - if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) || - test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags)) - goto out; + if (unlikely(q_stopped)) { + /* mark for waking later */ + set_bit(IEEE80211_TXQ_DIRTY, &txqi->flags); + return NULL; + } - if (vif->txqs_stopped[txq->ac]) { - set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags); + spin_lock_bh(&fq->lock); + + if (unlikely(test_bit(IEEE80211_TXQ_STOP, &txqi->flags))) goto out; - } /* Make sure fragments stay together. */ skb = __skb_dequeue(&txqi->frags); |