1 1.1 alc /* 2 1.1 alc * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 1.1 alc * Copyright (c) 2002-2006 Atheros Communications, Inc. 4 1.1 alc * 5 1.1 alc * Permission to use, copy, modify, and/or distribute this software for any 6 1.1 alc * purpose with or without fee is hereby granted, provided that the above 7 1.1 alc * copyright notice and this permission notice appear in all copies. 8 1.1 alc * 9 1.1 alc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 1.1 alc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 1.1 alc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 1.1 alc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 1.1 alc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 1.1 alc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 1.1 alc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 1.1 alc * 17 1.1 alc * $Id: ar5211_interrupts.c,v 1.1.1.1 2008/12/11 04:46:31 alc Exp $ 18 1.1 alc */ 19 1.1 alc #include "opt_ah.h" 20 1.1 alc 21 1.1 alc #include "ah.h" 22 1.1 alc #include "ah_internal.h" 23 1.1 alc 24 1.1 alc #include "ar5211/ar5211.h" 25 1.1 alc #include "ar5211/ar5211reg.h" 26 1.1 alc 27 1.1 alc /* 28 1.1 alc * Checks to see if an interrupt is pending on our NIC 29 1.1 alc * 30 1.1 alc * Returns: TRUE if an interrupt is pending 31 1.1 alc * FALSE if not 32 1.1 alc */ 33 1.1 alc HAL_BOOL 34 1.1 alc ar5211IsInterruptPending(struct ath_hal *ah) 35 1.1 alc { 36 1.1 alc return OS_REG_READ(ah, AR_INTPEND) != 0; 37 1.1 alc } 38 1.1 alc 39 1.1 alc /* 40 1.1 alc * Reads the Interrupt Status Register value from the NIC, thus deasserting 41 1.1 alc * the interrupt line, and returns both the masked and unmasked mapped ISR 42 1.1 alc * values. The value returned is mapped to abstract the hw-specific bit 43 1.1 alc * locations in the Interrupt Status Register. 44 1.1 alc * 45 1.1 alc * Returns: A hardware-abstracted bitmap of all non-masked-out 46 1.1 alc * interrupts pending, as well as an unmasked value 47 1.1 alc */ 48 1.1 alc HAL_BOOL 49 1.1 alc ar5211GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) 50 1.1 alc { 51 1.1 alc uint32_t isr; 52 1.1 alc 53 1.1 alc isr = OS_REG_READ(ah, AR_ISR_RAC); 54 1.1 alc if (isr == 0xffffffff) { 55 1.1 alc *masked = 0; 56 1.1 alc return AH_FALSE; 57 1.1 alc } 58 1.1 alc 59 1.1 alc *masked = isr & HAL_INT_COMMON; 60 1.1 alc 61 1.1 alc if (isr & AR_ISR_HIUERR) 62 1.1 alc *masked |= HAL_INT_FATAL; 63 1.1 alc if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) 64 1.1 alc *masked |= HAL_INT_RX; 65 1.1 alc if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL)) 66 1.1 alc *masked |= HAL_INT_TX; 67 1.1 alc /* 68 1.1 alc * Receive overrun is usually non-fatal on Oahu/Spirit. 69 1.1 alc * BUT on some parts rx could fail and the chip must be reset. 70 1.1 alc * So we force a hardware reset in all cases. 71 1.1 alc */ 72 1.1 alc if ((isr & AR_ISR_RXORN) && AH_PRIVATE(ah)->ah_rxornIsFatal) { 73 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 74 1.1 alc "%s: receive FIFO overrun interrupt\n", __func__); 75 1.1 alc *masked |= HAL_INT_FATAL; 76 1.1 alc } 77 1.1 alc 78 1.1 alc /* 79 1.1 alc * On fatal errors collect ISR state for debugging. 80 1.1 alc */ 81 1.1 alc if (*masked & HAL_INT_FATAL) { 82 1.1 alc AH_PRIVATE(ah)->ah_fatalState[0] = isr; 83 1.1 alc AH_PRIVATE(ah)->ah_fatalState[1] = OS_REG_READ(ah, AR_ISR_S0_S); 84 1.1 alc AH_PRIVATE(ah)->ah_fatalState[2] = OS_REG_READ(ah, AR_ISR_S1_S); 85 1.1 alc AH_PRIVATE(ah)->ah_fatalState[3] = OS_REG_READ(ah, AR_ISR_S2_S); 86 1.1 alc AH_PRIVATE(ah)->ah_fatalState[4] = OS_REG_READ(ah, AR_ISR_S3_S); 87 1.1 alc AH_PRIVATE(ah)->ah_fatalState[5] = OS_REG_READ(ah, AR_ISR_S4_S); 88 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 89 1.1 alc "%s: fatal error, ISR_RAC=0x%x ISR_S2_S=0x%x\n", 90 1.1 alc __func__, isr, AH_PRIVATE(ah)->ah_fatalState[3]); 91 1.1 alc } 92 1.1 alc return AH_TRUE; 93 1.1 alc } 94 1.1 alc 95 1.1 alc HAL_INT 96 1.1 alc ar5211GetInterrupts(struct ath_hal *ah) 97 1.1 alc { 98 1.1 alc return AH5211(ah)->ah_maskReg; 99 1.1 alc } 100 1.1 alc 101 1.1 alc /* 102 1.1 alc * Atomically enables NIC interrupts. Interrupts are passed in 103 1.1 alc * via the enumerated bitmask in ints. 104 1.1 alc */ 105 1.1 alc HAL_INT 106 1.1 alc ar5211SetInterrupts(struct ath_hal *ah, HAL_INT ints) 107 1.1 alc { 108 1.1 alc struct ath_hal_5211 *ahp = AH5211(ah); 109 1.1 alc uint32_t omask = ahp->ah_maskReg; 110 1.1 alc uint32_t mask; 111 1.1 alc 112 1.1 alc HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: 0x%x => 0x%x\n", 113 1.1 alc __func__, omask, ints); 114 1.1 alc 115 1.1 alc /* 116 1.1 alc * Disable interrupts here before reading & modifying 117 1.1 alc * the mask so that the ISR does not modify the mask 118 1.1 alc * out from under us. 119 1.1 alc */ 120 1.1 alc if (omask & HAL_INT_GLOBAL) { 121 1.1 alc HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__); 122 1.1 alc OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); 123 1.1 alc /* XXX??? */ 124 1.1 alc (void) OS_REG_READ(ah, AR_IER); /* flush write to HW */ 125 1.1 alc } 126 1.1 alc 127 1.1 alc mask = ints & HAL_INT_COMMON; 128 1.1 alc if (ints & HAL_INT_TX) { 129 1.1 alc if (ahp->ah_txOkInterruptMask) 130 1.1 alc mask |= AR_IMR_TXOK; 131 1.1 alc if (ahp->ah_txErrInterruptMask) 132 1.1 alc mask |= AR_IMR_TXERR; 133 1.1 alc if (ahp->ah_txDescInterruptMask) 134 1.1 alc mask |= AR_IMR_TXDESC; 135 1.1 alc if (ahp->ah_txEolInterruptMask) 136 1.1 alc mask |= AR_IMR_TXEOL; 137 1.1 alc } 138 1.1 alc if (ints & HAL_INT_RX) 139 1.1 alc mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC; 140 1.1 alc if (ints & HAL_INT_FATAL) { 141 1.1 alc /* 142 1.1 alc * NB: ar5212Reset sets MCABT+SSERR+DPERR in AR_IMR_S2 143 1.1 alc * so enabling HIUERR enables delivery. 144 1.1 alc */ 145 1.1 alc mask |= AR_IMR_HIUERR; 146 1.1 alc } 147 1.1 alc 148 1.1 alc /* Write the new IMR and store off our SW copy. */ 149 1.1 alc HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); 150 1.1 alc OS_REG_WRITE(ah, AR_IMR, mask); 151 1.1 alc ahp->ah_maskReg = ints; 152 1.1 alc 153 1.1 alc /* Re-enable interrupts as appropriate. */ 154 1.1 alc if (ints & HAL_INT_GLOBAL) { 155 1.1 alc HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__); 156 1.1 alc OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE); 157 1.1 alc } 158 1.1 alc 159 1.1 alc return omask; 160 1.1 alc } 161