aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 81f4b567c6f2..afedfeba13dd 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -891,6 +891,7 @@ ath5k_txq_setup(struct ath5k_softc *sc,
891 spin_lock_init(&txq->lock); 891 spin_lock_init(&txq->lock);
892 txq->setup = true; 892 txq->setup = true;
893 txq->txq_len = 0; 893 txq->txq_len = 0;
894 txq->txq_poll_mark = false;
894 } 895 }
895 return &sc->txqs[qnum]; 896 return &sc->txqs[qnum];
896} 897}
@@ -989,6 +990,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
989 spin_unlock_bh(&sc->txbuflock); 990 spin_unlock_bh(&sc->txbuflock);
990 } 991 }
991 txq->link = NULL; 992 txq->link = NULL;
993 txq->txq_poll_mark = false;
992 spin_unlock_bh(&txq->lock); 994 spin_unlock_bh(&txq->lock);
993} 995}
994 996
@@ -1616,6 +1618,8 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
1616 sc->txbuf_len++; 1618 sc->txbuf_len++;
1617 txq->txq_len--; 1619 txq->txq_len--;
1618 spin_unlock(&sc->txbuflock); 1620 spin_unlock(&sc->txbuflock);
1621
1622 txq->txq_poll_mark = false;
1619 } 1623 }
1620 if (likely(list_empty(&txq->q))) 1624 if (likely(list_empty(&txq->q)))
1621 txq->link = NULL; 1625 txq->link = NULL;
@@ -2170,6 +2174,46 @@ ath5k_tasklet_ani(unsigned long data)
2170} 2174}
2171 2175
2172 2176
2177static void
2178ath5k_tx_complete_poll_work(struct work_struct *work)
2179{
2180 struct ath5k_softc *sc = container_of(work, struct ath5k_softc,
2181 tx_complete_work.work);
2182 struct ath5k_txq *txq;
2183 int i;
2184 bool needreset = false;
2185
2186 for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
2187 if (sc->txqs[i].setup) {
2188 txq = &sc->txqs[i];
2189 spin_lock_bh(&txq->lock);
2190 if (txq->txq_len > 0) {
2191 if (txq->txq_poll_mark) {
2192 ATH5K_DBG(sc, ATH5K_DEBUG_XMIT,
2193 "TX queue stuck %d\n",
2194 txq->qnum);
2195 needreset = true;
2196 spin_unlock_bh(&txq->lock);
2197 break;
2198 } else {
2199 txq->txq_poll_mark = true;
2200 }
2201 }
2202 spin_unlock_bh(&txq->lock);
2203 }
2204 }
2205
2206 if (needreset) {
2207 ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
2208 "TX queues stuck, resetting\n");
2209 ath5k_reset(sc, sc->curchan);
2210 }
2211
2212 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
2213 msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));
2214}
2215
2216
2173/*************************\ 2217/*************************\
2174* Initialization routines * 2218* Initialization routines *
2175\*************************/ 2219\*************************/
@@ -2261,6 +2305,10 @@ ath5k_init(struct ath5k_softc *sc)
2261done: 2305done:
2262 mmiowb(); 2306 mmiowb();
2263 mutex_unlock(&sc->lock); 2307 mutex_unlock(&sc->lock);
2308
2309 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
2310 msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));
2311
2264 return ret; 2312 return ret;
2265} 2313}
2266 2314
@@ -2319,6 +2367,8 @@ ath5k_stop_hw(struct ath5k_softc *sc)
2319 2367
2320 stop_tasklets(sc); 2368 stop_tasklets(sc);
2321 2369
2370 cancel_delayed_work_sync(&sc->tx_complete_work);
2371
2322 ath5k_rfkill_hw_stop(sc->ah); 2372 ath5k_rfkill_hw_stop(sc->ah);
2323 2373
2324 return ret; 2374 return ret;
@@ -2505,6 +2555,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
2505 tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc); 2555 tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);
2506 2556
2507 INIT_WORK(&sc->reset_work, ath5k_reset_work); 2557 INIT_WORK(&sc->reset_work, ath5k_reset_work);
2558 INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work);
2508 2559
2509 ret = ath5k_eeprom_read_mac(ah, mac); 2560 ret = ath5k_eeprom_read_mac(ah, mac);
2510 if (ret) { 2561 if (ret) {