wl12xx: start/stop queues according to global per-AC counters
Split tx_queue_count to count per-AC skb's queued, instead of relying on
the skb-queue len. The skb queues used were only valid in STA-mode, as
AP-mode uses per-link queues.
This fixes a major regression in AP-mode, caused by the patch
"wl12xx: implement Tx watermarks per AC". With that patch applied, we
effectively had no regulation of Tx queues in AP-mode. Therefore a
sustained high rate of Tx could cause exhaustion of the skb memory pool.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 526b1ac..e58c22d 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -992,7 +992,7 @@
/* Check if any tx blocks were freed */
spin_lock_irqsave(&wl->wl_lock, flags);
if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
- wl->tx_queue_count) {
+ wl1271_tx_total_queue_count(wl) > 0) {
spin_unlock_irqrestore(&wl->wl_lock, flags);
/*
* In order to avoid starvation of the TX path,
@@ -1040,7 +1040,7 @@
/* In case TX was not handled here, queue TX work */
clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
- wl->tx_queue_count)
+ wl1271_tx_total_queue_count(wl) > 0)
ieee80211_queue_work(wl->hw, &wl->tx_work);
spin_unlock_irqrestore(&wl->wl_lock, flags);
@@ -1508,13 +1508,13 @@
spin_lock_irqsave(&wl->wl_lock, flags);
- wl->tx_queue_count++;
+ wl->tx_queue_count[q]++;
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (skb_queue_len(&wl->tx_queue[q]) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
+ if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
ieee80211_stop_queue(wl->hw, mapping);
set_bit(q, &wl->stopped_queues_map);
@@ -1543,10 +1543,11 @@
int wl1271_tx_dummy_packet(struct wl1271 *wl)
{
unsigned long flags;
+ int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
spin_lock_irqsave(&wl->wl_lock, flags);
set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
- wl->tx_queue_count++;
+ wl->tx_queue_count[q]++;
spin_unlock_irqrestore(&wl->wl_lock, flags);
/* The FW is low on RX memory blocks, so send the dummy packet asap */
@@ -3752,7 +3753,7 @@
goto out;
/* packets are considered pending if in the TX queue or the FW */
- ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
+ ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
/* the above is appropriate for STA mode for PS purposes */
WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);