ar9300_interrupts.c revision 250008
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 145250003Sadrian sync_cause = 146250003Sadrian OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)) & 147250003Sadrian (sync_en_def | AR_INTR_SYNC_MASK_GPIO); 148250003Sadrian 149250003Sadrian if (!isr && !sync_cause && !async_cause) { 150250003Sadrian ret_val = AH_FALSE; 151250003Sadrian goto end; 152250003Sadrian } 153250003Sadrian 154250008Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 155250008Sadrian "%s: isr=0x%x, sync_cause=0x%x, async_cause=0x%x\n", 156250008Sadrian __func__, 157250008Sadrian isr, 158250008Sadrian sync_cause, 159250008Sadrian async_cause); 160250008Sadrian 161250003Sadrian if (isr) { 162250003Sadrian if (isr & AR_ISR_BCNMISC) { 163250003Sadrian u_int32_t isr2; 164250003Sadrian isr2 = OS_REG_READ(ah, AR_ISR_S2); 165250003Sadrian 166250003Sadrian /* Translate ISR bits to HAL values */ 167250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_TIM) >> MAP_ISR_S2_HAL_TIM); 168250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_DTIM) >> MAP_ISR_S2_HAL_DTIM); 169250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_DTIMSYNC) >> MAP_ISR_S2_HAL_DTIMSYNC); 170250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_CABEND) >> MAP_ISR_S2_HAL_CABEND); 171250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_GTT) << MAP_ISR_S2_HAL_GTT); 172250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_CST) << MAP_ISR_S2_HAL_CST); 173250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >> MAP_ISR_S2_HAL_TSFOOR); 174250003Sadrian mask2 |= ((isr2 & AR_ISR_S2_BBPANIC) >> MAP_ISR_S2_HAL_BBPANIC); 175250003Sadrian 176250008Sadrian if (!p_cap->halIsrRacSupport) { 177250003Sadrian /* 178250003Sadrian * EV61133 (missing interrupts due to ISR_RAC): 179250003Sadrian * If not using ISR_RAC, clear interrupts by writing to ISR_S2. 180250003Sadrian * This avoids a race condition where a new BCNMISC interrupt 181250003Sadrian * could come in between reading the ISR and clearing the 182250003Sadrian * interrupt via the primary ISR. We therefore clear the 183250003Sadrian * interrupt via the secondary, which avoids this race. 184250003Sadrian */ 185250003Sadrian OS_REG_WRITE(ah, AR_ISR_S2, isr2); 186250003Sadrian isr &= ~AR_ISR_BCNMISC; 187250003Sadrian } 188250003Sadrian } 189250003Sadrian 190250003Sadrian /* Use AR_ISR_RAC only if chip supports it. 191250003Sadrian * See EV61133 (missing interrupts due to ISR_RAC) 192250003Sadrian */ 193250008Sadrian if (p_cap->halIsrRacSupport) { 194250003Sadrian isr = OS_REG_READ(ah, AR_ISR_RAC); 195250003Sadrian } 196250003Sadrian if (isr == 0xffffffff) { 197250003Sadrian *masked = 0; 198250003Sadrian ret_val = AH_FALSE; 199250003Sadrian goto end; 200250003Sadrian } 201250003Sadrian 202250003Sadrian *masked = isr & HAL_INT_COMMON; 203250003Sadrian 204250003Sadrian /* 205250003Sadrian * When interrupt mitigation is switched on, we fake a normal RX or TX 206250003Sadrian * interrupt when we received a mitigated interrupt. This way, the upper 207250003Sadrian * layer do not need to know about feature. 208250003Sadrian */ 209250003Sadrian if (ahp->ah_intr_mitigation_rx) { 210250003Sadrian /* Only Rx interrupt mitigation. No Tx intr. mitigation. */ 211250003Sadrian if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) { 212250003Sadrian *masked |= HAL_INT_RXLP; 213250003Sadrian } 214250003Sadrian } 215250003Sadrian if (ahp->ah_intr_mitigation_tx) { 216250003Sadrian if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) { 217250003Sadrian *masked |= HAL_INT_TX; 218250003Sadrian } 219250003Sadrian } 220250003Sadrian 221250003Sadrian if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR)) { 222250003Sadrian *masked |= HAL_INT_RXLP; 223250003Sadrian } 224250003Sadrian if (isr & AR_ISR_HP_RXOK) { 225250003Sadrian *masked |= HAL_INT_RXHP; 226250003Sadrian } 227250003Sadrian if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) { 228250003Sadrian *masked |= HAL_INT_TX; 229250003Sadrian 230250008Sadrian if (!p_cap->halIsrRacSupport) { 231250003Sadrian u_int32_t s0, s1; 232250003Sadrian /* 233250003Sadrian * EV61133 (missing interrupts due to ISR_RAC): 234250003Sadrian * If not using ISR_RAC, clear interrupts by writing to 235250003Sadrian * ISR_S0/S1. 236250003Sadrian * This avoids a race condition where a new interrupt 237250003Sadrian * could come in between reading the ISR and clearing the 238250003Sadrian * interrupt via the primary ISR. We therefore clear the 239250003Sadrian * interrupt via the secondary, which avoids this race. 240250003Sadrian */ 241250003Sadrian s0 = OS_REG_READ(ah, AR_ISR_S0); 242250003Sadrian OS_REG_WRITE(ah, AR_ISR_S0, s0); 243250003Sadrian s1 = OS_REG_READ(ah, AR_ISR_S1); 244250003Sadrian OS_REG_WRITE(ah, AR_ISR_S1, s1); 245250003Sadrian 246250003Sadrian isr &= ~(AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL); 247250003Sadrian } 248250003Sadrian } 249250003Sadrian 250250003Sadrian /* 251250003Sadrian * Do not treat receive overflows as fatal for owl. 252250003Sadrian */ 253250003Sadrian if (isr & AR_ISR_RXORN) { 254250003Sadrian#if __PKT_SERIOUS_ERRORS__ 255250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 256250003Sadrian "%s: receive FIFO overrun interrupt\n", __func__); 257250003Sadrian#endif 258250003Sadrian } 259250003Sadrian 260250003Sadrian#if 0 261250003Sadrian /* XXX Verify if this is fixed for Osprey */ 262250008Sadrian if (!p_cap->halAutoSleepSupport) { 263250003Sadrian u_int32_t isr5 = OS_REG_READ(ah, AR_ISR_S5_S); 264250003Sadrian if (isr5 & AR_ISR_S5_TIM_TIMER) { 265250003Sadrian *masked |= HAL_INT_TIM_TIMER; 266250003Sadrian } 267250003Sadrian } 268250003Sadrian#endif 269250003Sadrian if (isr & AR_ISR_GENTMR) { 270250003Sadrian u_int32_t s5; 271250003Sadrian 272250008Sadrian if (p_cap->halIsrRacSupport) { 273250003Sadrian /* Use secondary shadow registers if using ISR_RAC */ 274250003Sadrian s5 = OS_REG_READ(ah, AR_ISR_S5_S); 275250003Sadrian } else { 276250003Sadrian s5 = OS_REG_READ(ah, AR_ISR_S5); 277250003Sadrian } 278250003Sadrian if (isr & AR_ISR_GENTMR) { 279250003Sadrian 280250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 281250003Sadrian "%s: GENTIMER, ISR_RAC=0x%x ISR_S2_S=0x%x\n", __func__, 282250003Sadrian isr, s5); 283250003Sadrian ahp->ah_intr_gen_timer_trigger = 284250003Sadrian MS(s5, AR_ISR_S5_GENTIMER_TRIG); 285250003Sadrian ahp->ah_intr_gen_timer_thresh = 286250003Sadrian MS(s5, AR_ISR_S5_GENTIMER_THRESH); 287250003Sadrian if (ahp->ah_intr_gen_timer_trigger) { 288250003Sadrian *masked |= HAL_INT_GENTIMER; 289250003Sadrian } 290250003Sadrian } 291250008Sadrian if (!p_cap->halIsrRacSupport) { 292250003Sadrian /* 293250003Sadrian * EV61133 (missing interrupts due to ISR_RAC): 294250003Sadrian * If not using ISR_RAC, clear interrupts by writing to ISR_S5. 295250003Sadrian * This avoids a race condition where a new interrupt 296250003Sadrian * could come in between reading the ISR and clearing the 297250003Sadrian * interrupt via the primary ISR. We therefore clear the 298250003Sadrian * interrupt via the secondary, which avoids this race. 299250003Sadrian */ 300250003Sadrian OS_REG_WRITE(ah, AR_ISR_S5, s5); 301250003Sadrian isr &= ~AR_ISR_GENTMR; 302250003Sadrian } 303250003Sadrian } 304250003Sadrian 305250003Sadrian *masked |= mask2; 306250003Sadrian 307250008Sadrian if (!p_cap->halIsrRacSupport) { 308250003Sadrian /* 309250003Sadrian * EV61133 (missing interrupts due to ISR_RAC): 310250003Sadrian * If not using ISR_RAC, clear the interrupts we've read by 311250003Sadrian * writing back ones in these locations to the primary ISR 312250003Sadrian * (except for interrupts that have a secondary isr register - 313250003Sadrian * see above). 314250003Sadrian */ 315250003Sadrian OS_REG_WRITE(ah, AR_ISR, isr); 316250003Sadrian 317250003Sadrian /* Flush prior write */ 318250003Sadrian (void) OS_REG_READ(ah, AR_ISR); 319250003Sadrian } 320250003Sadrian 321250003Sadrian#ifdef AH_SUPPORT_AR9300 322250003Sadrian if (*masked & HAL_INT_BBPANIC) { 323250003Sadrian ar9300_handle_bb_panic(ah); 324250003Sadrian } 325250003Sadrian#endif 326250003Sadrian } 327250003Sadrian 328250003Sadrian if (async_cause) { 329250003Sadrian if (nortc) { 330250003Sadrian OS_REG_WRITE(ah, 331250003Sadrian AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE_CLR), async_cause); 332250003Sadrian /* Flush prior write */ 333250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE_CLR)); 334250003Sadrian } else { 335250003Sadrian#ifdef ATH_GPIO_USE_ASYNC_CAUSE 336250003Sadrian if (async_cause & AR_INTR_ASYNC_CAUSE_GPIO) { 337250003Sadrian ahp->ah_gpio_cause = (async_cause & AR_INTR_ASYNC_CAUSE_GPIO) >> 338250003Sadrian AR_INTR_ASYNC_ENABLE_GPIO_S; 339250003Sadrian *masked |= HAL_INT_GPIO; 340250003Sadrian } 341250003Sadrian#endif 342250003Sadrian } 343250003Sadrian 344250003Sadrian#if ATH_SUPPORT_MCI 345250003Sadrian if ((async_cause & AR_INTR_ASYNC_CAUSE_MCI) && 346250008Sadrian p_cap->halMciSupport) 347250003Sadrian { 348250003Sadrian u_int32_t int_raw, int_rx_msg; 349250003Sadrian 350250003Sadrian int_rx_msg = OS_REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); 351250003Sadrian int_raw = OS_REG_READ(ah, AR_MCI_INTERRUPT_RAW); 352250003Sadrian 353250003Sadrian if ((int_raw == 0xdeadbeef) || (int_rx_msg == 0xdeadbeef)) 354250003Sadrian { 355250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 356250003Sadrian "(MCI) Get 0xdeadbeef during MCI int processing" 357250003Sadrian "new int_raw=0x%08x, new rx_msg_raw=0x%08x, " 358250003Sadrian "int_raw=0x%08x, rx_msg_raw=0x%08x\n", 359250003Sadrian int_raw, int_rx_msg, ahp->ah_mci_int_raw, 360250003Sadrian ahp->ah_mci_int_rx_msg); 361250003Sadrian } 362250003Sadrian else { 363250003Sadrian if (ahp->ah_mci_int_raw || ahp->ah_mci_int_rx_msg) { 364250003Sadrian ahp->ah_mci_int_rx_msg |= int_rx_msg; 365250003Sadrian ahp->ah_mci_int_raw |= int_raw; 366250003Sadrian } 367250003Sadrian else { 368250003Sadrian ahp->ah_mci_int_rx_msg = int_rx_msg; 369250003Sadrian ahp->ah_mci_int_raw = int_raw; 370250003Sadrian } 371250003Sadrian 372250003Sadrian *masked |= HAL_INT_MCI; 373250003Sadrian ahp->ah_mci_rx_status = OS_REG_READ(ah, AR_MCI_RX_STATUS); 374250003Sadrian if (int_rx_msg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) { 375250003Sadrian ahp->ah_mci_cont_status = 376250003Sadrian OS_REG_READ(ah, AR_MCI_CONT_STATUS); 377250003Sadrian } 378250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 379250003Sadrian int_rx_msg); 380250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, int_raw); 381250003Sadrian 382250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s:AR_INTR_SYNC_MCI\n", __func__); 383250003Sadrian } 384250003Sadrian } 385250003Sadrian#endif 386250003Sadrian } 387250003Sadrian 388250003Sadrian if (sync_cause) { 389250003Sadrian int host1_fatal, host1_perr, radm_cpl_timeout, local_timeout; 390250003Sadrian 391250003Sadrian host1_fatal = AR_SREV_WASP(ah) ? 392250003Sadrian AR9340_INTR_SYNC_HOST1_FATAL : AR9300_INTR_SYNC_HOST1_FATAL; 393250003Sadrian host1_perr = AR_SREV_WASP(ah) ? 394250003Sadrian AR9340_INTR_SYNC_HOST1_PERR : AR9300_INTR_SYNC_HOST1_PERR; 395250003Sadrian radm_cpl_timeout = AR_SREV_WASP(ah) ? 396250003Sadrian 0x0 : AR9300_INTR_SYNC_RADM_CPL_TIMEOUT; 397250003Sadrian local_timeout = AR_SREV_WASP(ah) ? 398250003Sadrian AR9340_INTR_SYNC_LOCAL_TIMEOUT : AR9300_INTR_SYNC_LOCAL_TIMEOUT; 399250003Sadrian 400250003Sadrian if (sync_cause & host1_fatal) { 401250003Sadrian#if __PKT_SERIOUS_ERRORS__ 402250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 403250003Sadrian "%s: received PCI FATAL interrupt\n", __func__); 404250003Sadrian#endif 405250003Sadrian *masked |= HAL_INT_FATAL; /* Set FATAL INT flag here;*/ 406250003Sadrian } 407250003Sadrian if (sync_cause & host1_perr) { 408250003Sadrian#if __PKT_SERIOUS_ERRORS__ 409250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 410250003Sadrian "%s: received PCI PERR interrupt\n", __func__); 411250003Sadrian#endif 412250003Sadrian } 413250003Sadrian 414250003Sadrian if (sync_cause & radm_cpl_timeout) { 415250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 416250003Sadrian "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n", 417250003Sadrian __func__); 418250003Sadrian 419250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF); 420250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), 0); 421250003Sadrian *masked |= HAL_INT_FATAL; 422250003Sadrian } 423250003Sadrian if (sync_cause & local_timeout) { 424250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 425250003Sadrian "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n", 426250003Sadrian __func__); 427250003Sadrian } 428250003Sadrian 429250003Sadrian#ifndef ATH_GPIO_USE_ASYNC_CAUSE 430250003Sadrian if (sync_cause & AR_INTR_SYNC_MASK_GPIO) { 431250003Sadrian ahp->ah_gpio_cause = (sync_cause & AR_INTR_SYNC_MASK_GPIO) >> 432250003Sadrian AR_INTR_SYNC_ENABLE_GPIO_S; 433250003Sadrian *masked |= HAL_INT_GPIO; 434250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 435250003Sadrian "%s: AR_INTR_SYNC_GPIO\n", __func__); 436250003Sadrian } 437250003Sadrian#endif 438250003Sadrian 439250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR), sync_cause); 440250003Sadrian /* Flush prior write */ 441250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR)); 442250003Sadrian } 443250003Sadrian 444250003Sadrianend: 445250003Sadrian if (HAL_INT_MSI == type) { 446250003Sadrian /* 447250003Sadrian * WAR for Bug EV#75887 448250003Sadrian * In normal case, SW read HOST_INTF_PCIE_MSI (0x40A4) and write 449250003Sadrian * into ah_msi_reg. Then use value of ah_msi_reg to set bit#25 450250003Sadrian * when want to enable HW write the cfg_msi_pending. 451250003Sadrian * Sometimes, driver get MSI interrupt before read 0x40a4 and 452250003Sadrian * ah_msi_reg is initialization value (0x0). 453250003Sadrian * We don't know why "MSI interrupt earlier than driver read" now... 454250003Sadrian */ 455250003Sadrian if (!ahp->ah_msi_reg) { 456250003Sadrian ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI)); 457250003Sadrian } 458250003Sadrian if (AR_SREV_POSEIDON(ah)) { 459250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; 460250003Sadrian } else { 461250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR; 462250003Sadrian } 463250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI), 464250003Sadrian ((ahp->ah_msi_reg | AR_PCIE_MSI_ENABLE) & msi_pend_addr_mask)); 465250003Sadrian 466250003Sadrian } 467250003Sadrian 468250003Sadrian return ret_val; 469250003Sadrian} 470250003Sadrian 471250003SadrianHAL_INT 472250003Sadrianar9300_get_interrupts(struct ath_hal *ah) 473250003Sadrian{ 474250003Sadrian return AH9300(ah)->ah_mask_reg; 475250003Sadrian} 476250003Sadrian 477250003Sadrian/* 478250003Sadrian * Atomically enables NIC interrupts. Interrupts are passed in 479250003Sadrian * via the enumerated bitmask in ints. 480250003Sadrian */ 481250003SadrianHAL_INT 482250003Sadrianar9300_set_interrupts(struct ath_hal *ah, HAL_INT ints, HAL_BOOL nortc) 483250003Sadrian{ 484250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 485250003Sadrian u_int32_t omask = ahp->ah_mask_reg; 486250003Sadrian u_int32_t mask, mask2, msi_mask = 0; 487250003Sadrian u_int32_t msi_pend_addr_mask = 0; 488250003Sadrian u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT; 489250003Sadrian HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 490250003Sadrian 491250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 492250003Sadrian "%s: 0x%x => 0x%x\n", __func__, omask, ints); 493250003Sadrian 494250003Sadrian if (omask & HAL_INT_GLOBAL) { 495250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__); 496250003Sadrian 497250008Sadrian if (ah->ah_config.ath_hal_enable_msi) { 498250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0); 499250003Sadrian /* flush write to HW */ 500250003Sadrian (void)OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE)); 501250003Sadrian } 502250003Sadrian 503250003Sadrian if (!nortc) { 504250003Sadrian OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); 505250003Sadrian (void) OS_REG_READ(ah, AR_IER); /* flush write to HW */ 506250003Sadrian } 507250003Sadrian 508250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0); 509250003Sadrian /* flush write to HW */ 510250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE)); 511250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE), 0); 512250003Sadrian /* flush write to HW */ 513250003Sadrian (void) OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE)); 514250003Sadrian } 515250003Sadrian 516250003Sadrian if (!nortc) { 517250003Sadrian /* reference count for global IER */ 518250003Sadrian if (ints & HAL_INT_GLOBAL) { 519250003Sadrian#ifdef AH_DEBUG 520250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 521250003Sadrian "%s: Request HAL_INT_GLOBAL ENABLED\n", __func__); 522250008Sadrian#if 0 523250003Sadrian if (OS_ATOMIC_READ(&ahp->ah_ier_ref_count) == 0) { 524250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 525250003Sadrian "%s: WARNING: ah_ier_ref_count is 0 " 526250003Sadrian "and attempting to enable IER\n", 527250003Sadrian __func__); 528250003Sadrian } 529250003Sadrian#endif 530250008Sadrian#endif 531250008Sadrian#if 0 532250003Sadrian if (OS_ATOMIC_READ(&ahp->ah_ier_ref_count) > 0) { 533250003Sadrian OS_ATOMIC_DEC(&ahp->ah_ier_ref_count); 534250003Sadrian } 535250008Sadrian#endif 536250003Sadrian } else { 537250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 538250003Sadrian "%s: Request HAL_INT_GLOBAL DISABLED\n", __func__); 539250003Sadrian OS_ATOMIC_INC(&ahp->ah_ier_ref_count); 540250003Sadrian } 541250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 542250003Sadrian "%s: ah_ier_ref_count = %d\n", __func__, ahp->ah_ier_ref_count); 543250003Sadrian 544250003Sadrian mask = ints & HAL_INT_COMMON; 545250003Sadrian mask2 = 0; 546250003Sadrian msi_mask = 0; 547250003Sadrian 548250003Sadrian if (ints & HAL_INT_TX) { 549250003Sadrian if (ahp->ah_intr_mitigation_tx) { 550250003Sadrian mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; 551250003Sadrian } else if (ahp->ah_tx_ok_interrupt_mask) { 552250003Sadrian mask |= AR_IMR_TXOK; 553250003Sadrian } 554250003Sadrian msi_mask |= AR_INTR_PRIO_TX; 555250003Sadrian if (ahp->ah_tx_err_interrupt_mask) { 556250003Sadrian mask |= AR_IMR_TXERR; 557250003Sadrian } 558250003Sadrian if (ahp->ah_tx_eol_interrupt_mask) { 559250003Sadrian mask |= AR_IMR_TXEOL; 560250003Sadrian } 561250003Sadrian } 562250003Sadrian if (ints & HAL_INT_RX) { 563250003Sadrian mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP; 564250003Sadrian if (ahp->ah_intr_mitigation_rx) { 565250003Sadrian mask &= ~(AR_IMR_RXOK_LP); 566250003Sadrian mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; 567250003Sadrian } else { 568250003Sadrian mask |= AR_IMR_RXOK_LP; 569250003Sadrian } 570250003Sadrian msi_mask |= AR_INTR_PRIO_RXLP | AR_INTR_PRIO_RXHP; 571250008Sadrian if (! p_cap->halAutoSleepSupport) { 572250003Sadrian mask |= AR_IMR_GENTMR; 573250003Sadrian } 574250003Sadrian } 575250003Sadrian 576250003Sadrian if (ints & (HAL_INT_BMISC)) { 577250003Sadrian mask |= AR_IMR_BCNMISC; 578250003Sadrian if (ints & HAL_INT_TIM) { 579250003Sadrian mask2 |= AR_IMR_S2_TIM; 580250003Sadrian } 581250003Sadrian if (ints & HAL_INT_DTIM) { 582250003Sadrian mask2 |= AR_IMR_S2_DTIM; 583250003Sadrian } 584250003Sadrian if (ints & HAL_INT_DTIMSYNC) { 585250003Sadrian mask2 |= AR_IMR_S2_DTIMSYNC; 586250003Sadrian } 587250003Sadrian if (ints & HAL_INT_CABEND) { 588250003Sadrian mask2 |= (AR_IMR_S2_CABEND); 589250003Sadrian } 590250003Sadrian if (ints & HAL_INT_TSFOOR) { 591250003Sadrian mask2 |= AR_IMR_S2_TSFOOR; 592250003Sadrian } 593250003Sadrian } 594250003Sadrian 595250003Sadrian if (ints & (HAL_INT_GTT | HAL_INT_CST)) { 596250003Sadrian mask |= AR_IMR_BCNMISC; 597250003Sadrian if (ints & HAL_INT_GTT) { 598250003Sadrian mask2 |= AR_IMR_S2_GTT; 599250003Sadrian } 600250003Sadrian if (ints & HAL_INT_CST) { 601250003Sadrian mask2 |= AR_IMR_S2_CST; 602250003Sadrian } 603250003Sadrian } 604250003Sadrian 605250003Sadrian if (ints & HAL_INT_BBPANIC) { 606250003Sadrian /* EV92527 - MAC secondary interrupt must enable AR_IMR_BCNMISC */ 607250003Sadrian mask |= AR_IMR_BCNMISC; 608250003Sadrian mask2 |= AR_IMR_S2_BBPANIC; 609250003Sadrian } 610250003Sadrian 611250003Sadrian if (ints & HAL_INT_GENTIMER) { 612250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 613250003Sadrian "%s: enabling gen timer\n", __func__); 614250003Sadrian mask |= AR_IMR_GENTMR; 615250003Sadrian } 616250003Sadrian 617250003Sadrian /* Write the new IMR and store off our SW copy. */ 618250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); 619250003Sadrian OS_REG_WRITE(ah, AR_IMR, mask); 620250003Sadrian ahp->ah_mask2Reg &= ~(AR_IMR_S2_TIM | 621250003Sadrian AR_IMR_S2_DTIM | 622250003Sadrian AR_IMR_S2_DTIMSYNC | 623250003Sadrian AR_IMR_S2_CABEND | 624250003Sadrian AR_IMR_S2_CABTO | 625250003Sadrian AR_IMR_S2_TSFOOR | 626250003Sadrian AR_IMR_S2_GTT | 627250003Sadrian AR_IMR_S2_CST | 628250003Sadrian AR_IMR_S2_BBPANIC); 629250003Sadrian ahp->ah_mask2Reg |= mask2; 630250003Sadrian OS_REG_WRITE(ah, AR_IMR_S2, ahp->ah_mask2Reg ); 631250003Sadrian ahp->ah_mask_reg = ints; 632250003Sadrian 633250008Sadrian if (! p_cap->halAutoSleepSupport) { 634250003Sadrian if (ints & HAL_INT_TIM_TIMER) { 635250003Sadrian OS_REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); 636250003Sadrian } 637250003Sadrian else { 638250003Sadrian OS_REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); 639250003Sadrian } 640250003Sadrian } 641250003Sadrian } 642250003Sadrian 643250003Sadrian /* Re-enable interrupts if they were enabled before. */ 644250003Sadrian#if HAL_INTR_REFCOUNT_DISABLE 645250003Sadrian if ((ints & HAL_INT_GLOBAL)) { 646250003Sadrian#else 647250003Sadrian if ((ints & HAL_INT_GLOBAL) && (OS_ATOMIC_READ(&ahp->ah_ier_ref_count) == 0)) { 648250003Sadrian#endif 649250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__); 650250003Sadrian 651250003Sadrian if (!nortc) { 652250003Sadrian OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE); 653250003Sadrian } 654250003Sadrian 655250003Sadrian mask = AR_INTR_MAC_IRQ; 656250003Sadrian#ifdef ATH_GPIO_USE_ASYNC_CAUSE 657250003Sadrian if (ints & HAL_INT_GPIO) { 658250003Sadrian if (ahp->ah_gpio_mask) { 659250003Sadrian mask |= SM(ahp->ah_gpio_mask, AR_INTR_ASYNC_MASK_GPIO); 660250003Sadrian } 661250003Sadrian } 662250003Sadrian#endif 663250003Sadrian 664250003Sadrian#if ATH_SUPPORT_MCI 665250003Sadrian if (ints & HAL_INT_MCI) { 666250003Sadrian mask |= AR_INTR_ASYNC_MASK_MCI; 667250003Sadrian } 668250003Sadrian#endif 669250003Sadrian 670250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE), mask); 671250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK), mask); 672250003Sadrian 673250008Sadrian if (ah->ah_config.ath_hal_enable_msi) { 674250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 675250003Sadrian msi_mask); 676250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 677250003Sadrian msi_mask); 678250003Sadrian if (AR_SREV_POSEIDON(ah)) { 679250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; 680250003Sadrian } else { 681250003Sadrian msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR; 682250003Sadrian } 683250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI), 684250003Sadrian ((ahp->ah_msi_reg | AR_PCIE_MSI_ENABLE) & msi_pend_addr_mask)); 685250003Sadrian } 686250003Sadrian 687250003Sadrian /* 688250003Sadrian * debug - enable to see all synchronous interrupts status 689250003Sadrian * Enable synchronous GPIO interrupts as well, since some async 690250003Sadrian * GPIO interrupts don't wake the chip up. 691250003Sadrian */ 692250003Sadrian mask = 0; 693250003Sadrian#ifndef ATH_GPIO_USE_ASYNC_CAUSE 694250003Sadrian if (ints & HAL_INT_GPIO) { 695250003Sadrian mask |= SM(ahp->ah_gpio_mask, AR_INTR_SYNC_MASK_GPIO); 696250003Sadrian } 697250003Sadrian#endif 698250003Sadrian if (AR_SREV_POSEIDON(ah)) { 699250003Sadrian sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR; 700250003Sadrian } 701250003Sadrian else if (AR_SREV_WASP(ah)) { 702250003Sadrian sync_en_def = AR9340_INTR_SYNC_DEFAULT; 703250003Sadrian } 704250003Sadrian 705250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 706250003Sadrian (sync_en_def | mask)); 707250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 708250003Sadrian (sync_en_def | mask)); 709250003Sadrian 710250003Sadrian HALDEBUG(ah, HAL_DEBUG_INTERRUPT, 711250003Sadrian "AR_IMR 0x%x IER 0x%x\n", 712250003Sadrian OS_REG_READ(ah, AR_IMR), OS_REG_READ(ah, AR_IER)); 713250003Sadrian } 714250003Sadrian 715250003Sadrian return omask; 716250003Sadrian} 717250003Sadrian 718250003Sadrianvoid 719250003Sadrianar9300_set_intr_mitigation_timer( 720250003Sadrian struct ath_hal* ah, 721250003Sadrian HAL_INT_MITIGATION reg, 722250003Sadrian u_int32_t value) 723250003Sadrian{ 724250003Sadrian#ifdef AR5416_INT_MITIGATION 725250003Sadrian switch (reg) { 726250003Sadrian case HAL_INT_THRESHOLD: 727250003Sadrian OS_REG_WRITE(ah, AR_MIRT, 0); 728250003Sadrian break; 729250003Sadrian case HAL_INT_RX_LASTPKT: 730250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, value); 731250003Sadrian break; 732250003Sadrian case HAL_INT_RX_FIRSTPKT: 733250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, value); 734250003Sadrian break; 735250003Sadrian case HAL_INT_TX_LASTPKT: 736250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, value); 737250003Sadrian break; 738250003Sadrian case HAL_INT_TX_FIRSTPKT: 739250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, value); 740250003Sadrian break; 741250003Sadrian default: 742250003Sadrian break; 743250003Sadrian } 744250003Sadrian#endif 745250003Sadrian} 746250003Sadrian 747250003Sadrianu_int32_t 748250003Sadrianar9300_get_intr_mitigation_timer(struct ath_hal* ah, HAL_INT_MITIGATION reg) 749250003Sadrian{ 750250003Sadrian u_int32_t val = 0; 751250003Sadrian#ifdef AR5416_INT_MITIGATION 752250003Sadrian switch (reg) { 753250003Sadrian case HAL_INT_THRESHOLD: 754250003Sadrian val = OS_REG_READ(ah, AR_MIRT); 755250003Sadrian break; 756250003Sadrian case HAL_INT_RX_LASTPKT: 757250003Sadrian val = OS_REG_READ(ah, AR_RIMT) & 0xFFFF; 758250003Sadrian break; 759250003Sadrian case HAL_INT_RX_FIRSTPKT: 760250003Sadrian val = OS_REG_READ(ah, AR_RIMT) >> 16; 761250003Sadrian break; 762250003Sadrian case HAL_INT_TX_LASTPKT: 763250003Sadrian val = OS_REG_READ(ah, AR_TIMT) & 0xFFFF; 764250003Sadrian break; 765250003Sadrian case HAL_INT_TX_FIRSTPKT: 766250003Sadrian val = OS_REG_READ(ah, AR_TIMT) >> 16; 767250003Sadrian break; 768250003Sadrian default: 769250003Sadrian break; 770250003Sadrian } 771250003Sadrian#endif 772250003Sadrian return val; 773250003Sadrian} 774