diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-07-13 15:57:29 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-07-13 15:57:29 -0400 |
commit | e300d955debdadf599c36e47eb0bc16f5976215c (patch) | |
tree | 8fafcc789dc06e90665e6eee6388af228bbd2fd7 /drivers/net/wireless/ath/ath9k/xmit.c | |
parent | 242647bcf8464860f173f3d4d4ab3490d3558518 (diff) | |
parent | 815868e7b5c207ba42d5b317ccc51f8112732268 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
drivers/net/wireless/wl12xx/wl1271_cmd.h
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 65 |
1 files changed, 39 insertions, 26 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c3681a1dc941..bd52ac111795 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -329,6 +329,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
329 | int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; | 329 | int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; |
330 | bool rc_update = true; | 330 | bool rc_update = true; |
331 | struct ieee80211_tx_rate rates[4]; | 331 | struct ieee80211_tx_rate rates[4]; |
332 | unsigned long flags; | ||
332 | 333 | ||
333 | skb = bf->bf_mpdu; | 334 | skb = bf->bf_mpdu; |
334 | hdr = (struct ieee80211_hdr *)skb->data; | 335 | hdr = (struct ieee80211_hdr *)skb->data; |
@@ -344,12 +345,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
344 | sta = ieee80211_find_sta_by_hw(hw, hdr->addr1); | 345 | sta = ieee80211_find_sta_by_hw(hw, hdr->addr1); |
345 | if (!sta) { | 346 | if (!sta) { |
346 | rcu_read_unlock(); | 347 | rcu_read_unlock(); |
348 | |||
349 | spin_lock_irqsave(&sc->tx.txbuflock, flags); | ||
350 | list_splice_tail_init(bf_q, &sc->tx.txbuf); | ||
351 | spin_unlock_irqrestore(&sc->tx.txbuflock, flags); | ||
347 | return; | 352 | return; |
348 | } | 353 | } |
349 | 354 | ||
350 | an = (struct ath_node *)sta->drv_priv; | 355 | an = (struct ath_node *)sta->drv_priv; |
351 | tid = ATH_AN_2_TID(an, bf->bf_tidno); | 356 | tid = ATH_AN_2_TID(an, bf->bf_tidno); |
352 | 357 | ||
358 | /* | ||
359 | * The hardware occasionally sends a tx status for the wrong TID. | ||
360 | * In this case, the BA status cannot be considered valid and all | ||
361 | * subframes need to be retransmitted | ||
362 | */ | ||
363 | if (bf->bf_tidno != ts->tid) | ||
364 | txok = false; | ||
365 | |||
353 | isaggr = bf_isaggr(bf); | 366 | isaggr = bf_isaggr(bf); |
354 | memset(ba, 0, WME_BA_BMP_SIZE >> 3); | 367 | memset(ba, 0, WME_BA_BMP_SIZE >> 3); |
355 | 368 | ||
@@ -2430,37 +2443,37 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) | |||
2430 | 2443 | ||
2431 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) | 2444 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) |
2432 | { | 2445 | { |
2433 | int i; | 2446 | struct ath_atx_ac *ac; |
2434 | struct ath_atx_ac *ac, *ac_tmp; | 2447 | struct ath_atx_tid *tid; |
2435 | struct ath_atx_tid *tid, *tid_tmp; | ||
2436 | struct ath_txq *txq; | 2448 | struct ath_txq *txq; |
2449 | int i, tidno; | ||
2437 | 2450 | ||
2438 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | 2451 | for (tidno = 0, tid = &an->tid[tidno]; |
2439 | if (ATH_TXQ_SETUP(sc, i)) { | 2452 | tidno < WME_NUM_TID; tidno++, tid++) { |
2440 | txq = &sc->tx.txq[i]; | 2453 | i = tid->ac->qnum; |
2441 | 2454 | ||
2442 | spin_lock_bh(&txq->axq_lock); | 2455 | if (!ATH_TXQ_SETUP(sc, i)) |
2456 | continue; | ||
2443 | 2457 | ||
2444 | list_for_each_entry_safe(ac, | 2458 | txq = &sc->tx.txq[i]; |
2445 | ac_tmp, &txq->axq_acq, list) { | 2459 | ac = tid->ac; |
2446 | tid = list_first_entry(&ac->tid_q, | ||
2447 | struct ath_atx_tid, list); | ||
2448 | if (tid && tid->an != an) | ||
2449 | continue; | ||
2450 | list_del(&ac->list); | ||
2451 | ac->sched = false; | ||
2452 | |||
2453 | list_for_each_entry_safe(tid, | ||
2454 | tid_tmp, &ac->tid_q, list) { | ||
2455 | list_del(&tid->list); | ||
2456 | tid->sched = false; | ||
2457 | ath_tid_drain(sc, txq, tid); | ||
2458 | tid->state &= ~AGGR_ADDBA_COMPLETE; | ||
2459 | tid->state &= ~AGGR_CLEANUP; | ||
2460 | } | ||
2461 | } | ||
2462 | 2460 | ||
2463 | spin_unlock_bh(&txq->axq_lock); | 2461 | spin_lock_bh(&txq->axq_lock); |
2462 | |||
2463 | if (tid->sched) { | ||
2464 | list_del(&tid->list); | ||
2465 | tid->sched = false; | ||
2464 | } | 2466 | } |
2467 | |||
2468 | if (ac->sched) { | ||
2469 | list_del(&ac->list); | ||
2470 | tid->ac->sched = false; | ||
2471 | } | ||
2472 | |||
2473 | ath_tid_drain(sc, txq, tid); | ||
2474 | tid->state &= ~AGGR_ADDBA_COMPLETE; | ||
2475 | tid->state &= ~AGGR_CLEANUP; | ||
2476 | |||
2477 | spin_unlock_bh(&txq->axq_lock); | ||
2465 | } | 2478 | } |
2466 | } | 2479 | } |