diff options
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 89 |
1 files changed, 50 insertions, 39 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3b66f2b67fec..f9e6eb2a4e0b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -1345,8 +1345,8 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, | |||
1345 | } while (1); | 1345 | } while (1); |
1346 | } | 1346 | } |
1347 | 1347 | ||
1348 | static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | 1348 | static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, |
1349 | struct ath_atx_tid *tid) | 1349 | struct ath_atx_tid *tid, bool *stop) |
1350 | { | 1350 | { |
1351 | struct ath_buf *bf; | 1351 | struct ath_buf *bf; |
1352 | struct ieee80211_tx_info *tx_info; | 1352 | struct ieee80211_tx_info *tx_info; |
@@ -1355,40 +1355,41 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
1355 | int aggr_len = 0; | 1355 | int aggr_len = 0; |
1356 | bool aggr, last = true; | 1356 | bool aggr, last = true; |
1357 | 1357 | ||
1358 | do { | 1358 | if (!ath_tid_has_buffered(tid)) |
1359 | if (!ath_tid_has_buffered(tid)) | 1359 | return false; |
1360 | return; | ||
1361 | 1360 | ||
1362 | INIT_LIST_HEAD(&bf_q); | 1361 | INIT_LIST_HEAD(&bf_q); |
1363 | 1362 | ||
1364 | bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); | 1363 | bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); |
1365 | if (!bf) | 1364 | if (!bf) |
1366 | break; | 1365 | return false; |
1367 | 1366 | ||
1368 | tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); | 1367 | tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); |
1369 | aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); | 1368 | aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); |
1370 | if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || | 1369 | if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || |
1371 | (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) | 1370 | (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { |
1372 | break; | 1371 | *stop = true; |
1372 | return false; | ||
1373 | } | ||
1373 | 1374 | ||
1374 | ath_set_rates(tid->an->vif, tid->an->sta, bf); | 1375 | ath_set_rates(tid->an->vif, tid->an->sta, bf); |
1375 | if (aggr) | 1376 | if (aggr) |
1376 | last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, | 1377 | last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, |
1377 | tid_q, &aggr_len); | 1378 | tid_q, &aggr_len); |
1378 | else | 1379 | else |
1379 | ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q); | 1380 | ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q); |
1380 | 1381 | ||
1381 | if (list_empty(&bf_q)) | 1382 | if (list_empty(&bf_q)) |
1382 | return; | 1383 | return false; |
1383 | 1384 | ||
1384 | if (tid->ac->clear_ps_filter) { | 1385 | if (tid->ac->clear_ps_filter) { |
1385 | tid->ac->clear_ps_filter = false; | 1386 | tid->ac->clear_ps_filter = false; |
1386 | tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; | 1387 | tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; |
1387 | } | 1388 | } |
1388 | 1389 | ||
1389 | ath_tx_fill_desc(sc, bf, txq, aggr_len); | 1390 | ath_tx_fill_desc(sc, bf, txq, aggr_len); |
1390 | ath_tx_txqaddbuf(sc, txq, &bf_q, false); | 1391 | ath_tx_txqaddbuf(sc, txq, &bf_q, false); |
1391 | } while (!last); | 1392 | return true; |
1392 | } | 1393 | } |
1393 | 1394 | ||
1394 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | 1395 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, |
@@ -1824,25 +1825,27 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) | |||
1824 | */ | 1825 | */ |
1825 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | 1826 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) |
1826 | { | 1827 | { |
1827 | struct ath_atx_ac *ac, *ac_tmp, *last_ac; | 1828 | struct ath_atx_ac *ac, *last_ac; |
1828 | struct ath_atx_tid *tid, *last_tid; | 1829 | struct ath_atx_tid *tid, *last_tid; |
1830 | bool sent = false; | ||
1829 | 1831 | ||
1830 | if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) || | 1832 | if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) || |
1831 | list_empty(&txq->axq_acq) || | 1833 | list_empty(&txq->axq_acq)) |
1832 | txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) | ||
1833 | return; | 1834 | return; |
1834 | 1835 | ||
1835 | rcu_read_lock(); | 1836 | rcu_read_lock(); |
1836 | 1837 | ||
1837 | ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); | ||
1838 | last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); | 1838 | last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); |
1839 | while (!list_empty(&txq->axq_acq)) { | ||
1840 | bool stop = false; | ||
1839 | 1841 | ||
1840 | list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { | 1842 | ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); |
1841 | last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); | 1843 | last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); |
1842 | list_del(&ac->list); | 1844 | list_del(&ac->list); |
1843 | ac->sched = false; | 1845 | ac->sched = false; |
1844 | 1846 | ||
1845 | while (!list_empty(&ac->tid_q)) { | 1847 | while (!list_empty(&ac->tid_q)) { |
1848 | |||
1846 | tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, | 1849 | tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, |
1847 | list); | 1850 | list); |
1848 | list_del(&tid->list); | 1851 | list_del(&tid->list); |
@@ -1851,7 +1854,8 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | |||
1851 | if (tid->paused) | 1854 | if (tid->paused) |
1852 | continue; | 1855 | continue; |
1853 | 1856 | ||
1854 | ath_tx_sched_aggr(sc, txq, tid); | 1857 | if (ath_tx_sched_aggr(sc, txq, tid, &stop)) |
1858 | sent = true; | ||
1855 | 1859 | ||
1856 | /* | 1860 | /* |
1857 | * add tid to round-robin queue if more frames | 1861 | * add tid to round-robin queue if more frames |
@@ -1860,8 +1864,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | |||
1860 | if (ath_tid_has_buffered(tid)) | 1864 | if (ath_tid_has_buffered(tid)) |
1861 | ath_tx_queue_tid(txq, tid); | 1865 | ath_tx_queue_tid(txq, tid); |
1862 | 1866 | ||
1863 | if (tid == last_tid || | 1867 | if (stop || tid == last_tid) |
1864 | txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) | ||
1865 | break; | 1868 | break; |
1866 | } | 1869 | } |
1867 | 1870 | ||
@@ -1870,9 +1873,17 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | |||
1870 | list_add_tail(&ac->list, &txq->axq_acq); | 1873 | list_add_tail(&ac->list, &txq->axq_acq); |
1871 | } | 1874 | } |
1872 | 1875 | ||
1873 | if (ac == last_ac || | 1876 | if (stop) |
1874 | txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) | ||
1875 | break; | 1877 | break; |
1878 | |||
1879 | if (ac == last_ac) { | ||
1880 | if (!sent) | ||
1881 | break; | ||
1882 | |||
1883 | sent = false; | ||
1884 | last_ac = list_entry(txq->axq_acq.prev, | ||
1885 | struct ath_atx_ac, list); | ||
1886 | } | ||
1876 | } | 1887 | } |
1877 | 1888 | ||
1878 | rcu_read_unlock(); | 1889 | rcu_read_unlock(); |