Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 14 Sep 2011 07:56:25 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r225548 - in user/adrian/if_ath_tx/sys/dev/ath/ath_hal: . ar5416
Message-ID:  <201109140756.p8E7uP9Y016924@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201109140756.p8E7uP9Y016924>