Commit 73f0b56a authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville

ath9k: Fix interrupt handling for the AR9002 family

This patch adds a driver workaround for a HW issue.

A race condition in the HW results in missing interrupts,
which can be avoided by a read/write with the ISR register.
All chips in the AR9002 series are affected by this bug - AR9003
and above do not have this problem.

Cc: stable@vger.kernel.org
Cc: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarSujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 9278db62
...@@ -76,9 +76,16 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ...@@ -76,9 +76,16 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
mask2 |= ATH9K_INT_CST; mask2 |= ATH9K_INT_CST;
if (isr2 & AR_ISR_S2_TSFOOR) if (isr2 & AR_ISR_S2_TSFOOR)
mask2 |= ATH9K_INT_TSFOOR; mask2 |= ATH9K_INT_TSFOOR;
if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
REG_WRITE(ah, AR_ISR_S2, isr2);
isr &= ~AR_ISR_BCNMISC;
}
} }
isr = REG_READ(ah, AR_ISR_RAC); if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)
isr = REG_READ(ah, AR_ISR_RAC);
if (isr == 0xffffffff) { if (isr == 0xffffffff) {
*masked = 0; *masked = 0;
return false; return false;
...@@ -97,11 +104,23 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ...@@ -97,11 +104,23 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
*masked |= ATH9K_INT_TX; *masked |= ATH9K_INT_TX;
s0_s = REG_READ(ah, AR_ISR_S0_S); if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) {
s0_s = REG_READ(ah, AR_ISR_S0_S);
s1_s = REG_READ(ah, AR_ISR_S1_S);
} else {
s0_s = REG_READ(ah, AR_ISR_S0);
REG_WRITE(ah, AR_ISR_S0, s0_s);
s1_s = REG_READ(ah, AR_ISR_S1);
REG_WRITE(ah, AR_ISR_S1, s1_s);
isr &= ~(AR_ISR_TXOK |
AR_ISR_TXDESC |
AR_ISR_TXERR |
AR_ISR_TXEOL);
}
ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK); ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
s1_s = REG_READ(ah, AR_ISR_S1_S);
ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
} }
...@@ -114,13 +133,15 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ...@@ -114,13 +133,15 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
*masked |= mask2; *masked |= mask2;
} }
if (AR_SREV_9100(ah)) if (!AR_SREV_9100(ah) && (isr & AR_ISR_GENTMR)) {
return true;
if (isr & AR_ISR_GENTMR) {
u32 s5_s; u32 s5_s;
s5_s = REG_READ(ah, AR_ISR_S5_S); if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) {
s5_s = REG_READ(ah, AR_ISR_S5_S);
} else {
s5_s = REG_READ(ah, AR_ISR_S5);
}
ah->intr_gen_timer_trigger = ah->intr_gen_timer_trigger =
MS(s5_s, AR_ISR_S5_GENTIMER_TRIG); MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
...@@ -133,8 +154,21 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ...@@ -133,8 +154,21 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
if ((s5_s & AR_ISR_S5_TIM_TIMER) && if ((s5_s & AR_ISR_S5_TIM_TIMER) &&
!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) !(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
*masked |= ATH9K_INT_TIM_TIMER; *masked |= ATH9K_INT_TIM_TIMER;
if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
REG_WRITE(ah, AR_ISR_S5, s5_s);
isr &= ~AR_ISR_GENTMR;
}
} }
if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
REG_WRITE(ah, AR_ISR, isr);
REG_READ(ah, AR_ISR);
}
if (AR_SREV_9100(ah))
return true;
if (sync_cause) { if (sync_cause) {
ath9k_debug_sync_cause(common, sync_cause); ath9k_debug_sync_cause(common, sync_cause);
fatal_int = fatal_int =
......
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