diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 57 |
3 files changed, 50 insertions, 14 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 544599b826c1..20bf4a7f896d 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -225,6 +225,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, | |||
225 | #define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) | 225 | #define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) |
226 | #define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) | 226 | #define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) |
227 | 227 | ||
228 | #define ATH_TX_COMPLETE_POLL_INT 1000 | ||
229 | |||
228 | enum ATH_AGGR_STATUS { | 230 | enum ATH_AGGR_STATUS { |
229 | ATH_AGGR_DONE, | 231 | ATH_AGGR_DONE, |
230 | ATH_AGGR_BAW_CLOSED, | 232 | ATH_AGGR_BAW_CLOSED, |
@@ -240,6 +242,7 @@ struct ath_txq { | |||
240 | u8 axq_aggr_depth; | 242 | u8 axq_aggr_depth; |
241 | u32 axq_totalqueued; | 243 | u32 axq_totalqueued; |
242 | bool stopped; | 244 | bool stopped; |
245 | bool axq_tx_inprogress; | ||
243 | struct ath_buf *axq_linkbuf; | 246 | struct ath_buf *axq_linkbuf; |
244 | 247 | ||
245 | /* first desc of the last descriptor that contains CTS */ | 248 | /* first desc of the last descriptor that contains CTS */ |
@@ -605,6 +608,7 @@ struct ath_softc { | |||
605 | #endif | 608 | #endif |
606 | struct ath_bus_ops *bus_ops; | 609 | struct ath_bus_ops *bus_ops; |
607 | struct ath_beacon_config cur_beacon_conf; | 610 | struct ath_beacon_config cur_beacon_conf; |
611 | struct delayed_work tx_complete_work; | ||
608 | }; | 612 | }; |
609 | 613 | ||
610 | struct ath_wiphy { | 614 | struct ath_wiphy { |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2ad718489c0d..46f4a692c8d1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1259,6 +1259,7 @@ void ath_detach(struct ath_softc *sc) | |||
1259 | ath_deinit_leds(sc); | 1259 | ath_deinit_leds(sc); |
1260 | cancel_work_sync(&sc->chan_work); | 1260 | cancel_work_sync(&sc->chan_work); |
1261 | cancel_delayed_work_sync(&sc->wiphy_work); | 1261 | cancel_delayed_work_sync(&sc->wiphy_work); |
1262 | cancel_delayed_work_sync(&sc->tx_complete_work); | ||
1262 | 1263 | ||
1263 | for (i = 0; i < sc->num_sec_wiphy; i++) { | 1264 | for (i = 0; i < sc->num_sec_wiphy; i++) { |
1264 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | 1265 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; |
@@ -1979,6 +1980,8 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
1979 | 1980 | ||
1980 | ieee80211_wake_queues(hw); | 1981 | ieee80211_wake_queues(hw); |
1981 | 1982 | ||
1983 | queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0); | ||
1984 | |||
1982 | mutex_unlock: | 1985 | mutex_unlock: |
1983 | mutex_unlock(&sc->mutex); | 1986 | mutex_unlock(&sc->mutex); |
1984 | 1987 | ||
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5de9878d2c12..a3bc4310a67c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -857,6 +857,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) | |||
857 | txq->axq_aggr_depth = 0; | 857 | txq->axq_aggr_depth = 0; |
858 | txq->axq_totalqueued = 0; | 858 | txq->axq_totalqueued = 0; |
859 | txq->axq_linkbuf = NULL; | 859 | txq->axq_linkbuf = NULL; |
860 | txq->axq_tx_inprogress = false; | ||
860 | sc->tx.txqsetup |= 1<<qnum; | 861 | sc->tx.txqsetup |= 1<<qnum; |
861 | } | 862 | } |
862 | return &sc->tx.txq[qnum]; | 863 | return &sc->tx.txq[qnum]; |
@@ -1023,6 +1024,10 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) | |||
1023 | ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); | 1024 | ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); |
1024 | } | 1025 | } |
1025 | 1026 | ||
1027 | spin_lock_bh(&txq->axq_lock); | ||
1028 | txq->axq_tx_inprogress = false; | ||
1029 | spin_unlock_bh(&txq->axq_lock); | ||
1030 | |||
1026 | /* flush any pending frames if aggregation is enabled */ | 1031 | /* flush any pending frames if aggregation is enabled */ |
1027 | if (sc->sc_flags & SC_OP_TXAGGR) { | 1032 | if (sc->sc_flags & SC_OP_TXAGGR) { |
1028 | if (!retry_tx) { | 1033 | if (!retry_tx) { |
@@ -1103,8 +1108,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | |||
1103 | if (tid->paused) | 1108 | if (tid->paused) |
1104 | continue; | 1109 | continue; |
1105 | 1110 | ||
1106 | if ((txq->axq_depth % 2) == 0) | 1111 | ath_tx_sched_aggr(sc, txq, tid); |
1107 | ath_tx_sched_aggr(sc, txq, tid); | ||
1108 | 1112 | ||
1109 | /* | 1113 | /* |
1110 | * add tid to round-robin queue if more frames | 1114 | * add tid to round-robin queue if more frames |
@@ -1947,19 +1951,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
1947 | if (bf->bf_stale) { | 1951 | if (bf->bf_stale) { |
1948 | bf_held = bf; | 1952 | bf_held = bf; |
1949 | if (list_is_last(&bf_held->list, &txq->axq_q)) { | 1953 | if (list_is_last(&bf_held->list, &txq->axq_q)) { |
1950 | txq->axq_link = NULL; | ||
1951 | txq->axq_linkbuf = NULL; | ||
1952 | spin_unlock_bh(&txq->axq_lock); | 1954 | spin_unlock_bh(&txq->axq_lock); |
1953 | |||
1954 | /* | ||
1955 | * The holding descriptor is the last | ||
1956 | * descriptor in queue. It's safe to remove | ||
1957 | * the last holding descriptor in BH context. | ||
1958 | */ | ||
1959 | spin_lock_bh(&sc->tx.txbuflock); | ||
1960 | list_move_tail(&bf_held->list, &sc->tx.txbuf); | ||
1961 | spin_unlock_bh(&sc->tx.txbuflock); | ||
1962 | |||
1963 | break; | 1955 | break; |
1964 | } else { | 1956 | } else { |
1965 | bf = list_entry(bf_held->list.next, | 1957 | bf = list_entry(bf_held->list.next, |
@@ -1996,6 +1988,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
1996 | txq->axq_aggr_depth--; | 1988 | txq->axq_aggr_depth--; |
1997 | 1989 | ||
1998 | txok = (ds->ds_txstat.ts_status == 0); | 1990 | txok = (ds->ds_txstat.ts_status == 0); |
1991 | txq->axq_tx_inprogress = false; | ||
1999 | spin_unlock_bh(&txq->axq_lock); | 1992 | spin_unlock_bh(&txq->axq_lock); |
2000 | 1993 | ||
2001 | if (bf_held) { | 1994 | if (bf_held) { |
@@ -2029,6 +2022,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2029 | } | 2022 | } |
2030 | } | 2023 | } |
2031 | 2024 | ||
2025 | void ath_tx_complete_poll_work(struct work_struct *work) | ||
2026 | { | ||
2027 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
2028 | tx_complete_work.work); | ||
2029 | struct ath_txq *txq; | ||
2030 | int i; | ||
2031 | bool needreset = false; | ||
2032 | |||
2033 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
2034 | if (ATH_TXQ_SETUP(sc, i)) { | ||
2035 | txq = &sc->tx.txq[i]; | ||
2036 | spin_lock_bh(&txq->axq_lock); | ||
2037 | if (txq->axq_depth) { | ||
2038 | if (txq->axq_tx_inprogress) { | ||
2039 | needreset = true; | ||
2040 | spin_unlock_bh(&txq->axq_lock); | ||
2041 | break; | ||
2042 | } else { | ||
2043 | txq->axq_tx_inprogress = true; | ||
2044 | } | ||
2045 | } | ||
2046 | spin_unlock_bh(&txq->axq_lock); | ||
2047 | } | ||
2048 | |||
2049 | if (needreset) { | ||
2050 | DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n"); | ||
2051 | ath_reset(sc, false); | ||
2052 | } | ||
2053 | |||
2054 | queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, | ||
2055 | msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT)); | ||
2056 | } | ||
2057 | |||
2058 | |||
2032 | 2059 | ||
2033 | void ath_tx_tasklet(struct ath_softc *sc) | 2060 | void ath_tx_tasklet(struct ath_softc *sc) |
2034 | { | 2061 | { |
@@ -2069,6 +2096,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) | |||
2069 | goto err; | 2096 | goto err; |
2070 | } | 2097 | } |
2071 | 2098 | ||
2099 | INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); | ||
2100 | |||
2072 | err: | 2101 | err: |
2073 | if (error != 0) | 2102 | if (error != 0) |
2074 | ath_tx_cleanup(sc); | 2103 | ath_tx_cleanup(sc); |