Skip to content

Commit

Permalink
ath9k: Fix HW wait timeout
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sujith authored and John W. Linville committed Feb 27, 2009
1 parent 7076849 commit 0caa7b1
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 18 deletions.
6 changes: 4 additions & 2 deletions drivers/net/wireless/ath9k/calib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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");
Expand Down
17 changes: 10 additions & 7 deletions drivers/net/wireless/ath9k/hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,22 @@ 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;

udelay(AH_TIME_QUANTUM);
}

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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath9k/hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
28 changes: 23 additions & 5 deletions drivers/net/wireless/ath9k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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
}
3 changes: 2 additions & 1 deletion drivers/net/wireless/ath9k/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/ath9k/recv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 0caa7b1

Please sign in to comment.