svn commit: r225548 - in user/adrian/if_ath_tx/sys/dev/ath/ath_hal:
. ar5416
Adrian Chadd
adrian at FreeBSD.org
Wed Sep 14 07:56:26 UTC 2011
Author: adrian
Date: Wed Sep 14 07:56:25 2011
New Revision: 225548
URL: http://svn.freebsd.org/changeset/base/225548
Log:
Add support to use the non read-and-copy interrupt register path.
There appears to be a subtle race condition in the AR_ISR_RAC
path where some of the secondary conditions would be not show
up. This unfortunately includes TX events such as EOL.
The reference driver includes an alternate path which instead
uses the AR_ISR and AR_ISR_S{0,1,2,3,4,5} registers instead of
AR_ISR_RAC and the shadow AR_ISR_S{0,1,2,3,4,5}_S registers.
Here, the interrupts being handled are written back to the
status register, clearing them.
For interrupts caused by secondary registers, clear those bits
instead of the relevant bit in AR_ISR. That way if an event
occurs between the ISR_ISR_Sx read and write (clear), it won't
be cleared; and it'll trigger another interrupt.
This won't _entirely_ limit the TX hangs because of the
existing txqactive() race going on between the interrupt
handler and the TX process. I'll address that in a future commit.
Note: I should also do this for the AR5212 series NICs as well
as some of them may suffer from the same race.
Finally - for now, never set the relevant HAL capability that
I've introduced; I'll set it when I know which chips work and
which don't.
Finally finally - ath9k doesn't do this for the pre-ar9003
NICs but does for AR9300 v2.0 and later. ie, the AR9300 NIC
interrupt code has this RAC capability check, and only enables
it for AR9300 v2.0 MAC versions.
Obtained from: Atheros, Linux ath9k
Modified:
user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ah_internal.h
user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c
user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ar5416/ar5416reg.h
Modified: user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ah_internal.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ah_internal.h Wed Sep 14 04:13:48 2011 (r225547)
+++ user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ah_internal.h Wed Sep 14 07:56:25 2011 (r225548)
@@ -208,7 +208,13 @@ typedef struct {
halBssidMatchSupport : 1,
hal4kbSplitTransSupport : 1,
halHasRxSelfLinkedTail : 1,
- halSupportsFastClock5GHz : 1; /* Hardware supports 5ghz fast clock; check eeprom/channel before using */
+ /*
+ * Hardware supports 5ghz fast clock;
+ * check eeprom/channel before using
+ */
+ halSupportsFastClock5GHz : 1,
+ /* use AR_ISR_RAC and shadow registers */
+ halUseIsrRac : 1;
uint32_t halWirelessModes;
uint16_t halTotalQueues;
uint16_t halKeyCacheSize;
Modified: user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c Wed Sep 14 04:13:48 2011 (r225547)
+++ user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c Wed Sep 14 07:56:25 2011 (r225548)
@@ -68,6 +68,7 @@ HAL_BOOL
ar5416GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked)
{
uint32_t isr, isr0, isr1, sync_cause = 0;
+ HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
/*
* Verify there's a mac interrupt and the RTC is on.
@@ -110,9 +111,22 @@ ar5416GetPendingInterrupts(struct ath_ha
mask2 |= HAL_INT_CST;
if (isr2 & AR_ISR_S2_TSFOOR)
mask2 |= HAL_INT_TSFOOR;
+
+ /* XXX TXURN? */
+
+ /*
+ * Don't mask out AR_BCNMISC; instead mask
+ * out what causes it.
+ */
+ if (! pCap->halUseIsrRac) {
+ OS_REG_WRITE(ah, AR_ISR_S2, isr2);
+ isr &= ~AR_ISR_BCNMISC;
+ }
}
- isr = OS_REG_READ(ah, AR_ISR_RAC);
+ if (pCap->halUseIsrRac)
+ isr = OS_REG_READ(ah, AR_ISR_RAC);
+
if (isr == 0xffffffff) {
*masked = 0;
return AH_FALSE;
@@ -130,28 +144,64 @@ ar5416GetPendingInterrupts(struct ath_ha
*/
*masked = isr & HAL_INT_COMMON;
- if (isr & (AR_ISR_RXOK | AR_ISR_RXERR | AR_ISR_RXMINTR | AR_ISR_RXINTM))
+ if (isr & (AR_ISR_RXOK | AR_ISR_RXERR | AR_ISR_RXMINTR |
+ AR_ISR_RXINTM))
*masked |= HAL_INT_RX;
- if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL | AR_ISR_TXMINTR | AR_ISR_TXINTM)) {
+ if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
+ AR_ISR_TXEOL | AR_ISR_TXMINTR | AR_ISR_TXINTM)) {
*masked |= HAL_INT_TX;
- isr0 = OS_REG_READ(ah, AR_ISR_S0_S);
+ if (pCap->halUseIsrRac) {
+ isr0 = OS_REG_READ(ah, AR_ISR_S0_S);
+ isr1 = OS_REG_READ(ah, AR_ISR_S1_S);
+ } else {
+ isr0 = OS_REG_READ(ah, AR_ISR_S0);
+ OS_REG_WRITE(ah, AR_ISR_S0, isr0);
+ isr1 = OS_REG_READ(ah, AR_ISR_S1);
+ OS_REG_WRITE(ah, AR_ISR_S1, isr1);
+
+ /*
+ * Don't clear the primary ISR TX bits, clear
+ * what causes them (S0/S1.)
+ */
+ isr &= ~(AR_ISR_TXOK | AR_ISR_TXDESC |
+ AR_ISR_TXERR | AR_ISR_TXEOL);
+ }
ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXOK);
ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXDESC);
- isr1 = OS_REG_READ(ah, AR_ISR_S1_S);
ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXERR);
ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXEOL);
}
if (AR_SREV_MERLIN(ah) || AR_SREV_KITE(ah)) {
uint32_t isr5;
- isr5 = OS_REG_READ(ah, AR_ISR_S5_S);
+ if (pCap->halUseIsrRac) {
+ isr5 = OS_REG_READ(ah, AR_ISR_S5_S);
+ } else {
+ isr5 = OS_REG_READ(ah, AR_ISR_S5);
+ OS_REG_WRITE(ah, AR_ISR_S5, isr5);
+ isr &= ~AR_ISR_GENTMR;
+ }
if (isr5 & AR_ISR_S5_TIM_TIMER)
*masked |= HAL_INT_TIM_TIMER;
}
-
*masked |= mask2;
}
+ if (! pCap->halUseIsrRac) {
+ /*
+ * If we're not using AR_ISR_RAC, clear the status bits
+ * for handled interrupts here. For bits whose interrupt
+ * source is a secondary register, those bits should've been
+ * masked out - instead of those bits being written back,
+ * their source (ie, the secondary status registers) should
+ * be cleared. That way there are no race conditions with
+ * new triggers coming in whilst they've been read/cleared.
+ */
+ OS_REG_WRITE(ah, AR_ISR, isr);
+ /* Flush previous write */
+ OS_REG_READ(ah, AR_ISR);
+ }
+
if (AR_SREV_HOWL(ah))
return AH_TRUE;
Modified: user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ar5416/ar5416reg.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ar5416/ar5416reg.h Wed Sep 14 04:13:48 2011 (r225547)
+++ user/adrian/if_ath_tx/sys/dev/ath/ath_hal/ar5416/ar5416reg.h Wed Sep 14 07:56:25 2011 (r225548)
@@ -242,6 +242,7 @@
/* Interrupts */
#define AR_ISR_TXMINTR 0x00080000 /* Maximum interrupt tx rate */
#define AR_ISR_RXMINTR 0x01000000 /* Maximum interrupt rx rate */
+#define AR_ISR_GENTMR 0x10000000 /* OR of generic timer bits in S5 */
#define AR_ISR_TXINTM 0x40000000 /* Tx int after mitigation */
#define AR_ISR_RXINTM 0x80000000 /* Rx int after mitigation */
More information about the svn-src-user
mailing list