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); 392301091Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 393301091Sadrian "(MCI) cont_status=0x%08x\n", ahp->ah_mci_cont_status); 394250003Sadrian } 395250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 396250003Sadrian int_rx_msg); 397250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, int_raw); 398250003Sadrian 399250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s:AR_INTR_SYNC_MCI\n", __func__); 400250003Sadrian } 401250003Sadrian } 402250003Sadrian#endif 403250003Sadrian } 404250003Sadrian 405250003Sadrian if (sync_cause) { 406250003Sadrian int host1_fatal, host1_perr, radm_cpl_timeout, local_timeout; 407250003Sadrian 408250003Sadrian host1_fatal = AR_SREV_WASP(ah) ? 409250003Sadrian AR9340_INTR_SYNC_HOST1_FATAL : AR9300_INTR_SYNC_HOST1_FATAL; 410250003Sadrian host1_perr = AR_SREV_WASP(ah) ? 411250003Sadrian AR9340_INTR_SYNC_HOST1_PERR : AR9300_INTR_SYNC_HOST1_PERR; 412250003Sadrian radm_cpl_timeout = AR_SREV_WASP(ah) ? 413250003Sadrian 0x0 : AR9300_INTR_SYNC_RADM_CPL_TIMEOUT; 414250003Sadrian local_timeout = AR_SREV_WASP(ah) ? 415250003Sadrian AR9340_INTR_SYNC_LOCAL_TIMEOUT : AR9300_INTR_SYNC_LOCAL_TIMEOUT; 416250003Sadrian 417250003Sadrian if (sync_cause & host1_fatal) { 418250003Sadrian#if __PKT_SERIOUS_ERRORS__ 419250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 420250003Sadrian "%s: received PCI FATAL interrupt\n", __func__); 421250003Sadrian#endif 422250003Sadrian *masked |= HAL_INT_FATAL; /* Set FATAL INT flag here;*/ 423250003Sadrian } 424250003Sadrian if (sync_cause & host1_perr) { 425250003Sadrian#if __PKT_SERIOUS_ERRORS__ 426250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 427250003Sadrian "%s: received PCI PERR interrupt\n", __func__); 428250003Sadrian#endif 429250003Sadrian } 430250003Sadrian 431250003Sadrian if (sync_cause & radm_cpl_timeout) { 432250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 433250003Sadrian "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n", 434250003Sadrian __func__); 435250003Sadrian 436250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF); 437250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), 0); 438250003Sadrian *masked |= HAL_INT_FATAL; 439250003Sadrian } 440250003Sadrian if (sync_cause & local_timeout) { 441250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 442250003Sadrian "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n", 443250003Sadrian __func__); 444250003Sadrian } 445250003Sadrian 446250003Sadrian#ifndef ATH_GPIO_USE_ASYNC_CAUSE 447250003Sadrian if (sync_cause & AR_INTR_SYNC_MASK_GPIO) { 448250003Sadrian ahp->ah_gpio_cause = (sync_cause & AR_INTR_SYNC_MASK_GPIO) >> 449250003Sadrian AR_INTR_SYNC_ENABLE_GPIO_S; 450250003Sadrian *masked |= HAL_INT_GPIO; 451250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 452250003Sadrian "%s: AR_INTR_SYNC_GPIO\n", __func__); 453250003Sadrian } 454250003Sadrian#endif 455250003Sadrian 456250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR), sync_cause); 457250003Sadrian /* Flush prior write */ 458250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR)); 459250003Sadrian } 460250003Sadrian 461250003Sadrianend: 462250003Sadrian if (HAL_INT_MSI == type) { 463250003Sadrian /* 464250003Sadrian * WAR for Bug EV#75887 465250003Sadrian * In normal case, SW read HOST_INTF_PCIE_MSI (0x40A4) and write 466250003Sadrian * into ah_msi_reg. Then use value of ah_msi_reg to set bit#25 467250003Sadrian * when want to enable HW write the cfg_msi_pending. 468250003Sadrian * Sometimes, driver get MSI interrupt before read 0x40a4 and 469250003Sadrian * ah_msi_reg is initialization value (0x0). 470250003Sadrian * We don't know why "MSI interrupt earlier than driver read" now... 471250003Sadrian */ 472250003Sadrian if (!ahp->ah_msi_reg) { 473250003Sadrian ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI)); 474250003Sadrian } 475250003Sadrian if (AR_SREV_POSEIDON(ah)) { 476250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; 477250003Sadrian } else { 478250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR; 479250003Sadrian } 480250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI), 481250003Sadrian ((ahp->ah_msi_reg | AR_PCIE_MSI_ENABLE) & msi_pend_addr_mask)); 482250003Sadrian 483250003Sadrian } 484250003Sadrian 485250003Sadrian return ret_val; 486250003Sadrian} 487250003Sadrian 488250003SadrianHAL_INT 489250003Sadrianar9300_get_interrupts(struct ath_hal *ah) 490250003Sadrian{ 491250003Sadrian return AH9300(ah)->ah_mask_reg; 492250003Sadrian} 493250003Sadrian 494250003Sadrian/* 495250003Sadrian * Atomically enables NIC interrupts. Interrupts are passed in 496250003Sadrian * via the enumerated bitmask in ints. 497250003Sadrian */ 498250003SadrianHAL_INT 499250003Sadrianar9300_set_interrupts(struct ath_hal *ah, HAL_INT ints, HAL_BOOL nortc) 500250003Sadrian{ 501250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 502250003Sadrian u_int32_t omask = ahp->ah_mask_reg; 503250003Sadrian u_int32_t mask, mask2, msi_mask = 0; 504250003Sadrian u_int32_t msi_pend_addr_mask = 0; 505250003Sadrian u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT; 506250003Sadrian HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 507250003Sadrian 508250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 509250003Sadrian "%s: 0x%x => 0x%x\n", __func__, omask, ints); 510250003Sadrian 511250003Sadrian if (omask & HAL_INT_GLOBAL) { 512250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__); 513250003Sadrian 514250008Sadrian if (ah->ah_config.ath_hal_enable_msi) { 515250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0); 516250003Sadrian /* flush write to HW */ 517250003Sadrian (void)OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE)); 518250003Sadrian } 519250003Sadrian 520250003Sadrian if (!nortc) { 521250003Sadrian OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); 522250003Sadrian (void) OS_REG_READ(ah, AR_IER); /* flush write to HW */ 523250003Sadrian } 524250003Sadrian 525250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0); 526250003Sadrian /* flush write to HW */ 527250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE)); 528250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE), 0); 529250003Sadrian /* flush write to HW */ 530250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE)); 531250003Sadrian } 532250003Sadrian 533250003Sadrian if (!nortc) { 534250003Sadrian /* reference count for global IER */ 535250003Sadrian if (ints & HAL_INT_GLOBAL) { 536250003Sadrian#ifdef AH_DEBUG 537250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 538250003Sadrian "%s: Request HAL_INT_GLOBAL ENABLED\n", __func__); 539250008Sadrian#if 0 540250003Sadrian if (OS_ATOMIC_READ(&ahp->ah_ier_ref_count) == 0) { 541250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 542250003Sadrian "%s: WARNING: ah_ier_ref_count is 0 " 543250003Sadrian "and attempting to enable IER\n", 544250003Sadrian __func__); 545250003Sadrian } 546250003Sadrian#endif 547250008Sadrian#endif 548250008Sadrian#if 0 549250003Sadrian if (OS_ATOMIC_READ(&ahp->ah_ier_ref_count) > 0) { 550250003Sadrian OS_ATOMIC_DEC(&ahp->ah_ier_ref_count); 551250003Sadrian } 552250008Sadrian#endif 553250003Sadrian } else { 554250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 555250003Sadrian "%s: Request HAL_INT_GLOBAL DISABLED\n", __func__); 556250003Sadrian OS_ATOMIC_INC(&ahp->ah_ier_ref_count); 557250003Sadrian } 558250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 559250003Sadrian "%s: ah_ier_ref_count = %d\n", __func__, ahp->ah_ier_ref_count); 560250003Sadrian 561250003Sadrian mask = ints & HAL_INT_COMMON; 562250003Sadrian mask2 = 0; 563250003Sadrian msi_mask = 0; 564250003Sadrian 565250003Sadrian if (ints & HAL_INT_TX) { 566250003Sadrian if (ahp->ah_intr_mitigation_tx) { 567250003Sadrian mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; 568250003Sadrian } else if (ahp->ah_tx_ok_interrupt_mask) { 569250003Sadrian mask |= AR_IMR_TXOK; 570250003Sadrian } 571250003Sadrian msi_mask |= AR_INTR_PRIO_TX; 572250003Sadrian if (ahp->ah_tx_err_interrupt_mask) { 573250003Sadrian mask |= AR_IMR_TXERR; 574250003Sadrian } 575250003Sadrian if (ahp->ah_tx_eol_interrupt_mask) { 576250003Sadrian mask |= AR_IMR_TXEOL; 577250003Sadrian } 578250003Sadrian } 579250003Sadrian if (ints & HAL_INT_RX) { 580250003Sadrian mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP; 581250003Sadrian if (ahp->ah_intr_mitigation_rx) { 582250003Sadrian mask &= ~(AR_IMR_RXOK_LP); 583250003Sadrian mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; 584250003Sadrian } else { 585250003Sadrian mask |= AR_IMR_RXOK_LP; 586250003Sadrian } 587250003Sadrian msi_mask |= AR_INTR_PRIO_RXLP | AR_INTR_PRIO_RXHP; 588250008Sadrian if (! p_cap->halAutoSleepSupport) { 589250003Sadrian mask |= AR_IMR_GENTMR; 590250003Sadrian } 591250003Sadrian } 592250003Sadrian 593250003Sadrian if (ints & (HAL_INT_BMISC)) { 594250003Sadrian mask |= AR_IMR_BCNMISC; 595250003Sadrian if (ints & HAL_INT_TIM) { 596250003Sadrian mask2 |= AR_IMR_S2_TIM; 597250003Sadrian } 598250003Sadrian if (ints & HAL_INT_DTIM) { 599250003Sadrian mask2 |= AR_IMR_S2_DTIM; 600250003Sadrian } 601250003Sadrian if (ints & HAL_INT_DTIMSYNC) { 602250003Sadrian mask2 |= AR_IMR_S2_DTIMSYNC; 603250003Sadrian } 604250003Sadrian if (ints & HAL_INT_CABEND) { 605250003Sadrian mask2 |= (AR_IMR_S2_CABEND); 606250003Sadrian } 607250003Sadrian if (ints & HAL_INT_TSFOOR) { 608250003Sadrian mask2 |= AR_IMR_S2_TSFOOR; 609250003Sadrian } 610250003Sadrian } 611250003Sadrian 612250003Sadrian if (ints & (HAL_INT_GTT | HAL_INT_CST)) { 613250003Sadrian mask |= AR_IMR_BCNMISC; 614250003Sadrian if (ints & HAL_INT_GTT) { 615250003Sadrian mask2 |= AR_IMR_S2_GTT; 616250003Sadrian } 617250003Sadrian if (ints & HAL_INT_CST) { 618250003Sadrian mask2 |= AR_IMR_S2_CST; 619250003Sadrian } 620250003Sadrian } 621250003Sadrian 622250003Sadrian if (ints & HAL_INT_BBPANIC) { 623250003Sadrian /* EV92527 - MAC secondary interrupt must enable AR_IMR_BCNMISC */ 624250003Sadrian mask |= AR_IMR_BCNMISC; 625250003Sadrian mask2 |= AR_IMR_S2_BBPANIC; 626250003Sadrian } 627250003Sadrian 628250003Sadrian if (ints & HAL_INT_GENTIMER) { 629250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 630250003Sadrian "%s: enabling gen timer\n", __func__); 631250003Sadrian mask |= AR_IMR_GENTMR; 632250003Sadrian } 633250003Sadrian 634250003Sadrian /* Write the new IMR and store off our SW copy. */ 635250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); 636250003Sadrian OS_REG_WRITE(ah, AR_IMR, mask); 637250003Sadrian ahp->ah_mask2Reg &= ~(AR_IMR_S2_TIM | 638250003Sadrian AR_IMR_S2_DTIM | 639250003Sadrian AR_IMR_S2_DTIMSYNC | 640250003Sadrian AR_IMR_S2_CABEND | 641250003Sadrian AR_IMR_S2_CABTO | 642250003Sadrian AR_IMR_S2_TSFOOR | 643250003Sadrian AR_IMR_S2_GTT | 644250003Sadrian AR_IMR_S2_CST | 645250003Sadrian AR_IMR_S2_BBPANIC); 646250003Sadrian ahp->ah_mask2Reg |= mask2; 647250003Sadrian OS_REG_WRITE(ah, AR_IMR_S2, ahp->ah_mask2Reg ); 648250003Sadrian ahp->ah_mask_reg = ints; 649250003Sadrian 650250008Sadrian if (! p_cap->halAutoSleepSupport) { 651250003Sadrian if (ints & HAL_INT_TIM_TIMER) { 652250003Sadrian OS_REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); 653250003Sadrian } 654250003Sadrian else { 655250003Sadrian OS_REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); 656250003Sadrian } 657250003Sadrian } 658250003Sadrian } 659250003Sadrian 660250003Sadrian /* Re-enable interrupts if they were enabled before. */ 661250003Sadrian#if HAL_INTR_REFCOUNT_DISABLE 662250003Sadrian if ((ints & HAL_INT_GLOBAL)) { 663250003Sadrian#else 664250003Sadrian if ((ints & HAL_INT_GLOBAL) && (OS_ATOMIC_READ(&ahp->ah_ier_ref_count) == 0)) { 665250003Sadrian#endif 666250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__); 667250003Sadrian 668250003Sadrian if (!nortc) { 669250003Sadrian OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE); 670250003Sadrian } 671250003Sadrian 672250003Sadrian mask = AR_INTR_MAC_IRQ; 673250003Sadrian#ifdef ATH_GPIO_USE_ASYNC_CAUSE 674250003Sadrian if (ints & HAL_INT_GPIO) { 675250003Sadrian if (ahp->ah_gpio_mask) { 676250003Sadrian mask |= SM(ahp->ah_gpio_mask, AR_INTR_ASYNC_MASK_GPIO); 677250003Sadrian } 678250003Sadrian } 679250003Sadrian#endif 680250003Sadrian 681250003Sadrian#if ATH_SUPPORT_MCI 682250003Sadrian if (ints & HAL_INT_MCI) { 683250003Sadrian mask |= AR_INTR_ASYNC_MASK_MCI; 684250003Sadrian } 685250003Sadrian#endif 686250003Sadrian 687250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE), mask); 688250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK), mask); 689250003Sadrian 690250008Sadrian if (ah->ah_config.ath_hal_enable_msi) { 691250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 692250003Sadrian msi_mask); 693250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 694250003Sadrian msi_mask); 695250003Sadrian if (AR_SREV_POSEIDON(ah)) { 696250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; 697250003Sadrian } else { 698250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR; 699250003Sadrian } 700250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI), 701250003Sadrian ((ahp->ah_msi_reg | AR_PCIE_MSI_ENABLE) & msi_pend_addr_mask)); 702250003Sadrian } 703250003Sadrian 704250003Sadrian /* 705250003Sadrian * debug - enable to see all synchronous interrupts status 706250003Sadrian * Enable synchronous GPIO interrupts as well, since some async 707250003Sadrian * GPIO interrupts don't wake the chip up. 708250003Sadrian */ 709250003Sadrian mask = 0; 710250003Sadrian#ifndef ATH_GPIO_USE_ASYNC_CAUSE 711250003Sadrian if (ints & HAL_INT_GPIO) { 712250003Sadrian mask |= SM(ahp->ah_gpio_mask, AR_INTR_SYNC_MASK_GPIO); 713250003Sadrian } 714250003Sadrian#endif 715250003Sadrian if (AR_SREV_POSEIDON(ah)) { 716250003Sadrian sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR; 717250003Sadrian } 718250003Sadrian else if (AR_SREV_WASP(ah)) { 719250003Sadrian sync_en_def = AR9340_INTR_SYNC_DEFAULT; 720250003Sadrian } 721250003Sadrian 722250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 723250003Sadrian (sync_en_def | mask)); 724250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 725250003Sadrian (sync_en_def | mask)); 726250003Sadrian 727250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 728250003Sadrian "AR_IMR 0x%x IER 0x%x\n", 729250003Sadrian OS_REG_READ(ah, AR_IMR), OS_REG_READ(ah, AR_IER)); 730250003Sadrian } 731250003Sadrian 732250003Sadrian return omask; 733250003Sadrian} 734250003Sadrian 735250003Sadrianvoid 736250003Sadrianar9300_set_intr_mitigation_timer( 737250003Sadrian struct ath_hal* ah, 738250003Sadrian HAL_INT_MITIGATION reg, 739250003Sadrian u_int32_t value) 740250003Sadrian{ 741250003Sadrian#ifdef AR5416_INT_MITIGATION 742250003Sadrian switch (reg) { 743250003Sadrian case HAL_INT_THRESHOLD: 744250003Sadrian OS_REG_WRITE(ah, AR_MIRT, 0); 745250003Sadrian break; 746250003Sadrian case HAL_INT_RX_LASTPKT: 747250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, value); 748250003Sadrian break; 749250003Sadrian case HAL_INT_RX_FIRSTPKT: 750250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, value); 751250003Sadrian break; 752250003Sadrian case HAL_INT_TX_LASTPKT: 753250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, value); 754250003Sadrian break; 755250003Sadrian case HAL_INT_TX_FIRSTPKT: 756250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, value); 757250003Sadrian break; 758250003Sadrian default: 759250003Sadrian break; 760250003Sadrian } 761250003Sadrian#endif 762250003Sadrian} 763250003Sadrian 764250003Sadrianu_int32_t 765250003Sadrianar9300_get_intr_mitigation_timer(struct ath_hal* ah, HAL_INT_MITIGATION reg) 766250003Sadrian{ 767250003Sadrian u_int32_t val = 0; 768250003Sadrian#ifdef AR5416_INT_MITIGATION 769250003Sadrian switch (reg) { 770250003Sadrian case HAL_INT_THRESHOLD: 771250003Sadrian val = OS_REG_READ(ah, AR_MIRT); 772250003Sadrian break; 773250003Sadrian case HAL_INT_RX_LASTPKT: 774250003Sadrian val = OS_REG_READ(ah, AR_RIMT) & 0xFFFF; 775250003Sadrian break; 776250003Sadrian case HAL_INT_RX_FIRSTPKT: 777250003Sadrian val = OS_REG_READ(ah, AR_RIMT) >> 16; 778250003Sadrian break; 779250003Sadrian case HAL_INT_TX_LASTPKT: 780250003Sadrian val = OS_REG_READ(ah, AR_TIMT) & 0xFFFF; 781250003Sadrian break; 782250003Sadrian case HAL_INT_TX_FIRSTPKT: 783250003Sadrian val = OS_REG_READ(ah, AR_TIMT) >> 16; 784250003Sadrian break; 785250003Sadrian default: 786250003Sadrian break; 787250003Sadrian } 788250003Sadrian#endif 789250003Sadrian return val; 790250003Sadrian} 791