aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorNick Kossifidis <mick@madwifi.org>2008-09-28 18:23:07 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-09-30 14:07:26 -0400
commit509a106e68aa42acc1a0c44ab365d0de6869bd9e (patch)
tree2477b692d65bec9489f4db281b8ddcb7d0018a71 /drivers/net
parentee81c5544bbf49ea5b301784a605d865947ac1b0 (diff)
ath5k: Use QUIET mechanism on tx dma stop
* Use QUIET mechanism to drain tx buffer on PCU for newer chips * Make sure that INTPEND is really 1 and not 0xffffffff while checking for pending interrupts Changes-Licensed-under: ISC Signed-Off-by: Nick Kossifidis <mickflemm@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath5k/dma.c49
-rw-r--r--drivers/net/wireless/ath5k/reg.h4
2 files changed, 46 insertions, 7 deletions
diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c
index a28090be9603..7adceb2c7fab 100644
--- a/drivers/net/wireless/ath5k/dma.c
+++ b/drivers/net/wireless/ath5k/dma.c
@@ -68,7 +68,7 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
68 /* 68 /*
69 * It may take some time to disable the DMA receive unit 69 * It may take some time to disable the DMA receive unit
70 */ 70 */
71 for (i = 2000; i > 0 && 71 for (i = 1000; i > 0 &&
72 (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; 72 (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
73 i--) 73 i--)
74 udelay(10); 74 udelay(10);
@@ -182,11 +182,10 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
182 * have any pending frames. Returns -EBUSY if we still have pending frames, 182 * have any pending frames. Returns -EBUSY if we still have pending frames,
183 * -EINVAL if queue number is out of range. 183 * -EINVAL if queue number is out of range.
184 * 184 *
185 * TODO: Test queue drain code
186 */ 185 */
187int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) 186int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
188{ 187{
189 unsigned int i = 100; 188 unsigned int i = 40;
190 u32 tx_queue, pending; 189 u32 tx_queue, pending;
191 190
192 ATH5K_TRACE(ah->ah_sc); 191 ATH5K_TRACE(ah->ah_sc);
@@ -233,13 +232,53 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
233 udelay(100); 232 udelay(100);
234 } while (--i && pending); 233 } while (--i && pending);
235 234
235 /* For 2413+ order PCU to drop packets using
236 * QUIET mechanism */
237 if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) &&
238 pending){
239 /* Set periodicity and duration */
240 ath5k_hw_reg_write(ah,
241 AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)|
242 AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR),
243 AR5K_QUIET_CTL2);
244
245 /* Enable quiet period for current TSF */
246 ath5k_hw_reg_write(ah,
247 AR5K_QUIET_CTL1_QT_EN |
248 AR5K_REG_SM(ath5k_hw_reg_read(ah,
249 AR5K_TSF_L32_5211) >> 10,
250 AR5K_QUIET_CTL1_NEXT_QT_TSF),
251 AR5K_QUIET_CTL1);
252
253 /* Force channel idle high */
254 AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
255 AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
256
257 /* Wait a while and disable mechanism */
258 udelay(200);
259 AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1,
260 AR5K_QUIET_CTL1_QT_EN);
261
262 /* Re-check for pending frames */
263 i = 40;
264 do {
265 pending = ath5k_hw_reg_read(ah,
266 AR5K_QUEUE_STATUS(queue)) &
267 AR5K_QCU_STS_FRMPENDCNT;
268 udelay(100);
269 } while (--i && pending);
270
271 AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
272 AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
273 }
274
236 /* Clear register */ 275 /* Clear register */
237 ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); 276 ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
238 if (pending) 277 if (pending)
239 return -EBUSY; 278 return -EBUSY;
240 } 279 }
241 280
242 /* TODO: Check for success else return error */ 281 /* TODO: Check for success on 5210 else return error */
243 return 0; 282 return 0;
244} 283}
245 284
@@ -415,7 +454,7 @@ done:
415bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) 454bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
416{ 455{
417 ATH5K_TRACE(ah->ah_sc); 456 ATH5K_TRACE(ah->ah_sc);
418 return ath5k_hw_reg_read(ah, AR5K_INTPEND); 457 return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
419} 458}
420 459
421/** 460/**
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h
index 55054b575e83..e557fe178bbf 100644
--- a/drivers/net/wireless/ath5k/reg.h
+++ b/drivers/net/wireless/ath5k/reg.h
@@ -1424,7 +1424,7 @@
1424#define AR5K_DIAG_SW_OBSPT_S 18 1424#define AR5K_DIAG_SW_OBSPT_S 18
1425#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */ 1425#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */
1426#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */ 1426#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */
1427#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high (?) */ 1427#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high */
1428#define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */ 1428#define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */
1429 1429
1430/* 1430/*
@@ -1660,7 +1660,7 @@
1660 */ 1660 */
1661#define AR5K_QUIET_CTL1 0x80fc /* Register Address */ 1661#define AR5K_QUIET_CTL1 0x80fc /* Register Address */
1662#define AR5K_QUIET_CTL1_NEXT_QT_TSF 0x0000ffff /* Next quiet period TSF (TU) */ 1662#define AR5K_QUIET_CTL1_NEXT_QT_TSF 0x0000ffff /* Next quiet period TSF (TU) */
1663#define AR5K_QUIET_CTL1_NEXT_QT_TSF_0 1663#define AR5K_QUIET_CTL1_NEXT_QT_TSF_S 0
1664#define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet period */ 1664#define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet period */
1665#define AR5K_QUIET_CTL1_ACK_CTS_EN 0x00020000 /* Send ACK/CTS during quiet period */ 1665#define AR5K_QUIET_CTL1_ACK_CTS_EN 0x00020000 /* Send ACK/CTS during quiet period */
1666 1666