summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vasanth@atheros.com>2009-06-24 18:58:47 +0530
committerJohn W. Linville <linville@tuxdriver.com>2009-07-07 12:55:26 -0400
commitcbfe89c67b58e2bd1b47f6986b3b793f06f3d9b0 (patch)
tree892a092f32d746c841e98ef01e9d0b3da4f048e8 /drivers
parentfd4973c56f8d9baac8d269791a90e5119ce30a0e (diff)
ath9k: Fix leak in tx descriptor
When we reclaim the tx desc, we always assume that the last desc is a holding desc, which is not true, and skip it. If the tx queue is drained during channel change, internal reset and etc, the last descriptor may not be the holding descriptor and we fail to reclaim them. This results in the following two issues. 1. Tx stuck - We drop all the frames coming from upper layer due to shortage in tx desc. 2. Crash - If we fail to reclaim a tx descriptor, we miss to update the tx BA window with the seq number of the frame associated to that desc, which, at some point, result in the following crash due to an assert failure in ath_tx_addto_baw(). This patch fixes these two issues. kernel BUG at ../drivers/net/wireless/ath/ath9k/xmit.c:180! [155064.304164] invalid opcode: 0000 [#1] SMP Call Trace: [<fbc6d83b>] ? ath9k_tx+0xeb/0x160 [ath9k] [<fbbc9591>] ipv6? __ieee80211_tx+0x41/0x120 [mac80211] [<fbbcb5ae>] ? aes_i586ieee80211_master_start_xmit+0x28e/0x560 [mac80211] [<c037e501>] aes_generic? _spin_lock_irqsave+0x31/0x40 [<c02f347b>] ? dev_hard_start_xmit+0x16b/0x1c0 [<c03058b5>] ? __qdisc_run+0x1b5/0x200 [<fbbcda5a>] ? af_packetieee80211_select_queue+0xa/0x100 [mac80211] [<c02f53b7>] ? i915dev_queue_xmit+0x2e7/0x3f0 [<fbbc9b49>] ? ieee80211_subif_start_xmit+0x369/0x7a0 [mac80211] [<c031bc35>] ? ip_output+0x55/0xb0 [<c02e0188>] ? show_memcpy_count+0x18/0x60 [<c02eb186>] ? __kfree_skb+0x36/0x90 [<c02f2202>] ? binfmt_miscdev_queue_xmit_nit+0xd2/0x110 [<c02f347b>] ? dev_hard_start_xmit+0x16b/0x1c0 [<c03058b5>] ? __qdisc_run+0x1b5/0x200 [<c033bca7>] ? scoarp_create+0x57/0x2a0 [<c02f53b7>] ? bridgedev_queue_xmit+0x2e7/0x3f0 [<c03034a0>] ? eth_header+0x0/0xc0 [<c033b95f>] stp? arp_xmit+0x5f/0x70 [<c033bf4f>] ? arp_send+0x5f/0x70 [<c033c8f5>] bnep? arp_solicit+0x105/0x210 [<c02fa5aa>] ? neigh_timer_handler+0x19a/0x390 [<c013bf88>] ? run_timer_softirq+0x138/0x210 [<c02fa410>] ? ppdevneigh_timer_handler+0x0/0x390 [<c02fa410>] ? neigh_timer_handler+0x0/0x390 Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index b61a071788a..4ccf48e396d 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -355,7 +355,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
}
if (bf_next == NULL) {
- INIT_LIST_HEAD(&bf_head);
+ /*
+ * Make sure the last desc is reclaimed if it
+ * not a holding desc.
+ */
+ if (!bf_last->bf_stale)
+ list_move_tail(&bf->list, &bf_head);
+ else
+ INIT_LIST_HEAD(&bf_head);
} else {
ASSERT(!list_empty(bf_q));
list_move_tail(&bf->list, &bf_head);