aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/tx.c
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2012-02-28 00:41:30 +0200
committerLuciano Coelho <coelho@ti.com>2012-02-28 13:24:45 +0200
commit6246ca003f2560e30b9696757efc271284b809f6 (patch)
tree6a628af4152b5802f2f1c936a804e4defbba2653 /drivers/net/wireless/wl12xx/tx.c
parentwl12xx: change bits in the link_map under spin lock (diff)
downloadlinux-dev-6246ca003f2560e30b9696757efc271284b809f6.tar.xz
linux-dev-6246ca003f2560e30b9696757efc271284b809f6.zip
wl12xx: reset link Tx queues when freeing it
Before, the link was first freed (invalidating it in the map), and later on vif removal, all valid wlvif-related links were reset. Since these links were already invalid, we failed to reset them. The bug was made worse by op_stop, which set the tx_queue_count to 0 arbitrarily. This resulted in a negative tx_queue_count in some scenarios. Fix this by resetting the Tx-queues of a link when freeing it. Add a WARN_ON and reset all link Tx-queues in op_stop, to avoid a negative tx_queue_count. [changed WARN_ON to WARN_ON_ONCE -- Luca] Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to '')
-rw-r--r--drivers/net/wireless/wl12xx/tx.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 6446e4d3e8f9..8f5ab047aec8 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -527,6 +527,7 @@ static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl,
if (skb) {
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags);
+ WARN_ON_ONCE(wl->tx_queue_count[q] <= 0);
wl->tx_queue_count[q]--;
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
@@ -602,6 +603,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
skb = wl->dummy_packet;
q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags);
+ WARN_ON_ONCE(wl->tx_queue_count[q] <= 0);
wl->tx_queue_count[q]--;
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
@@ -959,7 +961,6 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
else
wlvif->sta.ba_rx_bitmap = 0;
- wl1271_tx_reset_link_queues(wl, i);
wl->links[i].allocated_pkts = 0;
wl->links[i].prev_freed_pkts = 0;
}
@@ -973,8 +974,14 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
struct sk_buff *skb;
struct ieee80211_tx_info *info;
- for (i = 0; i < NUM_TX_QUEUES; i++)
- wl->tx_queue_count[i] = 0;
+ /* only reset the queues if something bad happened */
+ if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) {
+ for (i = 0; i < WL12XX_MAX_LINKS; i++)
+ wl1271_tx_reset_link_queues(wl, i);
+
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ wl->tx_queue_count[i] = 0;
+ }
wl->stopped_queues_map = 0;