From owner-svn-src-all@FreeBSD.ORG Sat Apr 23 06:37:10 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1BBF21065740; Sat, 23 Apr 2011 06:37:10 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 087768FC13; Sat, 23 Apr 2011 06:37:10 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p3N6b9D8075411; Sat, 23 Apr 2011 06:37:09 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p3N6b9gU075408; Sat, 23 Apr 2011 06:37:09 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201104230637.p3N6b9gU075408@svn.freebsd.org> From: Adrian Chadd Date: Sat, 23 Apr 2011 06:37:09 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r220966 - in head/sys/dev/ath: . ath_hal/ar5416 X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 23 Apr 2011 06:37:10 -0000 Author: adrian Date: Sat Apr 23 06:37:09 2011 New Revision: 220966 URL: http://svn.freebsd.org/changeset/base/220966 Log: Fix a corner-case of interrupt handling which resulted in potentially spurious (and fatal) interrupt errors. One user reported seeing this: Apr 22 18:04:24 ceres kernel: ar5416GetPendingInterrupts: fatal error, ISR_RAC 0x0 SYNC_CAUSE 0x2000 SYNC_CAUSE of 0x2000 is AR_INTR_SYNC_LOCAL_TIMEOUT which is a bus timeout; this shouldn't cause HAL_INT_FATAL to be set. After checking out ath9k, ath9k_ar9002_hw_get_isr() clears (*masked) before continuing, regardless of whether any bits in the ISR registers are set. So if AR_INTR_SYNC_CAUSE is set to something that isn't treated as fatal, and AR_ISR isn't read or is read and is 0, then (*masked) wouldn't be cleared. Thus any of the existing bits set that were passed in would be preserved in the output. The caller in if_ath - ath_intr() - wasn't setting the masked value to 0 before calling ath_hal_getisr(), so anything that was present in that uninitialised variable would be preserved in the case above of AR_ISR=0, AR_INTR_SYNC_CAUSE != 0; and if the HAL_INT_FATAL bit was set, a fatal condition would be interpreted and the chip was reset. This patch does the following: * ath_intr() - set masked to 0 before calling ath_hal_getisr(); * ar5416GetPendingInterrupts() - clear (*masked) before processing continues; so if the interrupt source is AR_INTR_SYNC_CAUSE and it isn't fatal, the hardware isn't reset via returning HAL_INT_FATAL. This doesn't fix any underlying errors which trigger AR_INTR_SYNC_LOCAL_TIMEOUT - which is a bus timeout of some sort - so that likely should be further investigated. Modified: head/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c head/sys/dev/ath/if_ath.c Modified: head/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c ============================================================================== --- head/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c Sat Apr 23 05:56:06 2011 (r220965) +++ head/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c Sat Apr 23 06:37:09 2011 (r220966) @@ -55,6 +55,8 @@ ar5416IsInterruptPending(struct ath_hal * values. The value returned is mapped to abstract the hw-specific bit * locations in the Interrupt Status Register. * + * (*masked) is cleared on initial call. + * * Returns: A hardware-abstracted bitmap of all non-masked-out * interrupts pending, as well as an unmasked value */ @@ -73,10 +75,10 @@ ar5416GetPendingInterrupts(struct ath_ha isr = 0; sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); sync_cause &= AR_INTR_SYNC_DEFAULT; - if (isr == 0 && sync_cause == 0) { - *masked = 0; + *masked = 0; + + if (isr == 0 && sync_cause == 0) return AH_FALSE; - } if (isr != 0) { struct ath_hal_5212 *ahp = AH5212(ah); Modified: head/sys/dev/ath/if_ath.c ============================================================================== --- head/sys/dev/ath/if_ath.c Sat Apr 23 05:56:06 2011 (r220965) +++ head/sys/dev/ath/if_ath.c Sat Apr 23 06:37:09 2011 (r220966) @@ -1265,7 +1265,7 @@ ath_intr(void *arg) struct ath_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; struct ath_hal *ah = sc->sc_ah; - HAL_INT status; + HAL_INT status = 0; if (sc->sc_invalid) { /* @@ -1296,6 +1296,11 @@ ath_intr(void *arg) ath_hal_getisr(ah, &status); /* NB: clears ISR too */ DPRINTF(sc, ATH_DEBUG_INTR, "%s: status 0x%x\n", __func__, status); status &= sc->sc_imask; /* discard unasked for bits */ + + /* Short-circuit un-handled interrupts */ + if (status == 0x0) + return; + if (status & HAL_INT_FATAL) { sc->sc_stats.ast_hardware++; ath_hal_intrset(ah, 0); /* disable intr's until reset */