From 82e32fbb71d4eef91e8dbd0dd168502f9401e4d9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 1 Jun 2010 17:38:01 +0000 Subject: [PATCH] ath9k: fix queue stopping/starting logic, should slightly reduce RAM usage under load and make throughput more smooth SVN-Revision: 21650 --- .../patches/530-ath9k_queue_fill.patch | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 package/mac80211/patches/530-ath9k_queue_fill.patch diff --git a/package/mac80211/patches/530-ath9k_queue_fill.patch b/package/mac80211/patches/530-ath9k_queue_fill.patch new file mode 100644 index 0000000000..172fba4009 --- /dev/null +++ b/package/mac80211/patches/530-ath9k_queue_fill.patch @@ -0,0 +1,144 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -137,6 +137,8 @@ void ath_descdma_cleanup(struct ath_soft + #define ATH_MAX_ANTENNA 3 + #define ATH_RXBUF 512 + #define ATH_TXBUF 512 ++#define ATH_TXBUF_RESERVE 5 ++#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) + #define ATH_TXMAXTRY 13 + #define ATH_MGT_TXMAXTRY 4 + +@@ -205,6 +207,7 @@ struct ath_txq { + struct list_head txq_fifo_pending; + u8 txq_headidx; + u8 txq_tailidx; ++ int pending_frames; + }; + + struct ath_atx_ac { +@@ -242,6 +245,7 @@ struct ath_buf { + struct ath_buf_state bf_state; + dma_addr_t bf_dmacontext; + struct ath_wiphy *aphy; ++ struct ath_txq *txq; + }; + + struct ath_atx_tid { +@@ -331,7 +335,6 @@ void ath_tx_node_cleanup(struct ath_soft + void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); + int ath_tx_init(struct ath_softc *sc, int nbufs); + void ath_tx_cleanup(struct ath_softc *sc); +-struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); + int ath_txq_update(struct ath_softc *sc, int qnum, + struct ath9k_tx_queue_info *q); + int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -986,32 +986,6 @@ int ath_tx_get_qnum(struct ath_softc *sc + return qnum; + } + +-struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) +-{ +- struct ath_txq *txq = NULL; +- u16 skb_queue = skb_get_queue_mapping(skb); +- int qnum; +- +- qnum = ath_get_hal_qnum(skb_queue, sc); +- txq = &sc->tx.txq[qnum]; +- +- spin_lock_bh(&txq->axq_lock); +- +- if (txq->axq_depth >= (ATH_TXBUF - 20)) { +- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT, +- "TX queue: %d is full, depth: %d\n", +- qnum, txq->axq_depth); +- ath_mac80211_stop_queue(sc, skb_queue); +- txq->stopped = 1; +- spin_unlock_bh(&txq->axq_lock); +- return NULL; +- } +- +- spin_unlock_bh(&txq->axq_lock); +- +- return txq; +-} +- + int ath_txq_update(struct ath_softc *sc, int qnum, + struct ath9k_tx_queue_info *qinfo) + { +@@ -1811,6 +1785,7 @@ int ath_tx_start(struct ieee80211_hw *hw + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ struct ath_txq *txq = txctl->txq; + struct ath_buf *bf; + int r; + +@@ -1820,10 +1795,16 @@ int ath_tx_start(struct ieee80211_hw *hw + return -1; + } + ++ bf->txq = txctl->txq; ++ spin_lock_bh(&bf->txq->axq_lock); ++ if (++bf->txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { ++ ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb)); ++ txq->stopped = 1; ++ } ++ spin_unlock_bh(&bf->txq->axq_lock); ++ + r = ath_tx_setup_buffer(hw, bf, skb, txctl); + if (unlikely(r)) { +- struct ath_txq *txq = txctl->txq; +- + ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n"); + + /* upon ath_tx_processq() this TX queue will be resumed, we +@@ -1831,7 +1812,7 @@ int ath_tx_start(struct ieee80211_hw *hw + * we will at least have to run TX completionon one buffer + * on the queue */ + spin_lock_bh(&txq->axq_lock); +- if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) { ++ if (!txq->stopped && txq->axq_depth > 1) { + ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb)); + txq->stopped = 1; + } +@@ -1972,6 +1953,13 @@ static void ath_tx_complete_buf(struct a + tx_flags |= ATH_TX_XRETRY; + } + ++ if (bf->txq) { ++ spin_lock_bh(&bf->txq->axq_lock); ++ bf->txq->pending_frames--; ++ spin_unlock_bh(&bf->txq->axq_lock); ++ bf->txq = NULL; ++ } ++ + dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); + ath_tx_complete(sc, skb, bf->aphy, tx_flags); + ath_debug_stat_tx(sc, txq, bf, ts); +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -1026,6 +1026,7 @@ static int ath9k_tx(struct ieee80211_hw + struct ath_tx_control txctl; + int padpos, padsize; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; ++ int qnum; + + if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { + ath_print(common, ATH_DBG_XMIT, +@@ -1098,11 +1099,8 @@ static int ath9k_tx(struct ieee80211_hw + memmove(skb->data, skb->data + padsize, padpos); + } + +- /* Check if a tx queue is available */ +- +- txctl.txq = ath_test_get_txq(sc, skb); +- if (!txctl.txq) +- goto exit; ++ qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); ++ txctl.txq = &sc->tx.txq[qnum]; + + ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); + -- 2.30.2