ar9300_interrupts.c revision 269146
1250003Sadrian/* 2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc. 3250003Sadrian * 4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any 5250003Sadrian * purpose with or without fee is hereby granted, provided that the above 6250003Sadrian * copyright notice and this permission notice appear in all copies. 7250003Sadrian * 8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14250003Sadrian * PERFORMANCE OF THIS SOFTWARE. 15250003Sadrian */ 16250003Sadrian 17250003Sadrian#include "opt_ah.h" 18250003Sadrian 19250003Sadrian#include "ah.h" 20250003Sadrian#include "ah_internal.h" 21250003Sadrian 22250003Sadrian#include "ar9300/ar9300.h" 23250003Sadrian#include "ar9300/ar9300reg.h" 24250003Sadrian#include "ar9300/ar9300phy.h" 25250003Sadrian 26250003Sadrian/* 27250003Sadrian * Checks to see if an interrupt is pending on our NIC 28250003Sadrian * 29250003Sadrian * Returns: TRUE if an interrupt is pending 30250003Sadrian * FALSE if not 31250003Sadrian */ 32250003SadrianHAL_BOOL 33250003Sadrianar9300_is_interrupt_pending(struct ath_hal *ah) 34250003Sadrian{ 35250003Sadrian u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT; 36250003Sadrian u_int32_t host_isr; 37250003Sadrian 38250003Sadrian /* 39250003Sadrian * Some platforms trigger our ISR before applying power to 40250003Sadrian * the card, so make sure. 41250003Sadrian */ 42250003Sadrian host_isr = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE)); 43250003Sadrian if ((host_isr & AR_INTR_ASYNC_USED) && (host_isr != AR_INTR_SPURIOUS)) { 44250003Sadrian return AH_TRUE; 45250003Sadrian } 46250003Sadrian 47250003Sadrian host_isr = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)); 48250003Sadrian if (AR_SREV_POSEIDON(ah)) { 49250003Sadrian sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR; 50250003Sadrian } 51250003Sadrian else if (AR_SREV_WASP(ah)) { 52250003Sadrian sync_en_def = AR9340_INTR_SYNC_DEFAULT; 53250003Sadrian } 54250003Sadrian 55250003Sadrian if ((host_isr & (sync_en_def | AR_INTR_SYNC_MASK_GPIO)) && 56250003Sadrian (host_isr != AR_INTR_SPURIOUS)) { 57250003Sadrian return AH_TRUE; 58250003Sadrian } 59250003Sadrian 60250003Sadrian return AH_FALSE; 61250003Sadrian} 62250003Sadrian 63250003Sadrian/* 64250003Sadrian * Reads the Interrupt Status Register value from the NIC, thus deasserting 65250003Sadrian * the interrupt line, and returns both the masked and unmasked mapped ISR 66250003Sadrian * values. The value returned is mapped to abstract the hw-specific bit 67250003Sadrian * locations in the Interrupt Status Register. 68250003Sadrian * 69250003Sadrian * Returns: A hardware-abstracted bitmap of all non-masked-out 70250003Sadrian * interrupts pending, as well as an unmasked value 71250003Sadrian */ 72250003Sadrian#define MAP_ISR_S2_HAL_CST 6 /* Carrier sense timeout */ 73250003Sadrian#define MAP_ISR_S2_HAL_GTT 6 /* Global transmit timeout */ 74250003Sadrian#define MAP_ISR_S2_HAL_TIM 3 /* TIM */ 75250003Sadrian#define MAP_ISR_S2_HAL_CABEND 0 /* CABEND */ 76250003Sadrian#define MAP_ISR_S2_HAL_DTIMSYNC 7 /* DTIMSYNC */ 77250003Sadrian#define MAP_ISR_S2_HAL_DTIM 7 /* DTIM */ 78250003Sadrian#define MAP_ISR_S2_HAL_TSFOOR 4 /* Rx TSF out of range */ 79250003Sadrian#define MAP_ISR_S2_HAL_BBPANIC 6 /* Panic watchdog IRQ from BB */ 80250003SadrianHAL_BOOL 81250003Sadrianar9300_get_pending_interrupts( 82250003Sadrian struct ath_hal *ah, 83250003Sadrian HAL_INT *masked, 84250003Sadrian HAL_INT_TYPE type, 85250003Sadrian u_int8_t msi, 86250003Sadrian HAL_BOOL nortc) 87250003Sadrian{ 88250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 89250003Sadrian HAL_BOOL ret_val = AH_TRUE; 90250003Sadrian u_int32_t isr = 0; 91250003Sadrian u_int32_t mask2 = 0; 92250003Sadrian u_int32_t sync_cause = 0; 93250003Sadrian u_int32_t async_cause; 94250003Sadrian u_int32_t msi_pend_addr_mask = 0; 95250003Sadrian u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT; 96250003Sadrian HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 97250003Sadrian 98250003Sadrian *masked = 0; 99250003Sadrian 100250003Sadrian if (!nortc) { 101250003Sadrian if (HAL_INT_MSI == type) { 102250003Sadrian if (msi == HAL_MSIVEC_RXHP) { 103250003Sadrian OS_REG_WRITE(ah, AR_ISR, AR_ISR_HP_RXOK); 104250003Sadrian *masked = HAL_INT_RXHP; 105250003Sadrian goto end; 106250003Sadrian } else if (msi == HAL_MSIVEC_RXLP) { 107250003Sadrian OS_REG_WRITE(ah, AR_ISR, 108250003Sadrian (AR_ISR_LP_RXOK | AR_ISR_RXMINTR | AR_ISR_RXINTM)); 109250003Sadrian *masked = HAL_INT_RXLP; 110250003Sadrian goto end; 111250003Sadrian } else if (msi == HAL_MSIVEC_TX) { 112250003Sadrian OS_REG_WRITE(ah, AR_ISR, AR_ISR_TXOK); 113250003Sadrian *masked = HAL_INT_TX; 114250003Sadrian goto end; 115250003Sadrian } else if (msi == HAL_MSIVEC_MISC) { 116250003Sadrian /* 117250003Sadrian * For the misc MSI event fall through and determine the cause. 118250003Sadrian */ 119250003Sadrian } 120250003Sadrian } 121250003Sadrian } 122250003Sadrian 123250003Sadrian /* Make sure mac interrupt is pending in async interrupt cause register */ 124250003Sadrian async_cause = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE)); 125250003Sadrian if (async_cause & AR_INTR_ASYNC_USED) { 126250003Sadrian /* 127250003Sadrian * RTC may not be on since it runs on a slow 32khz clock 128250003Sadrian * so check its status to be sure 129250003Sadrian */ 130250003Sadrian if (!nortc && 131250003Sadrian (OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == 132250003Sadrian AR_RTC_STATUS_ON) 133250003Sadrian { 134250003Sadrian isr = OS_REG_READ(ah, AR_ISR); 135250003Sadrian } 136250003Sadrian } 137250003Sadrian 138250003Sadrian if (AR_SREV_POSEIDON(ah)) { 139250003Sadrian sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR; 140250003Sadrian } 141250003Sadrian else if (AR_SREV_WASP(ah)) { 142250003Sadrian sync_en_def = AR9340_INTR_SYNC_DEFAULT; 143250003Sadrian } 144250003Sadrian 145269146Sadrian /* Store away the async and sync cause registers */ 146269146Sadrian /* XXX Do this before the filtering done below */ 147269146Sadrian#ifdef AH_INTERRUPT_DEBUGGING 148269146Sadrian ah->ah_intrstate[0] = OS_REG_READ(ah, AR_ISR); 149269146Sadrian ah->ah_intrstate[1] = OS_REG_READ(ah, AR_ISR_S0); 150269146Sadrian ah->ah_intrstate[2] = OS_REG_READ(ah, AR_ISR_S1); 151269146Sadrian ah->ah_intrstate[3] = OS_REG_READ(ah, AR_ISR_S2); 152269146Sadrian ah->ah_intrstate[4] = OS_REG_READ(ah, AR_ISR_S3); 153269146Sadrian ah->ah_intrstate[5] = OS_REG_READ(ah, AR_ISR_S4); 154269146Sadrian ah->ah_intrstate[6] = OS_REG_READ(ah, AR_ISR_S5); 155269146Sadrian 156269146Sadrian /* XXX double reading? */ 157269146Sadrian ah->ah_syncstate = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)); 158269146Sadrian#endif 159269146Sadrian 160250003Sadrian sync_cause = 161250003Sadrian OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)) & 162250003Sadrian (sync_en_def | AR_INTR_SYNC_MASK_GPIO); 163250003Sadrian 164250003Sadrian if (!isr && !sync_cause && !async_cause) { 165250003Sadrian ret_val = AH_FALSE; 166250003Sadrian goto end; 167250003Sadrian } 168250003Sadrian 169250008Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 170250008Sadrian "%s: isr=0x%x, sync_cause=0x%x, async_cause=0x%x\n", 171250008Sadrian __func__, 172250008Sadrian isr, 173250008Sadrian sync_cause, 174250008Sadrian async_cause); 175250008Sadrian 176250003Sadrian if (isr) { 177250003Sadrian if (isr & AR_ISR_BCNMISC) { 178250003Sadrian u_int32_t isr2; 179250003Sadrian isr2 = OS_REG_READ(ah, AR_ISR_S2); 180250003Sadrian 181250003Sadrian /* Translate ISR bits to HAL values */ 182250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_TIM) >> MAP_ISR_S2_HAL_TIM); 183250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_DTIM) >> MAP_ISR_S2_HAL_DTIM); 184250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_DTIMSYNC) >> MAP_ISR_S2_HAL_DTIMSYNC); 185250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_CABEND) >> MAP_ISR_S2_HAL_CABEND); 186250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_GTT) << MAP_ISR_S2_HAL_GTT); 187250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_CST) << MAP_ISR_S2_HAL_CST); 188250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >> MAP_ISR_S2_HAL_TSFOOR); 189250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_BBPANIC) >> MAP_ISR_S2_HAL_BBPANIC); 190250003Sadrian 191250008Sadrian if (!p_cap->halIsrRacSupport) { 192250003Sadrian /* 193250003Sadrian * EV61133 (missing interrupts due to ISR_RAC): 194250003Sadrian * If not using ISR_RAC, clear interrupts by writing to ISR_S2. 195250003Sadrian * This avoids a race condition where a new BCNMISC interrupt 196250003Sadrian * could come in between reading the ISR and clearing the 197250003Sadrian * interrupt via the primary ISR. We therefore clear the 198250003Sadrian * interrupt via the secondary, which avoids this race. 199250003Sadrian */ 200250003Sadrian OS_REG_WRITE(ah, AR_ISR_S2, isr2); 201250003Sadrian isr &= ~AR_ISR_BCNMISC; 202250003Sadrian } 203250003Sadrian } 204250003Sadrian 205250003Sadrian /* Use AR_ISR_RAC only if chip supports it. 206250003Sadrian * See EV61133 (missing interrupts due to ISR_RAC) 207250003Sadrian */ 208250008Sadrian if (p_cap->halIsrRacSupport) { 209250003Sadrian isr = OS_REG_READ(ah, AR_ISR_RAC); 210250003Sadrian } 211250003Sadrian if (isr == 0xffffffff) { 212250003Sadrian *masked = 0; 213250003Sadrian ret_val = AH_FALSE; 214250003Sadrian goto end; 215250003Sadrian } 216250003Sadrian 217250003Sadrian *masked = isr & HAL_INT_COMMON; 218250003Sadrian 219250003Sadrian /* 220250003Sadrian * When interrupt mitigation is switched on, we fake a normal RX or TX 221250003Sadrian * interrupt when we received a mitigated interrupt. This way, the upper 222250003Sadrian * layer do not need to know about feature. 223250003Sadrian */ 224250003Sadrian if (ahp->ah_intr_mitigation_rx) { 225250003Sadrian /* Only Rx interrupt mitigation. No Tx intr. mitigation. */ 226250003Sadrian if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) { 227250003Sadrian *masked |= HAL_INT_RXLP; 228250003Sadrian } 229250003Sadrian } 230250003Sadrian if (ahp->ah_intr_mitigation_tx) { 231250003Sadrian if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) { 232250003Sadrian *masked |= HAL_INT_TX; 233250003Sadrian } 234250003Sadrian } 235250003Sadrian 236250003Sadrian if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR)) { 237250003Sadrian *masked |= HAL_INT_RXLP; 238250003Sadrian } 239250003Sadrian if (isr & AR_ISR_HP_RXOK) { 240250003Sadrian *masked |= HAL_INT_RXHP; 241250003Sadrian } 242250003Sadrian if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) { 243250003Sadrian *masked |= HAL_INT_TX; 244250003Sadrian 245250008Sadrian if (!p_cap->halIsrRacSupport) { 246250003Sadrian u_int32_t s0, s1; 247250003Sadrian /* 248250003Sadrian * EV61133 (missing interrupts due to ISR_RAC): 249250003Sadrian * If not using ISR_RAC, clear interrupts by writing to 250250003Sadrian * ISR_S0/S1. 251250003Sadrian * This avoids a race condition where a new interrupt 252250003Sadrian * could come in between reading the ISR and clearing the 253250003Sadrian * interrupt via the primary ISR. We therefore clear the 254250003Sadrian * interrupt via the secondary, which avoids this race. 255250003Sadrian */ 256250003Sadrian s0 = OS_REG_READ(ah, AR_ISR_S0); 257250003Sadrian OS_REG_WRITE(ah, AR_ISR_S0, s0); 258250003Sadrian s1 = OS_REG_READ(ah, AR_ISR_S1); 259250003Sadrian OS_REG_WRITE(ah, AR_ISR_S1, s1); 260250003Sadrian 261250003Sadrian isr &= ~(AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL); 262250003Sadrian } 263250003Sadrian } 264250003Sadrian 265250003Sadrian /* 266250003Sadrian * Do not treat receive overflows as fatal for owl. 267250003Sadrian */ 268250003Sadrian if (isr & AR_ISR_RXORN) { 269250003Sadrian#if __PKT_SERIOUS_ERRORS__ 270250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 271250003Sadrian "%s: receive FIFO overrun interrupt\n", __func__); 272250003Sadrian#endif 273250003Sadrian } 274250003Sadrian 275250003Sadrian#if 0 276250003Sadrian /* XXX Verify if this is fixed for Osprey */ 277250008Sadrian if (!p_cap->halAutoSleepSupport) { 278250003Sadrian u_int32_t isr5 = OS_REG_READ(ah, AR_ISR_S5_S); 279250003Sadrian if (isr5 & AR_ISR_S5_TIM_TIMER) { 280250003Sadrian *masked |= HAL_INT_TIM_TIMER; 281250003Sadrian } 282250003Sadrian } 283250003Sadrian#endif 284250003Sadrian if (isr & AR_ISR_GENTMR) { 285250003Sadrian u_int32_t s5; 286250003Sadrian 287250008Sadrian if (p_cap->halIsrRacSupport) { 288250003Sadrian /* Use secondary shadow registers if using ISR_RAC */ 289250003Sadrian s5 = OS_REG_READ(ah, AR_ISR_S5_S); 290250003Sadrian } else { 291250003Sadrian s5 = OS_REG_READ(ah, AR_ISR_S5); 292250003Sadrian } 293250003Sadrian if (isr & AR_ISR_GENTMR) { 294250003Sadrian 295250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 296250003Sadrian "%s: GENTIMER, ISR_RAC=0x%x ISR_S2_S=0x%x\n", __func__, 297250003Sadrian isr, s5); 298250003Sadrian ahp->ah_intr_gen_timer_trigger = 299250003Sadrian MS(s5, AR_ISR_S5_GENTIMER_TRIG); 300250003Sadrian ahp->ah_intr_gen_timer_thresh = 301250003Sadrian MS(s5, AR_ISR_S5_GENTIMER_THRESH); 302250003Sadrian if (ahp->ah_intr_gen_timer_trigger) { 303250003Sadrian *masked |= HAL_INT_GENTIMER; 304250003Sadrian } 305250003Sadrian } 306250008Sadrian if (!p_cap->halIsrRacSupport) { 307250003Sadrian /* 308250003Sadrian * EV61133 (missing interrupts due to ISR_RAC): 309250003Sadrian * If not using ISR_RAC, clear interrupts by writing to ISR_S5. 310250003Sadrian * This avoids a race condition where a new interrupt 311250003Sadrian * could come in between reading the ISR and clearing the 312250003Sadrian * interrupt via the primary ISR. We therefore clear the 313250003Sadrian * interrupt via the secondary, which avoids this race. 314250003Sadrian */ 315250003Sadrian OS_REG_WRITE(ah, AR_ISR_S5, s5); 316250003Sadrian isr &= ~AR_ISR_GENTMR; 317250003Sadrian } 318250003Sadrian } 319250003Sadrian 320250003Sadrian *masked |= mask2; 321250003Sadrian 322250008Sadrian if (!p_cap->halIsrRacSupport) { 323250003Sadrian /* 324250003Sadrian * EV61133 (missing interrupts due to ISR_RAC): 325250003Sadrian * If not using ISR_RAC, clear the interrupts we've read by 326250003Sadrian * writing back ones in these locations to the primary ISR 327250003Sadrian * (except for interrupts that have a secondary isr register - 328250003Sadrian * see above). 329250003Sadrian */ 330250003Sadrian OS_REG_WRITE(ah, AR_ISR, isr); 331250003Sadrian 332250003Sadrian /* Flush prior write */ 333250003Sadrian (void) OS_REG_READ(ah, AR_ISR); 334250003Sadrian } 335250003Sadrian 336250003Sadrian#ifdef AH_SUPPORT_AR9300 337250003Sadrian if (*masked & HAL_INT_BBPANIC) { 338250003Sadrian ar9300_handle_bb_panic(ah); 339250003Sadrian } 340250003Sadrian#endif 341250003Sadrian } 342250003Sadrian 343250003Sadrian if (async_cause) { 344250003Sadrian if (nortc) { 345250003Sadrian OS_REG_WRITE(ah, 346250003Sadrian AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE_CLR), async_cause); 347250003Sadrian /* Flush prior write */ 348250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE_CLR)); 349250003Sadrian } else { 350250003Sadrian#ifdef ATH_GPIO_USE_ASYNC_CAUSE 351250003Sadrian if (async_cause & AR_INTR_ASYNC_CAUSE_GPIO) { 352250003Sadrian ahp->ah_gpio_cause = (async_cause & AR_INTR_ASYNC_CAUSE_GPIO) >> 353250003Sadrian AR_INTR_ASYNC_ENABLE_GPIO_S; 354250003Sadrian *masked |= HAL_INT_GPIO; 355250003Sadrian } 356250003Sadrian#endif 357250003Sadrian } 358250003Sadrian 359250003Sadrian#if ATH_SUPPORT_MCI 360250003Sadrian if ((async_cause & AR_INTR_ASYNC_CAUSE_MCI) && 361250008Sadrian p_cap->halMciSupport) 362250003Sadrian { 363250003Sadrian u_int32_t int_raw, int_rx_msg; 364250003Sadrian 365250003Sadrian int_rx_msg = OS_REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); 366250003Sadrian int_raw = OS_REG_READ(ah, AR_MCI_INTERRUPT_RAW); 367250003Sadrian 368250003Sadrian if ((int_raw == 0xdeadbeef) || (int_rx_msg == 0xdeadbeef)) 369250003Sadrian { 370250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 371250003Sadrian "(MCI) Get 0xdeadbeef during MCI int processing" 372250003Sadrian "new int_raw=0x%08x, new rx_msg_raw=0x%08x, " 373250003Sadrian "int_raw=0x%08x, rx_msg_raw=0x%08x\n", 374250003Sadrian int_raw, int_rx_msg, ahp->ah_mci_int_raw, 375250003Sadrian ahp->ah_mci_int_rx_msg); 376250003Sadrian } 377250003Sadrian else { 378250003Sadrian if (ahp->ah_mci_int_raw || ahp->ah_mci_int_rx_msg) { 379250003Sadrian ahp->ah_mci_int_rx_msg |= int_rx_msg; 380250003Sadrian ahp->ah_mci_int_raw |= int_raw; 381250003Sadrian } 382250003Sadrian else { 383250003Sadrian ahp->ah_mci_int_rx_msg = int_rx_msg; 384250003Sadrian ahp->ah_mci_int_raw = int_raw; 385250003Sadrian } 386250003Sadrian 387250003Sadrian *masked |= HAL_INT_MCI; 388250003Sadrian ahp->ah_mci_rx_status = OS_REG_READ(ah, AR_MCI_RX_STATUS); 389250003Sadrian if (int_rx_msg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) { 390250003Sadrian ahp->ah_mci_cont_status = 391250003Sadrian OS_REG_READ(ah, AR_MCI_CONT_STATUS); 392250003Sadrian } 393250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 394250003Sadrian int_rx_msg); 395250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, int_raw); 396250003Sadrian 397250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s:AR_INTR_SYNC_MCI\n", __func__); 398250003Sadrian } 399250003Sadrian } 400250003Sadrian#endif 401250003Sadrian } 402250003Sadrian 403250003Sadrian if (sync_cause) { 404250003Sadrian int host1_fatal, host1_perr, radm_cpl_timeout, local_timeout; 405250003Sadrian 406250003Sadrian host1_fatal = AR_SREV_WASP(ah) ? 407250003Sadrian AR9340_INTR_SYNC_HOST1_FATAL : AR9300_INTR_SYNC_HOST1_FATAL; 408250003Sadrian host1_perr = AR_SREV_WASP(ah) ? 409250003Sadrian AR9340_INTR_SYNC_HOST1_PERR : AR9300_INTR_SYNC_HOST1_PERR; 410250003Sadrian radm_cpl_timeout = AR_SREV_WASP(ah) ? 411250003Sadrian 0x0 : AR9300_INTR_SYNC_RADM_CPL_TIMEOUT; 412250003Sadrian local_timeout = AR_SREV_WASP(ah) ? 413250003Sadrian AR9340_INTR_SYNC_LOCAL_TIMEOUT : AR9300_INTR_SYNC_LOCAL_TIMEOUT; 414250003Sadrian 415250003Sadrian if (sync_cause & host1_fatal) { 416250003Sadrian#if __PKT_SERIOUS_ERRORS__ 417250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 418250003Sadrian "%s: received PCI FATAL interrupt\n", __func__); 419250003Sadrian#endif 420250003Sadrian *masked |= HAL_INT_FATAL; /* Set FATAL INT flag here;*/ 421250003Sadrian } 422250003Sadrian if (sync_cause & host1_perr) { 423250003Sadrian#if __PKT_SERIOUS_ERRORS__ 424250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 425250003Sadrian "%s: received PCI PERR interrupt\n", __func__); 426250003Sadrian#endif 427250003Sadrian } 428250003Sadrian 429250003Sadrian if (sync_cause & radm_cpl_timeout) { 430250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 431250003Sadrian "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n", 432250003Sadrian __func__); 433250003Sadrian 434250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF); 435250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), 0); 436250003Sadrian *masked |= HAL_INT_FATAL; 437250003Sadrian } 438250003Sadrian if (sync_cause & local_timeout) { 439250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 440250003Sadrian "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n", 441250003Sadrian __func__); 442250003Sadrian } 443250003Sadrian 444250003Sadrian#ifndef ATH_GPIO_USE_ASYNC_CAUSE 445250003Sadrian if (sync_cause & AR_INTR_SYNC_MASK_GPIO) { 446250003Sadrian ahp->ah_gpio_cause = (sync_cause & AR_INTR_SYNC_MASK_GPIO) >> 447250003Sadrian AR_INTR_SYNC_ENABLE_GPIO_S; 448250003Sadrian *masked |= HAL_INT_GPIO; 449250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 450250003Sadrian "%s: AR_INTR_SYNC_GPIO\n", __func__); 451250003Sadrian } 452250003Sadrian#endif 453250003Sadrian 454250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR), sync_cause); 455250003Sadrian /* Flush prior write */ 456250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR)); 457250003Sadrian } 458250003Sadrian 459250003Sadrianend: 460250003Sadrian if (HAL_INT_MSI == type) { 461250003Sadrian /* 462250003Sadrian * WAR for Bug EV#75887 463250003Sadrian * In normal case, SW read HOST_INTF_PCIE_MSI (0x40A4) and write 464250003Sadrian * into ah_msi_reg. Then use value of ah_msi_reg to set bit#25 465250003Sadrian * when want to enable HW write the cfg_msi_pending. 466250003Sadrian * Sometimes, driver get MSI interrupt before read 0x40a4 and 467250003Sadrian * ah_msi_reg is initialization value (0x0). 468250003Sadrian * We don't know why "MSI interrupt earlier than driver read" now... 469250003Sadrian */ 470250003Sadrian if (!ahp->ah_msi_reg) { 471250003Sadrian ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI)); 472250003Sadrian } 473250003Sadrian if (AR_SREV_POSEIDON(ah)) { 474250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; 475250003Sadrian } else { 476250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR; 477250003Sadrian } 478250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI), 479250003Sadrian ((ahp->ah_msi_reg | AR_PCIE_MSI_ENABLE) & msi_pend_addr_mask)); 480250003Sadrian 481250003Sadrian } 482250003Sadrian 483250003Sadrian return ret_val; 484250003Sadrian} 485250003Sadrian 486250003SadrianHAL_INT 487250003Sadrianar9300_get_interrupts(struct ath_hal *ah) 488250003Sadrian{ 489250003Sadrian return AH9300(ah)->ah_mask_reg; 490250003Sadrian} 491250003Sadrian 492250003Sadrian/* 493250003Sadrian * Atomically enables NIC interrupts. Interrupts are passed in 494250003Sadrian * via the enumerated bitmask in ints. 495250003Sadrian */ 496250003SadrianHAL_INT 497250003Sadrianar9300_set_interrupts(struct ath_hal *ah, HAL_INT ints, HAL_BOOL nortc) 498250003Sadrian{ 499250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 500250003Sadrian u_int32_t omask = ahp->ah_mask_reg; 501250003Sadrian u_int32_t mask, mask2, msi_mask = 0; 502250003Sadrian u_int32_t msi_pend_addr_mask = 0; 503250003Sadrian u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT; 504250003Sadrian HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 505250003Sadrian 506250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 507250003Sadrian "%s: 0x%x => 0x%x\n", __func__, omask, ints); 508250003Sadrian 509250003Sadrian if (omask & HAL_INT_GLOBAL) { 510250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__); 511250003Sadrian 512250008Sadrian if (ah->ah_config.ath_hal_enable_msi) { 513250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0); 514250003Sadrian /* flush write to HW */ 515250003Sadrian (void)OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE)); 516250003Sadrian } 517250003Sadrian 518250003Sadrian if (!nortc) { 519250003Sadrian OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); 520250003Sadrian (void) OS_REG_READ(ah, AR_IER); /* flush write to HW */ 521250003Sadrian } 522250003Sadrian 523250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0); 524250003Sadrian /* flush write to HW */ 525250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE)); 526250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE), 0); 527250003Sadrian /* flush write to HW */ 528250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE)); 529250003Sadrian } 530250003Sadrian 531250003Sadrian if (!nortc) { 532250003Sadrian /* reference count for global IER */ 533250003Sadrian if (ints & HAL_INT_GLOBAL) { 534250003Sadrian#ifdef AH_DEBUG 535250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 536250003Sadrian "%s: Request HAL_INT_GLOBAL ENABLED\n", __func__); 537250008Sadrian#if 0 538250003Sadrian if (OS_ATOMIC_READ(&ahp->ah_ier_ref_count) == 0) { 539250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 540250003Sadrian "%s: WARNING: ah_ier_ref_count is 0 " 541250003Sadrian "and attempting to enable IER\n", 542250003Sadrian __func__); 543250003Sadrian } 544250003Sadrian#endif 545250008Sadrian#endif 546250008Sadrian#if 0 547250003Sadrian if (OS_ATOMIC_READ(&ahp->ah_ier_ref_count) > 0) { 548250003Sadrian OS_ATOMIC_DEC(&ahp->ah_ier_ref_count); 549250003Sadrian } 550250008Sadrian#endif 551250003Sadrian } else { 552250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 553250003Sadrian "%s: Request HAL_INT_GLOBAL DISABLED\n", __func__); 554250003Sadrian OS_ATOMIC_INC(&ahp->ah_ier_ref_count); 555250003Sadrian } 556250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 557250003Sadrian "%s: ah_ier_ref_count = %d\n", __func__, ahp->ah_ier_ref_count); 558250003Sadrian 559250003Sadrian mask = ints & HAL_INT_COMMON; 560250003Sadrian mask2 = 0; 561250003Sadrian msi_mask = 0; 562250003Sadrian 563250003Sadrian if (ints & HAL_INT_TX) { 564250003Sadrian if (ahp->ah_intr_mitigation_tx) { 565250003Sadrian mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; 566250003Sadrian } else if (ahp->ah_tx_ok_interrupt_mask) { 567250003Sadrian mask |= AR_IMR_TXOK; 568250003Sadrian } 569250003Sadrian msi_mask |= AR_INTR_PRIO_TX; 570250003Sadrian if (ahp->ah_tx_err_interrupt_mask) { 571250003Sadrian mask |= AR_IMR_TXERR; 572250003Sadrian } 573250003Sadrian if (ahp->ah_tx_eol_interrupt_mask) { 574250003Sadrian mask |= AR_IMR_TXEOL; 575250003Sadrian } 576250003Sadrian } 577250003Sadrian if (ints & HAL_INT_RX) { 578250003Sadrian mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP; 579250003Sadrian if (ahp->ah_intr_mitigation_rx) { 580250003Sadrian mask &= ~(AR_IMR_RXOK_LP); 581250003Sadrian mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; 582250003Sadrian } else { 583250003Sadrian mask |= AR_IMR_RXOK_LP; 584250003Sadrian } 585250003Sadrian msi_mask |= AR_INTR_PRIO_RXLP | AR_INTR_PRIO_RXHP; 586250008Sadrian if (! p_cap->halAutoSleepSupport) { 587250003Sadrian mask |= AR_IMR_GENTMR; 588250003Sadrian } 589250003Sadrian } 590250003Sadrian 591250003Sadrian if (ints & (HAL_INT_BMISC)) { 592250003Sadrian mask |= AR_IMR_BCNMISC; 593250003Sadrian if (ints & HAL_INT_TIM) { 594250003Sadrian mask2 |= AR_IMR_S2_TIM; 595250003Sadrian } 596250003Sadrian if (ints & HAL_INT_DTIM) { 597250003Sadrian mask2 |= AR_IMR_S2_DTIM; 598250003Sadrian } 599250003Sadrian if (ints & HAL_INT_DTIMSYNC) { 600250003Sadrian mask2 |= AR_IMR_S2_DTIMSYNC; 601250003Sadrian } 602250003Sadrian if (ints & HAL_INT_CABEND) { 603250003Sadrian mask2 |= (AR_IMR_S2_CABEND); 604250003Sadrian } 605250003Sadrian if (ints & HAL_INT_TSFOOR) { 606250003Sadrian mask2 |= AR_IMR_S2_TSFOOR; 607250003Sadrian } 608250003Sadrian } 609250003Sadrian 610250003Sadrian if (ints & (HAL_INT_GTT | HAL_INT_CST)) { 611250003Sadrian mask |= AR_IMR_BCNMISC; 612250003Sadrian if (ints & HAL_INT_GTT) { 613250003Sadrian mask2 |= AR_IMR_S2_GTT; 614250003Sadrian } 615250003Sadrian if (ints & HAL_INT_CST) { 616250003Sadrian mask2 |= AR_IMR_S2_CST; 617250003Sadrian } 618250003Sadrian } 619250003Sadrian 620250003Sadrian if (ints & HAL_INT_BBPANIC) { 621250003Sadrian /* EV92527 - MAC secondary interrupt must enable AR_IMR_BCNMISC */ 622250003Sadrian mask |= AR_IMR_BCNMISC; 623250003Sadrian mask2 |= AR_IMR_S2_BBPANIC; 624250003Sadrian } 625250003Sadrian 626250003Sadrian if (ints & HAL_INT_GENTIMER) { 627250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 628250003Sadrian "%s: enabling gen timer\n", __func__); 629250003Sadrian mask |= AR_IMR_GENTMR; 630250003Sadrian } 631250003Sadrian 632250003Sadrian /* Write the new IMR and store off our SW copy. */ 633250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); 634250003Sadrian OS_REG_WRITE(ah, AR_IMR, mask); 635250003Sadrian ahp->ah_mask2Reg &= ~(AR_IMR_S2_TIM | 636250003Sadrian AR_IMR_S2_DTIM | 637250003Sadrian AR_IMR_S2_DTIMSYNC | 638250003Sadrian AR_IMR_S2_CABEND | 639250003Sadrian AR_IMR_S2_CABTO | 640250003Sadrian AR_IMR_S2_TSFOOR | 641250003Sadrian AR_IMR_S2_GTT | 642250003Sadrian AR_IMR_S2_CST | 643250003Sadrian AR_IMR_S2_BBPANIC); 644250003Sadrian ahp->ah_mask2Reg |= mask2; 645250003Sadrian OS_REG_WRITE(ah, AR_IMR_S2, ahp->ah_mask2Reg ); 646250003Sadrian ahp->ah_mask_reg = ints; 647250003Sadrian 648250008Sadrian if (! p_cap->halAutoSleepSupport) { 649250003Sadrian if (ints & HAL_INT_TIM_TIMER) { 650250003Sadrian OS_REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); 651250003Sadrian } 652250003Sadrian else { 653250003Sadrian OS_REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); 654250003Sadrian } 655250003Sadrian } 656250003Sadrian } 657250003Sadrian 658250003Sadrian /* Re-enable interrupts if they were enabled before. */ 659250003Sadrian#if HAL_INTR_REFCOUNT_DISABLE 660250003Sadrian if ((ints & HAL_INT_GLOBAL)) { 661250003Sadrian#else 662250003Sadrian if ((ints & HAL_INT_GLOBAL) && (OS_ATOMIC_READ(&ahp->ah_ier_ref_count) == 0)) { 663250003Sadrian#endif 664250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__); 665250003Sadrian 666250003Sadrian if (!nortc) { 667250003Sadrian OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE); 668250003Sadrian } 669250003Sadrian 670250003Sadrian mask = AR_INTR_MAC_IRQ; 671250003Sadrian#ifdef ATH_GPIO_USE_ASYNC_CAUSE 672250003Sadrian if (ints & HAL_INT_GPIO) { 673250003Sadrian if (ahp->ah_gpio_mask) { 674250003Sadrian mask |= SM(ahp->ah_gpio_mask, AR_INTR_ASYNC_MASK_GPIO); 675250003Sadrian } 676250003Sadrian } 677250003Sadrian#endif 678250003Sadrian 679250003Sadrian#if ATH_SUPPORT_MCI 680250003Sadrian if (ints & HAL_INT_MCI) { 681250003Sadrian mask |= AR_INTR_ASYNC_MASK_MCI; 682250003Sadrian } 683250003Sadrian#endif 684250003Sadrian 685250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE), mask); 686250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK), mask); 687250003Sadrian 688250008Sadrian if (ah->ah_config.ath_hal_enable_msi) { 689250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 690250003Sadrian msi_mask); 691250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 692250003Sadrian msi_mask); 693250003Sadrian if (AR_SREV_POSEIDON(ah)) { 694250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; 695250003Sadrian } else { 696250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR; 697250003Sadrian } 698250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI), 699250003Sadrian ((ahp->ah_msi_reg | AR_PCIE_MSI_ENABLE) & msi_pend_addr_mask)); 700250003Sadrian } 701250003Sadrian 702250003Sadrian /* 703250003Sadrian * debug - enable to see all synchronous interrupts status 704250003Sadrian * Enable synchronous GPIO interrupts as well, since some async 705250003Sadrian * GPIO interrupts don't wake the chip up. 706250003Sadrian */ 707250003Sadrian mask = 0; 708250003Sadrian#ifndef ATH_GPIO_USE_ASYNC_CAUSE 709250003Sadrian if (ints & HAL_INT_GPIO) { 710250003Sadrian mask |= SM(ahp->ah_gpio_mask, AR_INTR_SYNC_MASK_GPIO); 711250003Sadrian } 712250003Sadrian#endif 713250003Sadrian if (AR_SREV_POSEIDON(ah)) { 714250003Sadrian sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR; 715250003Sadrian } 716250003Sadrian else if (AR_SREV_WASP(ah)) { 717250003Sadrian sync_en_def = AR9340_INTR_SYNC_DEFAULT; 718250003Sadrian } 719250003Sadrian 720250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 721250003Sadrian (sync_en_def | mask)); 722250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 723250003Sadrian (sync_en_def | mask)); 724250003Sadrian 725250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 726250003Sadrian "AR_IMR 0x%x IER 0x%x\n", 727250003Sadrian OS_REG_READ(ah, AR_IMR), OS_REG_READ(ah, AR_IER)); 728250003Sadrian } 729250003Sadrian 730250003Sadrian return omask; 731250003Sadrian} 732250003Sadrian 733250003Sadrianvoid 734250003Sadrianar9300_set_intr_mitigation_timer( 735250003Sadrian struct ath_hal* ah, 736250003Sadrian HAL_INT_MITIGATION reg, 737250003Sadrian u_int32_t value) 738250003Sadrian{ 739250003Sadrian#ifdef AR5416_INT_MITIGATION 740250003Sadrian switch (reg) { 741250003Sadrian case HAL_INT_THRESHOLD: 742250003Sadrian OS_REG_WRITE(ah, AR_MIRT, 0); 743250003Sadrian break; 744250003Sadrian case HAL_INT_RX_LASTPKT: 745250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, value); 746250003Sadrian break; 747250003Sadrian case HAL_INT_RX_FIRSTPKT: 748250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, value); 749250003Sadrian break; 750250003Sadrian case HAL_INT_TX_LASTPKT: 751250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, value); 752250003Sadrian break; 753250003Sadrian case HAL_INT_TX_FIRSTPKT: 754250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, value); 755250003Sadrian break; 756250003Sadrian default: 757250003Sadrian break; 758250003Sadrian } 759250003Sadrian#endif 760250003Sadrian} 761250003Sadrian 762250003Sadrianu_int32_t 763250003Sadrianar9300_get_intr_mitigation_timer(struct ath_hal* ah, HAL_INT_MITIGATION reg) 764250003Sadrian{ 765250003Sadrian u_int32_t val = 0; 766250003Sadrian#ifdef AR5416_INT_MITIGATION 767250003Sadrian switch (reg) { 768250003Sadrian case HAL_INT_THRESHOLD: 769250003Sadrian val = OS_REG_READ(ah, AR_MIRT); 770250003Sadrian break; 771250003Sadrian case HAL_INT_RX_LASTPKT: 772250003Sadrian val = OS_REG_READ(ah, AR_RIMT) & 0xFFFF; 773250003Sadrian break; 774250003Sadrian case HAL_INT_RX_FIRSTPKT: 775250003Sadrian val = OS_REG_READ(ah, AR_RIMT) >> 16; 776250003Sadrian break; 777250003Sadrian case HAL_INT_TX_LASTPKT: 778250003Sadrian val = OS_REG_READ(ah, AR_TIMT) & 0xFFFF; 779250003Sadrian break; 780250003Sadrian case HAL_INT_TX_FIRSTPKT: 781250003Sadrian val = OS_REG_READ(ah, AR_TIMT) >> 16; 782250003Sadrian break; 783250003Sadrian default: 784250003Sadrian break; 785250003Sadrian } 786250003Sadrian#endif 787250003Sadrian return val; 788250003Sadrian} 789