aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/xmit.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c65
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
2431void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) 2444void 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}