Path: blob/main/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2008 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"2223#include "ar5416/ar5416.h"24#include "ar5416/ar5416reg.h"2526/*27* Checks to see if an interrupt is pending on our NIC28*29* Returns: TRUE if an interrupt is pending30* FALSE if not31*/32HAL_BOOL33ar5416IsInterruptPending(struct ath_hal *ah)34{35uint32_t isr;3637if (AR_SREV_HOWL(ah))38return AH_TRUE;3940/*41* Some platforms trigger our ISR before applying power to42* the card, so make sure the INTPEND is really 1, not 0xffffffff.43*/44isr = OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE);45if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_MAC_IRQ) != 0)46return AH_TRUE;4748isr = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE);49if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_SYNC_DEFAULT))50return AH_TRUE;5152return AH_FALSE;53}5455/*56* Reads the Interrupt Status Register value from the NIC, thus deasserting57* the interrupt line, and returns both the masked and unmasked mapped ISR58* values. The value returned is mapped to abstract the hw-specific bit59* locations in the Interrupt Status Register.60*61* (*masked) is cleared on initial call.62*63* Returns: A hardware-abstracted bitmap of all non-masked-out64* interrupts pending, as well as an unmasked value65*/66HAL_BOOL67ar5416GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked)68{69uint32_t isr, isr0, isr1, sync_cause = 0, o_sync_cause = 0;70HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;7172#ifdef AH_INTERRUPT_DEBUGGING73/*74* Blank the interrupt debugging area regardless.75*/76bzero(&ah->ah_intrstate, sizeof(ah->ah_intrstate));77ah->ah_syncstate = 0;78#endif7980/*81* Verify there's a mac interrupt and the RTC is on.82*/83if (AR_SREV_HOWL(ah)) {84*masked = 0;85isr = OS_REG_READ(ah, AR_ISR);86} else {87if ((OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) &&88(OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON)89isr = OS_REG_READ(ah, AR_ISR);90else91isr = 0;92#ifdef AH_INTERRUPT_DEBUGGING93ah->ah_syncstate =94#endif95o_sync_cause = sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE);96sync_cause &= AR_INTR_SYNC_DEFAULT;97*masked = 0;9899if (isr == 0 && sync_cause == 0)100return AH_FALSE;101}102103#ifdef AH_INTERRUPT_DEBUGGING104ah->ah_intrstate[0] = isr;105ah->ah_intrstate[1] = OS_REG_READ(ah, AR_ISR_S0);106ah->ah_intrstate[2] = OS_REG_READ(ah, AR_ISR_S1);107ah->ah_intrstate[3] = OS_REG_READ(ah, AR_ISR_S2);108ah->ah_intrstate[4] = OS_REG_READ(ah, AR_ISR_S3);109ah->ah_intrstate[5] = OS_REG_READ(ah, AR_ISR_S4);110ah->ah_intrstate[6] = OS_REG_READ(ah, AR_ISR_S5);111#endif112113if (isr != 0) {114struct ath_hal_5212 *ahp = AH5212(ah);115uint32_t mask2;116117mask2 = 0;118if (isr & AR_ISR_BCNMISC) {119uint32_t isr2 = OS_REG_READ(ah, AR_ISR_S2);120if (isr2 & AR_ISR_S2_TIM)121mask2 |= HAL_INT_TIM;122if (isr2 & AR_ISR_S2_DTIM)123mask2 |= HAL_INT_DTIM;124if (isr2 & AR_ISR_S2_DTIMSYNC)125mask2 |= HAL_INT_DTIMSYNC;126if (isr2 & (AR_ISR_S2_CABEND ))127mask2 |= HAL_INT_CABEND;128if (isr2 & AR_ISR_S2_GTT)129mask2 |= HAL_INT_GTT;130if (isr2 & AR_ISR_S2_CST)131mask2 |= HAL_INT_CST;132if (isr2 & AR_ISR_S2_TSFOOR)133mask2 |= HAL_INT_TSFOOR;134135/*136* Don't mask out AR_BCNMISC; instead mask137* out what causes it.138*/139OS_REG_WRITE(ah, AR_ISR_S2, isr2);140isr &= ~AR_ISR_BCNMISC;141}142143if (isr == 0xffffffff) {144*masked = 0;145return AH_FALSE;146}147148*masked = isr & HAL_INT_COMMON;149150if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))151*masked |= HAL_INT_RX;152if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))153*masked |= HAL_INT_TX;154155/*156* When doing RX interrupt mitigation, the RXOK bit is set157* in AR_ISR even if the relevant bit in AR_IMR is clear.158* Since this interrupt may be due to another source, don't159* just automatically set HAL_INT_RX if it's set, otherwise160* we could prematurely service the RX queue.161*162* In some cases, the driver can even handle all the RX163* frames just before the mitigation interrupt fires.164* The subsequent RX processing trip will then end up165* processing 0 frames.166*/167#ifdef AH_AR5416_INTERRUPT_MITIGATION168if (isr & AR_ISR_RXERR)169*masked |= HAL_INT_RX;170#else171if (isr & (AR_ISR_RXOK | AR_ISR_RXERR))172*masked |= HAL_INT_RX;173#endif174175if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |176AR_ISR_TXEOL)) {177*masked |= HAL_INT_TX;178179isr0 = OS_REG_READ(ah, AR_ISR_S0);180OS_REG_WRITE(ah, AR_ISR_S0, isr0);181isr1 = OS_REG_READ(ah, AR_ISR_S1);182OS_REG_WRITE(ah, AR_ISR_S1, isr1);183184/*185* Don't clear the primary ISR TX bits, clear186* what causes them (S0/S1.)187*/188isr &= ~(AR_ISR_TXOK | AR_ISR_TXDESC |189AR_ISR_TXERR | AR_ISR_TXEOL);190191ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXOK);192ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXDESC);193ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXERR);194ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXEOL);195}196197if ((isr & AR_ISR_GENTMR) || (! pCap->halAutoSleepSupport)) {198uint32_t isr5;199isr5 = OS_REG_READ(ah, AR_ISR_S5);200OS_REG_WRITE(ah, AR_ISR_S5, isr5);201isr &= ~AR_ISR_GENTMR;202203if (! pCap->halAutoSleepSupport)204if (isr5 & AR_ISR_S5_TIM_TIMER)205*masked |= HAL_INT_TIM_TIMER;206}207*masked |= mask2;208}209210/*211* Since we're not using AR_ISR_RAC, clear the status bits212* for handled interrupts here. For bits whose interrupt213* source is a secondary register, those bits should've been214* masked out - instead of those bits being written back,215* their source (ie, the secondary status registers) should216* be cleared. That way there are no race conditions with217* new triggers coming in whilst they've been read/cleared.218*/219OS_REG_WRITE(ah, AR_ISR, isr);220/* Flush previous write */221OS_REG_READ(ah, AR_ISR);222223if (AR_SREV_HOWL(ah))224return AH_TRUE;225226if (sync_cause != 0) {227HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: sync_cause=0x%x\n",228__func__,229o_sync_cause);230if (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) {231*masked |= HAL_INT_FATAL;232}233if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {234HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RADM CPL timeout\n",235__func__);236OS_REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);237OS_REG_WRITE(ah, AR_RC, 0);238*masked |= HAL_INT_FATAL;239}240/*241* On fatal errors collect ISR state for debugging.242*/243if (*masked & HAL_INT_FATAL) {244AH_PRIVATE(ah)->ah_fatalState[0] = isr;245AH_PRIVATE(ah)->ah_fatalState[1] = sync_cause;246HALDEBUG(ah, HAL_DEBUG_ANY,247"%s: fatal error, ISR_RAC 0x%x SYNC_CAUSE 0x%x\n",248__func__, isr, sync_cause);249}250251OS_REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);252/* NB: flush write */253(void) OS_REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);254}255return AH_TRUE;256}257258/*259* Atomically enables NIC interrupts. Interrupts are passed in260* via the enumerated bitmask in ints.261*/262HAL_INT263ar5416SetInterrupts(struct ath_hal *ah, HAL_INT ints)264{265struct ath_hal_5212 *ahp = AH5212(ah);266uint32_t omask = ahp->ah_maskReg;267uint32_t mask, mask2;268269HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: 0x%x => 0x%x\n",270__func__, omask, ints);271272if (omask & HAL_INT_GLOBAL) {273HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__);274OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE);275(void) OS_REG_READ(ah, AR_IER);276277if (! AR_SREV_HOWL(ah)) {278OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);279(void) OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE);280281OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);282(void) OS_REG_READ(ah, AR_INTR_SYNC_ENABLE);283}284}285286mask = ints & HAL_INT_COMMON;287mask2 = 0;288289#ifdef AH_AR5416_INTERRUPT_MITIGATION290/*291* Overwrite default mask if Interrupt mitigation292* is specified for AR5416293*/294if (ints & HAL_INT_RX)295mask |= AR_IMR_RXERR | AR_IMR_RXMINTR | AR_IMR_RXINTM;296#else297if (ints & HAL_INT_RX)298mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC;299#endif300if (ints & HAL_INT_TX) {301if (ahp->ah_txOkInterruptMask)302mask |= AR_IMR_TXOK;303if (ahp->ah_txErrInterruptMask)304mask |= AR_IMR_TXERR;305if (ahp->ah_txDescInterruptMask)306mask |= AR_IMR_TXDESC;307if (ahp->ah_txEolInterruptMask)308mask |= AR_IMR_TXEOL;309if (ahp->ah_txUrnInterruptMask)310mask |= AR_IMR_TXURN;311}312if (ints & (HAL_INT_BMISC)) {313mask |= AR_IMR_BCNMISC;314if (ints & HAL_INT_TIM)315mask2 |= AR_IMR_S2_TIM;316if (ints & HAL_INT_DTIM)317mask2 |= AR_IMR_S2_DTIM;318if (ints & HAL_INT_DTIMSYNC)319mask2 |= AR_IMR_S2_DTIMSYNC;320if (ints & HAL_INT_CABEND)321mask2 |= (AR_IMR_S2_CABEND );322if (ints & HAL_INT_CST)323mask2 |= AR_IMR_S2_CST;324if (ints & HAL_INT_TSFOOR)325mask2 |= AR_IMR_S2_TSFOOR;326}327328if (ints & (HAL_INT_GTT | HAL_INT_CST)) {329mask |= AR_IMR_BCNMISC;330if (ints & HAL_INT_GTT)331mask2 |= AR_IMR_S2_GTT;332if (ints & HAL_INT_CST)333mask2 |= AR_IMR_S2_CST;334}335336/* Write the new IMR and store off our SW copy. */337HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask);338OS_REG_WRITE(ah, AR_IMR, mask);339/* Flush write */340(void) OS_REG_READ(ah, AR_IMR);341342mask = OS_REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |343AR_IMR_S2_DTIM |344AR_IMR_S2_DTIMSYNC |345AR_IMR_S2_CABEND |346AR_IMR_S2_CABTO |347AR_IMR_S2_TSFOOR |348AR_IMR_S2_GTT |349AR_IMR_S2_CST);350OS_REG_WRITE(ah, AR_IMR_S2, mask | mask2);351352ahp->ah_maskReg = ints;353354/* Re-enable interrupts if they were enabled before. */355if (ints & HAL_INT_GLOBAL) {356HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__);357OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE);358359if (! AR_SREV_HOWL(ah)) {360mask = AR_INTR_MAC_IRQ;361if (ints & HAL_INT_GPIO)362mask |= SM(AH5416(ah)->ah_gpioMask,363AR_INTR_ASYNC_MASK_GPIO);364OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, mask);365OS_REG_WRITE(ah, AR_INTR_ASYNC_MASK, mask);366367mask = AR_INTR_SYNC_DEFAULT;368if (ints & HAL_INT_GPIO)369mask |= SM(AH5416(ah)->ah_gpioMask,370AR_INTR_SYNC_MASK_GPIO);371OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, mask);372OS_REG_WRITE(ah, AR_INTR_SYNC_MASK, mask);373}374}375376return omask;377}378379380