ath9k: Fix HW wait timeout
authorSujith <Sujith.Manoharan@atheros.com>
Mon, 16 Feb 2009 07:53:20 +0000 (13:23 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 27 Feb 2009 19:52:37 +0000 (14:52 -0500)
RX and calibration have different timeout requirements.
This patch fixes it by changing the HW wait routine
to accept a timeout value.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath9k/calib.c
drivers/net/wireless/ath9k/hw.c
drivers/net/wireless/ath9k/hw.h
drivers/net/wireless/ath9k/mac.c
drivers/net/wireless/ath9k/pci.c
drivers/net/wireless/ath9k/recv.c

index e5abe6564ca7b50c7641d583675e7e4e01e9c345..93c6e1f72353ad89964874088e51367f703cfa1c 100644 (file)
@@ -893,7 +893,8 @@ bool ath9k_hw_init_cal(struct ath_hw *ah,
                          AR_PHY_AGC_CONTROL_CAL);
 
                if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
-                                  AR_PHY_AGC_CONTROL_CAL, 0)) {
+                                  AR_PHY_AGC_CONTROL_CAL, 0,
+                                  AH_WAIT_TIMEOUT)) {
                        DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
                                "offset calibration failed to complete in 1ms; "
                                "noisy environment?\n");
@@ -910,7 +911,8 @@ bool ath9k_hw_init_cal(struct ath_hw *ah,
                  REG_READ(ah, AR_PHY_AGC_CONTROL) |
                  AR_PHY_AGC_CONTROL_CAL);
 
-       if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
+       if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
+                          0, AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
                        "offset calibration failed to complete in 1ms; "
                        "noisy environment?\n");
index 1c02358b31f5931c418db9c60b35d2d456e10206..eeee5b8081548f863ebeea40ca1d8c46c877fb57 100644 (file)
@@ -84,11 +84,13 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
                return ath9k_hw_mac_clks(ah, usecs);
 }
 
-bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val)
+bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
 {
        int i;
 
-       for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) {
+       BUG_ON(timeout < AH_TIME_QUANTUM);
+
+       for (i = 0; i < (timeout / AH_TIME_QUANTUM); i++) {
                if ((REG_READ(ah, reg) & mask) == val)
                        return true;
 
@@ -96,8 +98,8 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val)
        }
 
        DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-               "timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
-               reg, REG_READ(ah, reg), mask, val);
+               "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+               timeout, reg, REG_READ(ah, reg), mask, val);
 
        return false;
 }
@@ -1516,7 +1518,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
        udelay(50);
 
        REG_WRITE(ah, AR_RTC_RC, 0);
-       if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) {
+       if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET,
                        "RTC stuck in MAC reset\n");
                return false;
@@ -1545,7 +1547,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
        if (!ath9k_hw_wait(ah,
                           AR_RTC_STATUS,
                           AR_RTC_STATUS_M,
-                          AR_RTC_STATUS_ON)) {
+                          AR_RTC_STATUS_ON,
+                          AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n");
                return false;
        }
@@ -1640,7 +1643,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
 
        REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
        if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
-                          AR_PHY_RFBUS_GRANT_EN)) {
+                          AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
                        "Could not kill baseband RX\n");
                return false;
index 08469d9525bc580d1c9c4139634d45eba33bd107..ddab3b7d07b262c769975aaee38762b36112f714 100644 (file)
@@ -93,7 +93,7 @@
 #define ATH9K_NUM_QUEUES            10
 
 #define MAX_RATE_POWER              63
-#define AH_TIMEOUT                  100000
+#define AH_WAIT_TIMEOUT             100000 /* (us) */
 #define AH_TIME_QUANTUM             10
 #define AR_KEYTABLE_SIZE            128
 #define POWER_UP_TIME               200000
@@ -612,7 +612,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
                               u8 *antenna_cfgd);
 
 /* General Operation */
-bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val);
+bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
 u32 ath9k_hw_reverse_bits(u32 val, u32 n);
 bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high);
 u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates,
index f32c622db6e7c82322e0f27b929b51a6e09b529e..a6c204283ad56d415d90ecaa663961e3441b2230 100644 (file)
@@ -886,7 +886,8 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
                REG_SET_BIT(ah, AR_DIAG_SW,
                            (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 
-               if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
+               if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
+                                  0, AH_WAIT_TIMEOUT)) {
                        REG_CLR_BIT(ah, AR_DIAG_SW,
                                    (AR_DIAG_RX_DIS |
                                     AR_DIAG_RX_ABORT));
@@ -933,15 +934,32 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah)
 
 bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
 {
+#define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
+#define AH_RX_TIME_QUANTUM     100     /* usec */
+
+       int i;
+
        REG_WRITE(ah, AR_CR, AR_CR_RXD);
 
-       if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
+       /* Wait for rx enable bit to go low */
+       for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
+               if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
+                       break;
+               udelay(AH_TIME_QUANTUM);
+       }
+
+       if (i == 0) {
                DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-                       "dma failed to stop in 10ms\n"
-                       "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
-                       REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
+                       "dma failed to stop in %d ms "
+                       "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
+                       AH_RX_STOP_DMA_TIMEOUT / 1000,
+                       REG_READ(ah, AR_CR),
+                       REG_READ(ah, AR_DIAG_SW));
                return false;
        } else {
                return true;
        }
+
+#undef AH_RX_TIME_QUANTUM
+#undef AH_RX_STOP_DMA_TIMEOUT
 }
index c28afe42b2694c31866306399e909228828e5910..a70f954c9e75474f1f5765444c2528c6580b151b 100644 (file)
@@ -63,7 +63,8 @@ static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
        if (!ath9k_hw_wait(ah,
                           AR_EEPROM_STATUS_DATA,
                           AR_EEPROM_STATUS_DATA_BUSY |
-                          AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
+                          AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
+                          AH_WAIT_TIMEOUT)) {
                return false;
        }
 
index 08f676af894f0cbd9d3b98185b6aba6663751774..28ad1d5af129aec5cc42e1ece1265393db06699e 100644 (file)
@@ -427,7 +427,6 @@ bool ath_stoprecv(struct ath_softc *sc)
        ath9k_hw_stoppcurecv(ah);
        ath9k_hw_setrxfilter(ah, 0);
        stopped = ath9k_hw_stopdmarecv(ah);
-       mdelay(3); /* 3ms is long enough for 1 frame */
        sc->rx.rxlink = NULL;
 
        return stopped;