1 1.1 alc /* 2 1.1 alc * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 1.1 alc * Copyright (c) 2002-2008 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.3 jmcneill * $Id: ar5416_interrupts.c,v 1.3 2011/11/28 00:30:17 jmcneill 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 "ar5416/ar5416.h" 25 1.1 alc #include "ar5416/ar5416reg.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 ar5416IsInterruptPending(struct ath_hal *ah) 35 1.1 alc { 36 1.1 alc uint32_t isr; 37 1.1 alc /* 38 1.1 alc * Some platforms trigger our ISR before applying power to 39 1.1 alc * the card, so make sure the INTPEND is really 1, not 0xffffffff. 40 1.1 alc */ 41 1.1 alc isr = OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE); 42 1.1 alc if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_MAC_IRQ) != 0) 43 1.1 alc return AH_TRUE; 44 1.1 alc 45 1.1 alc isr = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); 46 1.1 alc if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_SYNC_DEFAULT)) 47 1.1 alc return AH_TRUE; 48 1.1 alc 49 1.1 alc return AH_FALSE; 50 1.1 alc } 51 1.1 alc 52 1.1 alc /* 53 1.1 alc * Reads the Interrupt Status Register value from the NIC, thus deasserting 54 1.1 alc * the interrupt line, and returns both the masked and unmasked mapped ISR 55 1.1 alc * values. The value returned is mapped to abstract the hw-specific bit 56 1.1 alc * locations in the Interrupt Status Register. 57 1.1 alc * 58 1.3 jmcneill * (*masked) is cleared on initial call. 59 1.3 jmcneill * 60 1.1 alc * Returns: A hardware-abstracted bitmap of all non-masked-out 61 1.1 alc * interrupts pending, as well as an unmasked value 62 1.1 alc */ 63 1.1 alc HAL_BOOL 64 1.1 alc ar5416GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) 65 1.1 alc { 66 1.1 alc uint32_t isr, isr0, isr1, sync_cause; 67 1.1 alc 68 1.1 alc /* 69 1.1 alc * Verify there's a mac interrupt and the RTC is on. 70 1.1 alc */ 71 1.1 alc if ((OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) && 72 1.1 alc (OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON) 73 1.1 alc isr = OS_REG_READ(ah, AR_ISR); 74 1.1 alc else 75 1.1 alc isr = 0; 76 1.1 alc sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); 77 1.1 alc sync_cause &= AR_INTR_SYNC_DEFAULT; 78 1.3 jmcneill *masked = 0; 79 1.3 jmcneill if (isr == 0 && sync_cause == 0) 80 1.1 alc return AH_FALSE; 81 1.1 alc 82 1.1 alc if (isr != 0) { 83 1.1 alc struct ath_hal_5212 *ahp = AH5212(ah); 84 1.1 alc uint32_t mask2; 85 1.1 alc 86 1.1 alc mask2 = 0; 87 1.1 alc if (isr & AR_ISR_BCNMISC) { 88 1.1 alc uint32_t isr2 = OS_REG_READ(ah, AR_ISR_S2); 89 1.1 alc if (isr2 & AR_ISR_S2_TIM) 90 1.1 alc mask2 |= HAL_INT_TIM; 91 1.1 alc if (isr2 & AR_ISR_S2_DTIM) 92 1.1 alc mask2 |= HAL_INT_DTIM; 93 1.1 alc if (isr2 & AR_ISR_S2_DTIMSYNC) 94 1.1 alc mask2 |= HAL_INT_DTIMSYNC; 95 1.1 alc if (isr2 & (AR_ISR_S2_CABEND )) 96 1.1 alc mask2 |= HAL_INT_CABEND; 97 1.1 alc if (isr2 & AR_ISR_S2_GTT) 98 1.1 alc mask2 |= HAL_INT_GTT; 99 1.1 alc if (isr2 & AR_ISR_S2_CST) 100 1.1 alc mask2 |= HAL_INT_CST; 101 1.1 alc if (isr2 & AR_ISR_S2_TSFOOR) 102 1.1 alc mask2 |= HAL_INT_TSFOOR; 103 1.1 alc } 104 1.1 alc 105 1.1 alc isr = OS_REG_READ(ah, AR_ISR_RAC); 106 1.1 alc if (isr == 0xffffffff) { 107 1.1 alc *masked = 0; 108 1.2 cegger return AH_FALSE; 109 1.1 alc } 110 1.1 alc 111 1.1 alc *masked = isr & HAL_INT_COMMON; 112 1.1 alc if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) 113 1.1 alc *masked |= HAL_INT_RX; 114 1.1 alc if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL)) { 115 1.1 alc *masked |= HAL_INT_TX; 116 1.1 alc isr0 = OS_REG_READ(ah, AR_ISR_S0_S); 117 1.1 alc ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXOK); 118 1.1 alc ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXDESC); 119 1.1 alc isr1 = OS_REG_READ(ah, AR_ISR_S1_S); 120 1.1 alc ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXERR); 121 1.1 alc ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXEOL); 122 1.1 alc } 123 1.1 alc 124 1.2 cegger if (AR_SREV_MERLIN(ah) || AR_SREV_KITE(ah)) { 125 1.2 cegger uint32_t isr5; 126 1.2 cegger isr5 = OS_REG_READ(ah, AR_ISR_S5_S); 127 1.2 cegger if (isr5 & AR_ISR_S5_TIM_TIMER) 128 1.2 cegger *masked |= HAL_INT_TIM_TIMER; 129 1.2 cegger } 130 1.2 cegger 131 1.1 alc /* Interrupt Mitigation on AR5416 */ 132 1.1 alc #ifdef AR5416_INT_MITIGATION 133 1.1 alc if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) 134 1.1 alc *masked |= HAL_INT_RX; 135 1.1 alc if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) 136 1.1 alc *masked |= HAL_INT_TX; 137 1.1 alc #endif 138 1.1 alc *masked |= mask2; 139 1.1 alc } 140 1.1 alc if (sync_cause != 0) { 141 1.1 alc if (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) { 142 1.1 alc *masked |= HAL_INT_FATAL; 143 1.1 alc } 144 1.1 alc if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { 145 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RADM CPL timeout\n", 146 1.1 alc __func__); 147 1.1 alc OS_REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); 148 1.1 alc OS_REG_WRITE(ah, AR_RC, 0); 149 1.1 alc *masked |= HAL_INT_FATAL; 150 1.1 alc } 151 1.1 alc /* 152 1.1 alc * On fatal errors collect ISR state for debugging. 153 1.1 alc */ 154 1.1 alc if (*masked & HAL_INT_FATAL) { 155 1.1 alc AH_PRIVATE(ah)->ah_fatalState[0] = isr; 156 1.1 alc AH_PRIVATE(ah)->ah_fatalState[1] = sync_cause; 157 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 158 1.1 alc "%s: fatal error, ISR_RAC 0x%x SYNC_CAUSE 0x%x\n", 159 1.1 alc __func__, isr, sync_cause); 160 1.1 alc } 161 1.1 alc 162 1.1 alc OS_REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); 163 1.1 alc /* NB: flush write */ 164 1.1 alc (void) OS_REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); 165 1.1 alc } 166 1.1 alc return AH_TRUE; 167 1.1 alc } 168 1.1 alc 169 1.1 alc /* 170 1.1 alc * Atomically enables NIC interrupts. Interrupts are passed in 171 1.1 alc * via the enumerated bitmask in ints. 172 1.1 alc */ 173 1.1 alc HAL_INT 174 1.1 alc ar5416SetInterrupts(struct ath_hal *ah, HAL_INT ints) 175 1.1 alc { 176 1.1 alc struct ath_hal_5212 *ahp = AH5212(ah); 177 1.1 alc uint32_t omask = ahp->ah_maskReg; 178 1.2 cegger uint32_t mask, mask2; 179 1.1 alc 180 1.1 alc HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: 0x%x => 0x%x\n", 181 1.1 alc __func__, omask, ints); 182 1.1 alc 183 1.1 alc if (omask & HAL_INT_GLOBAL) { 184 1.1 alc HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__); 185 1.1 alc OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); 186 1.1 alc (void) OS_REG_READ(ah, AR_IER); 187 1.1 alc 188 1.1 alc OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); 189 1.1 alc (void) OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE); 190 1.1 alc 191 1.1 alc OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); 192 1.1 alc (void) OS_REG_READ(ah, AR_INTR_SYNC_ENABLE); 193 1.1 alc } 194 1.1 alc 195 1.1 alc mask = ints & HAL_INT_COMMON; 196 1.1 alc mask2 = 0; 197 1.1 alc 198 1.1 alc if (ints & HAL_INT_TX) { 199 1.1 alc if (ahp->ah_txOkInterruptMask) 200 1.1 alc mask |= AR_IMR_TXOK; 201 1.1 alc if (ahp->ah_txErrInterruptMask) 202 1.1 alc mask |= AR_IMR_TXERR; 203 1.1 alc if (ahp->ah_txDescInterruptMask) 204 1.1 alc mask |= AR_IMR_TXDESC; 205 1.1 alc if (ahp->ah_txEolInterruptMask) 206 1.1 alc mask |= AR_IMR_TXEOL; 207 1.1 alc } 208 1.1 alc if (ints & HAL_INT_RX) 209 1.1 alc mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC; 210 1.1 alc #ifdef AR5416_INT_MITIGATION 211 1.1 alc /* 212 1.1 alc * Overwrite default mask if Interrupt mitigation 213 1.1 alc * is specified for AR5416 214 1.1 alc */ 215 1.1 alc mask = ints & HAL_INT_COMMON; 216 1.1 alc if (ints & HAL_INT_TX) 217 1.1 alc mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; 218 1.1 alc if (ints & HAL_INT_RX) 219 1.1 alc mask |= AR_IMR_RXERR | AR_IMR_RXMINTR | AR_IMR_RXINTM; 220 1.1 alc #endif 221 1.1 alc if (ints & (HAL_INT_BMISC)) { 222 1.1 alc mask |= AR_IMR_BCNMISC; 223 1.1 alc if (ints & HAL_INT_TIM) 224 1.1 alc mask2 |= AR_IMR_S2_TIM; 225 1.1 alc if (ints & HAL_INT_DTIM) 226 1.1 alc mask2 |= AR_IMR_S2_DTIM; 227 1.1 alc if (ints & HAL_INT_DTIMSYNC) 228 1.1 alc mask2 |= AR_IMR_S2_DTIMSYNC; 229 1.1 alc if (ints & HAL_INT_CABEND) 230 1.1 alc mask2 |= (AR_IMR_S2_CABEND ); 231 1.1 alc if (ints & HAL_INT_GTT) 232 1.1 alc mask2 |= AR_IMR_S2_GTT; 233 1.1 alc if (ints & HAL_INT_CST) 234 1.1 alc mask2 |= AR_IMR_S2_CST; 235 1.1 alc if (ints & HAL_INT_TSFOOR) 236 1.1 alc mask2 |= AR_IMR_S2_TSFOOR; 237 1.1 alc } 238 1.1 alc 239 1.1 alc /* Write the new IMR and store off our SW copy. */ 240 1.1 alc HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); 241 1.1 alc OS_REG_WRITE(ah, AR_IMR, mask); 242 1.1 alc mask = OS_REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | 243 1.1 alc AR_IMR_S2_DTIM | 244 1.1 alc AR_IMR_S2_DTIMSYNC | 245 1.1 alc AR_IMR_S2_CABEND | 246 1.1 alc AR_IMR_S2_CABTO | 247 1.1 alc AR_IMR_S2_TSFOOR | 248 1.1 alc AR_IMR_S2_GTT | 249 1.1 alc AR_IMR_S2_CST); 250 1.1 alc OS_REG_WRITE(ah, AR_IMR_S2, mask | mask2); 251 1.1 alc 252 1.1 alc ahp->ah_maskReg = ints; 253 1.1 alc 254 1.1 alc /* Re-enable interrupts if they were enabled before. */ 255 1.1 alc if (ints & HAL_INT_GLOBAL) { 256 1.1 alc HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__); 257 1.1 alc OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE); 258 1.1 alc 259 1.1 alc OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, AR_INTR_MAC_IRQ); 260 1.1 alc OS_REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); 261 1.1 alc 262 1.1 alc OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); 263 1.1 alc OS_REG_WRITE(ah, AR_INTR_SYNC_MASK, AR_INTR_SYNC_DEFAULT); 264 1.1 alc } 265 1.1 alc 266 1.1 alc return omask; 267 1.1 alc } 268