Commit 0caa7b14 authored by Sujith's avatar Sujith Committed by John W. Linville

ath9k: Fix HW wait timeout

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: default avatarSujith <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 70768496
...@@ -893,7 +893,8 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, ...@@ -893,7 +893,8 @@ bool ath9k_hw_init_cal(struct ath_hw *ah,
AR_PHY_AGC_CONTROL_CAL); AR_PHY_AGC_CONTROL_CAL);
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, 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, DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
"offset calibration failed to complete in 1ms; " "offset calibration failed to complete in 1ms; "
"noisy environment?\n"); "noisy environment?\n");
...@@ -910,7 +911,8 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, ...@@ -910,7 +911,8 @@ bool ath9k_hw_init_cal(struct ath_hw *ah,
REG_READ(ah, AR_PHY_AGC_CONTROL) | REG_READ(ah, AR_PHY_AGC_CONTROL) |
AR_PHY_AGC_CONTROL_CAL); 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, DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
"offset calibration failed to complete in 1ms; " "offset calibration failed to complete in 1ms; "
"noisy environment?\n"); "noisy environment?\n");
......
...@@ -84,11 +84,13 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) ...@@ -84,11 +84,13 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
return ath9k_hw_mac_clks(ah, 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; 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) if ((REG_READ(ah, reg) & mask) == val)
return true; return true;
...@@ -96,8 +98,8 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val) ...@@ -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, DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
"timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
reg, REG_READ(ah, reg), mask, val); timeout, reg, REG_READ(ah, reg), mask, val);
return false; return false;
} }
...@@ -1516,7 +1518,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) ...@@ -1516,7 +1518,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
udelay(50); udelay(50);
REG_WRITE(ah, AR_RTC_RC, 0); 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, DPRINTF(ah->ah_sc, ATH_DBG_RESET,
"RTC stuck in MAC reset\n"); "RTC stuck in MAC reset\n");
return false; return false;
...@@ -1545,7 +1547,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) ...@@ -1545,7 +1547,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
if (!ath9k_hw_wait(ah, if (!ath9k_hw_wait(ah,
AR_RTC_STATUS, AR_RTC_STATUS,
AR_RTC_STATUS_M, 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"); DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n");
return false; return false;
} }
...@@ -1640,7 +1643,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ...@@ -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); 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, 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, DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
"Could not kill baseband RX\n"); "Could not kill baseband RX\n");
return false; return false;
......
...@@ -93,7 +93,7 @@ ...@@ -93,7 +93,7 @@
#define ATH9K_NUM_QUEUES 10 #define ATH9K_NUM_QUEUES 10
#define MAX_RATE_POWER 63 #define MAX_RATE_POWER 63
#define AH_TIMEOUT 100000 #define AH_WAIT_TIMEOUT 100000 /* (us) */
#define AH_TIME_QUANTUM 10 #define AH_TIME_QUANTUM 10
#define AR_KEYTABLE_SIZE 128 #define AR_KEYTABLE_SIZE 128
#define POWER_UP_TIME 200000 #define POWER_UP_TIME 200000
...@@ -612,7 +612,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah, ...@@ -612,7 +612,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
u8 *antenna_cfgd); u8 *antenna_cfgd);
/* General Operation */ /* 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); u32 ath9k_hw_reverse_bits(u32 val, u32 n);
bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); 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, u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates,
......
...@@ -886,7 +886,8 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) ...@@ -886,7 +886,8 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
REG_SET_BIT(ah, AR_DIAG_SW, REG_SET_BIT(ah, AR_DIAG_SW,
(AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); (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, REG_CLR_BIT(ah, AR_DIAG_SW,
(AR_DIAG_RX_DIS | (AR_DIAG_RX_DIS |
AR_DIAG_RX_ABORT)); AR_DIAG_RX_ABORT));
...@@ -933,15 +934,32 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah) ...@@ -933,15 +934,32 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah)
bool ath9k_hw_stopdmarecv(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); 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, DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
"dma failed to stop in 10ms\n" "dma failed to stop in %d ms "
"AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); AH_RX_STOP_DMA_TIMEOUT / 1000,
REG_READ(ah, AR_CR),
REG_READ(ah, AR_DIAG_SW));
return false; return false;
} else { } else {
return true; return true;
} }
#undef AH_RX_TIME_QUANTUM
#undef AH_RX_STOP_DMA_TIMEOUT
} }
...@@ -63,7 +63,8 @@ static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) ...@@ -63,7 +63,8 @@ static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
if (!ath9k_hw_wait(ah, if (!ath9k_hw_wait(ah,
AR_EEPROM_STATUS_DATA, AR_EEPROM_STATUS_DATA,
AR_EEPROM_STATUS_DATA_BUSY | AR_EEPROM_STATUS_DATA_BUSY |
AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
AH_WAIT_TIMEOUT)) {
return false; return false;
} }
......
...@@ -427,7 +427,6 @@ bool ath_stoprecv(struct ath_softc *sc) ...@@ -427,7 +427,6 @@ bool ath_stoprecv(struct ath_softc *sc)
ath9k_hw_stoppcurecv(ah); ath9k_hw_stoppcurecv(ah);
ath9k_hw_setrxfilter(ah, 0); ath9k_hw_setrxfilter(ah, 0);
stopped = ath9k_hw_stopdmarecv(ah); stopped = ath9k_hw_stopdmarecv(ah);
mdelay(3); /* 3ms is long enough for 1 frame */
sc->rx.rxlink = NULL; sc->rx.rxlink = NULL;
return stopped; return stopped;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment