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