diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 51 |
1 files changed, 7 insertions, 44 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index d59dd01d6cde..f777ddcd1172 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -105,19 +105,19 @@ static int ath_max_4ms_framelen[4][32] = { | |||
105 | /* Aggregation logic */ | 105 | /* Aggregation logic */ |
106 | /*********************/ | 106 | /*********************/ |
107 | 107 | ||
108 | static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq) | 108 | void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq) |
109 | __acquires(&txq->axq_lock) | 109 | __acquires(&txq->axq_lock) |
110 | { | 110 | { |
111 | spin_lock_bh(&txq->axq_lock); | 111 | spin_lock_bh(&txq->axq_lock); |
112 | } | 112 | } |
113 | 113 | ||
114 | static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq) | 114 | void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq) |
115 | __releases(&txq->axq_lock) | 115 | __releases(&txq->axq_lock) |
116 | { | 116 | { |
117 | spin_unlock_bh(&txq->axq_lock); | 117 | spin_unlock_bh(&txq->axq_lock); |
118 | } | 118 | } |
119 | 119 | ||
120 | static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) | 120 | void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) |
121 | __releases(&txq->axq_lock) | 121 | __releases(&txq->axq_lock) |
122 | { | 122 | { |
123 | struct sk_buff_head q; | 123 | struct sk_buff_head q; |
@@ -1536,7 +1536,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) | |||
1536 | int i; | 1536 | int i; |
1537 | u32 npend = 0; | 1537 | u32 npend = 0; |
1538 | 1538 | ||
1539 | if (sc->sc_flags & SC_OP_INVALID) | 1539 | if (test_bit(SC_OP_INVALID, &sc->sc_flags)) |
1540 | return true; | 1540 | return true; |
1541 | 1541 | ||
1542 | ath9k_hw_abort_tx_dma(ah); | 1542 | ath9k_hw_abort_tx_dma(ah); |
@@ -1994,6 +1994,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | |||
1994 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1994 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1995 | struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; | 1995 | struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; |
1996 | int q, padpos, padsize; | 1996 | int q, padpos, padsize; |
1997 | unsigned long flags; | ||
1997 | 1998 | ||
1998 | ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); | 1999 | ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); |
1999 | 2000 | ||
@@ -2012,6 +2013,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | |||
2012 | skb_pull(skb, padsize); | 2013 | skb_pull(skb, padsize); |
2013 | } | 2014 | } |
2014 | 2015 | ||
2016 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | ||
2015 | if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) { | 2017 | if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) { |
2016 | sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; | 2018 | sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; |
2017 | ath_dbg(common, PS, | 2019 | ath_dbg(common, PS, |
@@ -2021,6 +2023,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | |||
2021 | PS_WAIT_FOR_PSPOLL_DATA | | 2023 | PS_WAIT_FOR_PSPOLL_DATA | |
2022 | PS_WAIT_FOR_TX_ACK)); | 2024 | PS_WAIT_FOR_TX_ACK)); |
2023 | } | 2025 | } |
2026 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | ||
2024 | 2027 | ||
2025 | q = skb_get_queue_mapping(skb); | 2028 | q = skb_get_queue_mapping(skb); |
2026 | if (txq == sc->tx.txq_map[q]) { | 2029 | if (txq == sc->tx.txq_map[q]) { |
@@ -2231,46 +2234,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2231 | ath_txq_unlock_complete(sc, txq); | 2234 | ath_txq_unlock_complete(sc, txq); |
2232 | } | 2235 | } |
2233 | 2236 | ||
2234 | static void ath_tx_complete_poll_work(struct work_struct *work) | ||
2235 | { | ||
2236 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
2237 | tx_complete_work.work); | ||
2238 | struct ath_txq *txq; | ||
2239 | int i; | ||
2240 | bool needreset = false; | ||
2241 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
2242 | sc->tx_complete_poll_work_seen++; | ||
2243 | #endif | ||
2244 | |||
2245 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
2246 | if (ATH_TXQ_SETUP(sc, i)) { | ||
2247 | txq = &sc->tx.txq[i]; | ||
2248 | ath_txq_lock(sc, txq); | ||
2249 | if (txq->axq_depth) { | ||
2250 | if (txq->axq_tx_inprogress) { | ||
2251 | needreset = true; | ||
2252 | ath_txq_unlock(sc, txq); | ||
2253 | break; | ||
2254 | } else { | ||
2255 | txq->axq_tx_inprogress = true; | ||
2256 | } | ||
2257 | } | ||
2258 | ath_txq_unlock_complete(sc, txq); | ||
2259 | } | ||
2260 | |||
2261 | if (needreset) { | ||
2262 | ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, | ||
2263 | "tx hung, resetting the chip\n"); | ||
2264 | RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); | ||
2265 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | ||
2266 | } | ||
2267 | |||
2268 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, | ||
2269 | msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT)); | ||
2270 | } | ||
2271 | |||
2272 | |||
2273 | |||
2274 | void ath_tx_tasklet(struct ath_softc *sc) | 2237 | void ath_tx_tasklet(struct ath_softc *sc) |
2275 | { | 2238 | { |
2276 | struct ath_hw *ah = sc->sc_ah; | 2239 | struct ath_hw *ah = sc->sc_ah; |