aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2011-03-11 15:38:20 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-03-14 14:46:58 -0400
commitefff395e97fffd55c60c77c09a18deba8d84e2c0 (patch)
tree0e2383a56e0137c8013d44bfbe945c76f3fb95b0 /drivers/net/wireless/ath/ath9k
parent86271e460a66003dc1f4cbfd845adafb790b7587 (diff)
ath9k: improve reliability of beacon transmission and stuck beacon handling
ath9k calls ath9k_hw_stoptxdma every time it sends a beacon, however there is not much point in doing that if the previous beacon and mcast traffic went out properly. On AR9380, calling that function too often can result in an increase of stuck beacons due to differences in the handling of the queue enable/disable functionality. With this patch, the queue will only be explicitly stopped if the previous data frames were not sent successfully. With the beacon code being the only remaining user of ath9k_hw_stoptxdma, this function can be simplified in order to remove the now pointless attempts at waiting for transmission completion, which would never happen at this point due to the different method of tx scheduling of the beacon queue. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c71
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h2
3 files changed, 12 insertions, 74 deletions
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index a4bdfdb043ef..6d2a545fc35e 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -373,6 +373,7 @@ void ath_beacon_tasklet(unsigned long data)
373 ath_dbg(common, ATH_DBG_BSTUCK, 373 ath_dbg(common, ATH_DBG_BSTUCK,
374 "missed %u consecutive beacons\n", 374 "missed %u consecutive beacons\n",
375 sc->beacon.bmisscnt); 375 sc->beacon.bmisscnt);
376 ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
376 ath9k_hw_bstuck_nfcal(ah); 377 ath9k_hw_bstuck_nfcal(ah);
377 } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { 378 } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
378 ath_dbg(common, ATH_DBG_BSTUCK, 379 ath_dbg(common, ATH_DBG_BSTUCK,
@@ -450,16 +451,6 @@ void ath_beacon_tasklet(unsigned long data)
450 sc->beacon.updateslot = OK; 451 sc->beacon.updateslot = OK;
451 } 452 }
452 if (bfaddr != 0) { 453 if (bfaddr != 0) {
453 /*
454 * Stop any current dma and put the new frame(s) on the queue.
455 * This should never fail since we check above that no frames
456 * are still pending on the queue.
457 */
458 if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
459 ath_err(common, "beacon queue %u did not stop?\n",
460 sc->beacon.beaconq);
461 }
462
463 /* NB: cabq traffic should already be queued and primed */ 454 /* NB: cabq traffic should already be queued and primed */
464 ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); 455 ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
465 ath9k_hw_txstart(ah, sc->beacon.beaconq); 456 ath9k_hw_txstart(ah, sc->beacon.beaconq);
@@ -780,7 +771,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
780 ah->imask &= ~ATH9K_INT_SWBA; 771 ah->imask &= ~ATH9K_INT_SWBA;
781 ath9k_hw_set_interrupts(ah, ah->imask); 772 ath9k_hw_set_interrupts(ah, ah->imask);
782 tasklet_kill(&sc->bcon_tasklet); 773 tasklet_kill(&sc->bcon_tasklet);
783 ath9k_hw_stoptxdma(ah, sc->beacon.beaconq); 774 ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
784 } 775 }
785 ath9k_ps_restore(sc); 776 ath9k_ps_restore(sc);
786} 777}
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 58aaf9ab0920..cb5d81426d57 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -171,84 +171,31 @@ void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
171} 171}
172EXPORT_SYMBOL(ath9k_hw_abort_tx_dma); 172EXPORT_SYMBOL(ath9k_hw_abort_tx_dma);
173 173
174bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) 174bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q)
175{ 175{
176#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */ 176#define ATH9K_TX_STOP_DMA_TIMEOUT 1000 /* usec */
177#define ATH9K_TIME_QUANTUM 100 /* usec */ 177#define ATH9K_TIME_QUANTUM 100 /* usec */
178 struct ath_common *common = ath9k_hw_common(ah); 178 int wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
179 struct ath9k_hw_capabilities *pCap = &ah->caps; 179 int wait;
180 struct ath9k_tx_queue_info *qi;
181 u32 tsfLow, j, wait;
182 u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
183
184 if (q >= pCap->total_queues) {
185 ath_dbg(common, ATH_DBG_QUEUE,
186 "Stopping TX DMA, invalid queue: %u\n", q);
187 return false;
188 }
189
190 qi = &ah->txq[q];
191 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
192 ath_dbg(common, ATH_DBG_QUEUE,
193 "Stopping TX DMA, inactive queue: %u\n", q);
194 return false;
195 }
196 180
197 REG_WRITE(ah, AR_Q_TXD, 1 << q); 181 REG_WRITE(ah, AR_Q_TXD, 1 << q);
198 182
199 for (wait = wait_time; wait != 0; wait--) { 183 for (wait = wait_time; wait != 0; wait--) {
200 if (ath9k_hw_numtxpending(ah, q) == 0) 184 if (wait != wait_time)
201 break;
202 udelay(ATH9K_TIME_QUANTUM);
203 }
204
205 if (ath9k_hw_numtxpending(ah, q)) {
206 ath_dbg(common, ATH_DBG_QUEUE,
207 "%s: Num of pending TX Frames %d on Q %d\n",
208 __func__, ath9k_hw_numtxpending(ah, q), q);
209
210 for (j = 0; j < 2; j++) {
211 tsfLow = REG_READ(ah, AR_TSF_L32);
212 REG_WRITE(ah, AR_QUIET2,
213 SM(10, AR_QUIET2_QUIET_DUR));
214 REG_WRITE(ah, AR_QUIET_PERIOD, 100);
215 REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
216 REG_SET_BIT(ah, AR_TIMER_MODE,
217 AR_QUIET_TIMER_EN);
218
219 if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
220 break;
221
222 ath_dbg(common, ATH_DBG_QUEUE,
223 "TSF has moved while trying to set quiet time TSF: 0x%08x\n",
224 tsfLow);
225 }
226
227 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
228
229 udelay(200);
230 REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
231
232 wait = wait_time;
233 while (ath9k_hw_numtxpending(ah, q)) {
234 if ((--wait) == 0) {
235 ath_err(common,
236 "Failed to stop TX DMA in 100 msec after killing last frame\n");
237 break;
238 }
239 udelay(ATH9K_TIME_QUANTUM); 185 udelay(ATH9K_TIME_QUANTUM);
240 }
241 186
242 REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); 187 if (ath9k_hw_numtxpending(ah, q) == 0)
188 break;
243 } 189 }
244 190
245 REG_WRITE(ah, AR_Q_TXD, 0); 191 REG_WRITE(ah, AR_Q_TXD, 0);
192
246 return wait != 0; 193 return wait != 0;
247 194
248#undef ATH9K_TX_STOP_DMA_TIMEOUT 195#undef ATH9K_TX_STOP_DMA_TIMEOUT
249#undef ATH9K_TIME_QUANTUM 196#undef ATH9K_TIME_QUANTUM
250} 197}
251EXPORT_SYMBOL(ath9k_hw_stoptxdma); 198EXPORT_SYMBOL(ath9k_hw_stop_dma_queue);
252 199
253void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) 200void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
254{ 201{
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index d37c6d413be1..b2b2ff852c32 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -676,7 +676,7 @@ void ath9k_hw_txstart(struct ath_hw *ah, u32 q);
676void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds); 676void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds);
677u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); 677u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
678bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); 678bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
679bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); 679bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q);
680void ath9k_hw_abort_tx_dma(struct ath_hw *ah); 680void ath9k_hw_abort_tx_dma(struct ath_hw *ah);
681void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); 681void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
682bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, 682bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,