The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: ISC
    3  *
    4  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
    5  * Copyright (c) 2002-2008 Atheros Communications, Inc.
    6  *
    7  * Permission to use, copy, modify, and/or distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  *
   19  * $FreeBSD$
   20  */
   21 #include "opt_ah.h"
   22 
   23 #include "ah.h"
   24 #include "ah_internal.h"
   25 
   26 #include "ar5416/ar5416.h"
   27 #include "ar5416/ar5416reg.h"
   28 
   29 /*
   30  * Checks to see if an interrupt is pending on our NIC
   31  *
   32  * Returns: TRUE    if an interrupt is pending
   33  *          FALSE   if not
   34  */
   35 HAL_BOOL
   36 ar5416IsInterruptPending(struct ath_hal *ah)
   37 {
   38         uint32_t isr;
   39 
   40         if (AR_SREV_HOWL(ah))
   41                 return AH_TRUE;
   42 
   43         /* 
   44          * Some platforms trigger our ISR before applying power to
   45          * the card, so make sure the INTPEND is really 1, not 0xffffffff.
   46          */
   47         isr = OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE);
   48         if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_MAC_IRQ) != 0)
   49                 return AH_TRUE;
   50 
   51         isr = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE);
   52         if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_SYNC_DEFAULT))
   53                 return AH_TRUE;
   54 
   55         return AH_FALSE;
   56 }
   57 
   58 /*
   59  * Reads the Interrupt Status Register value from the NIC, thus deasserting
   60  * the interrupt line, and returns both the masked and unmasked mapped ISR
   61  * values.  The value returned is mapped to abstract the hw-specific bit
   62  * locations in the Interrupt Status Register.
   63  *
   64  * (*masked) is cleared on initial call.
   65  *
   66  * Returns: A hardware-abstracted bitmap of all non-masked-out
   67  *          interrupts pending, as well as an unmasked value
   68  */
   69 HAL_BOOL
   70 ar5416GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked)
   71 {
   72         uint32_t isr, isr0, isr1, sync_cause = 0, o_sync_cause = 0;
   73         HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
   74 
   75 #ifdef  AH_INTERRUPT_DEBUGGING
   76         /*
   77          * Blank the interrupt debugging area regardless.
   78          */
   79         bzero(&ah->ah_intrstate, sizeof(ah->ah_intrstate));
   80         ah->ah_syncstate = 0;
   81 #endif
   82 
   83         /*
   84          * Verify there's a mac interrupt and the RTC is on.
   85          */
   86         if (AR_SREV_HOWL(ah)) {
   87                 *masked = 0;
   88                 isr = OS_REG_READ(ah, AR_ISR);
   89         } else {
   90                 if ((OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) &&
   91                     (OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON)
   92                         isr = OS_REG_READ(ah, AR_ISR);
   93                 else
   94                         isr = 0;
   95 #ifdef  AH_INTERRUPT_DEBUGGING
   96                 ah->ah_syncstate =
   97 #endif
   98                 o_sync_cause = sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE);
   99                 sync_cause &= AR_INTR_SYNC_DEFAULT;
  100                 *masked = 0;
  101 
  102                 if (isr == 0 && sync_cause == 0)
  103                         return AH_FALSE;
  104         }
  105 
  106 #ifdef  AH_INTERRUPT_DEBUGGING
  107         ah->ah_intrstate[0] = isr;
  108         ah->ah_intrstate[1] = OS_REG_READ(ah, AR_ISR_S0);
  109         ah->ah_intrstate[2] = OS_REG_READ(ah, AR_ISR_S1);
  110         ah->ah_intrstate[3] = OS_REG_READ(ah, AR_ISR_S2);
  111         ah->ah_intrstate[4] = OS_REG_READ(ah, AR_ISR_S3);
  112         ah->ah_intrstate[5] = OS_REG_READ(ah, AR_ISR_S4);
  113         ah->ah_intrstate[6] = OS_REG_READ(ah, AR_ISR_S5);
  114 #endif
  115 
  116         if (isr != 0) {
  117                 struct ath_hal_5212 *ahp = AH5212(ah);
  118                 uint32_t mask2;
  119 
  120                 mask2 = 0;
  121                 if (isr & AR_ISR_BCNMISC) {
  122                         uint32_t isr2 = OS_REG_READ(ah, AR_ISR_S2);
  123                         if (isr2 & AR_ISR_S2_TIM)
  124                                 mask2 |= HAL_INT_TIM;
  125                         if (isr2 & AR_ISR_S2_DTIM)
  126                                 mask2 |= HAL_INT_DTIM;
  127                         if (isr2 & AR_ISR_S2_DTIMSYNC)
  128                                 mask2 |= HAL_INT_DTIMSYNC;
  129                         if (isr2 & (AR_ISR_S2_CABEND ))
  130                                 mask2 |= HAL_INT_CABEND;
  131                         if (isr2 & AR_ISR_S2_GTT)
  132                                 mask2 |= HAL_INT_GTT;
  133                         if (isr2 & AR_ISR_S2_CST)
  134                                 mask2 |= HAL_INT_CST;   
  135                         if (isr2 & AR_ISR_S2_TSFOOR)
  136                                 mask2 |= HAL_INT_TSFOOR;
  137 
  138                         /*
  139                          * Don't mask out AR_BCNMISC; instead mask
  140                          * out what causes it.
  141                          */
  142                         OS_REG_WRITE(ah, AR_ISR_S2, isr2);
  143                         isr &= ~AR_ISR_BCNMISC;
  144                 }
  145 
  146                 if (isr == 0xffffffff) {
  147                         *masked = 0;
  148                         return AH_FALSE;
  149                 }
  150 
  151                 *masked = isr & HAL_INT_COMMON;
  152 
  153                 if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
  154                         *masked |= HAL_INT_RX;
  155                 if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
  156                         *masked |= HAL_INT_TX;
  157 
  158                 /*
  159                  * When doing RX interrupt mitigation, the RXOK bit is set
  160                  * in AR_ISR even if the relevant bit in AR_IMR is clear.
  161                  * Since this interrupt may be due to another source, don't
  162                  * just automatically set HAL_INT_RX if it's set, otherwise
  163                  * we could prematurely service the RX queue.
  164                  *
  165                  * In some cases, the driver can even handle all the RX
  166                  * frames just before the mitigation interrupt fires.
  167                  * The subsequent RX processing trip will then end up
  168                  * processing 0 frames.
  169                  */
  170 #ifdef  AH_AR5416_INTERRUPT_MITIGATION
  171                 if (isr & AR_ISR_RXERR)
  172                         *masked |= HAL_INT_RX;
  173 #else
  174                 if (isr & (AR_ISR_RXOK | AR_ISR_RXERR))
  175                         *masked |= HAL_INT_RX;
  176 #endif
  177 
  178                 if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
  179                     AR_ISR_TXEOL)) {
  180                         *masked |= HAL_INT_TX;
  181 
  182                         isr0 = OS_REG_READ(ah, AR_ISR_S0);
  183                         OS_REG_WRITE(ah, AR_ISR_S0, isr0);
  184                         isr1 = OS_REG_READ(ah, AR_ISR_S1);
  185                         OS_REG_WRITE(ah, AR_ISR_S1, isr1);
  186 
  187                         /*
  188                          * Don't clear the primary ISR TX bits, clear
  189                          * what causes them (S0/S1.)
  190                          */
  191                         isr &= ~(AR_ISR_TXOK | AR_ISR_TXDESC |
  192                             AR_ISR_TXERR | AR_ISR_TXEOL);
  193 
  194                         ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXOK);
  195                         ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXDESC);
  196                         ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXERR);
  197                         ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXEOL);
  198                 }
  199 
  200                 if ((isr & AR_ISR_GENTMR) || (! pCap->halAutoSleepSupport)) {
  201                         uint32_t isr5;
  202                         isr5 = OS_REG_READ(ah, AR_ISR_S5);
  203                         OS_REG_WRITE(ah, AR_ISR_S5, isr5);
  204                         isr &= ~AR_ISR_GENTMR;
  205 
  206                         if (! pCap->halAutoSleepSupport)
  207                                 if (isr5 & AR_ISR_S5_TIM_TIMER)
  208                                         *masked |= HAL_INT_TIM_TIMER;
  209                 }
  210                 *masked |= mask2;
  211         }
  212 
  213         /*
  214          * Since we're not using AR_ISR_RAC, clear the status bits
  215          * for handled interrupts here. For bits whose interrupt
  216          * source is a secondary register, those bits should've been
  217          * masked out - instead of those bits being written back,
  218          * their source (ie, the secondary status registers) should
  219          * be cleared. That way there are no race conditions with
  220          * new triggers coming in whilst they've been read/cleared.
  221          */
  222         OS_REG_WRITE(ah, AR_ISR, isr);
  223         /* Flush previous write */
  224         OS_REG_READ(ah, AR_ISR);
  225 
  226         if (AR_SREV_HOWL(ah))
  227                 return AH_TRUE;
  228 
  229         if (sync_cause != 0) {
  230                 HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: sync_cause=0x%x\n",
  231                     __func__,
  232                     o_sync_cause);
  233                 if (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) {
  234                         *masked |= HAL_INT_FATAL;
  235                 }
  236                 if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
  237                         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RADM CPL timeout\n",
  238                             __func__);
  239                         OS_REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
  240                         OS_REG_WRITE(ah, AR_RC, 0);
  241                         *masked |= HAL_INT_FATAL;
  242                 }
  243                 /*
  244                  * On fatal errors collect ISR state for debugging.
  245                  */
  246                 if (*masked & HAL_INT_FATAL) {
  247                         AH_PRIVATE(ah)->ah_fatalState[0] = isr;
  248                         AH_PRIVATE(ah)->ah_fatalState[1] = sync_cause;
  249                         HALDEBUG(ah, HAL_DEBUG_ANY,
  250                             "%s: fatal error, ISR_RAC 0x%x SYNC_CAUSE 0x%x\n",
  251                             __func__, isr, sync_cause);
  252                 }
  253 
  254                 OS_REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
  255                 /* NB: flush write */
  256                 (void) OS_REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
  257         }
  258         return AH_TRUE;
  259 }
  260 
  261 /*
  262  * Atomically enables NIC interrupts.  Interrupts are passed in
  263  * via the enumerated bitmask in ints.
  264  */
  265 HAL_INT
  266 ar5416SetInterrupts(struct ath_hal *ah, HAL_INT ints)
  267 {
  268         struct ath_hal_5212 *ahp = AH5212(ah);
  269         uint32_t omask = ahp->ah_maskReg;
  270         uint32_t mask, mask2;
  271 
  272         HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: 0x%x => 0x%x\n",
  273             __func__, omask, ints);
  274 
  275         if (omask & HAL_INT_GLOBAL) {
  276                 HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__);
  277                 OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
  278                 (void) OS_REG_READ(ah, AR_IER);
  279 
  280                 if (! AR_SREV_HOWL(ah)) {
  281                         OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
  282                         (void) OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE);
  283 
  284                         OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
  285                         (void) OS_REG_READ(ah, AR_INTR_SYNC_ENABLE);
  286                 }
  287         }
  288 
  289         mask = ints & HAL_INT_COMMON;
  290         mask2 = 0;
  291 
  292 #ifdef  AH_AR5416_INTERRUPT_MITIGATION
  293         /*
  294          * Overwrite default mask if Interrupt mitigation
  295          * is specified for AR5416
  296          */
  297         if (ints & HAL_INT_RX)
  298                 mask |= AR_IMR_RXERR | AR_IMR_RXMINTR | AR_IMR_RXINTM;
  299 #else
  300         if (ints & HAL_INT_RX)
  301                 mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC;
  302 #endif
  303         if (ints & HAL_INT_TX) {
  304                 if (ahp->ah_txOkInterruptMask)
  305                         mask |= AR_IMR_TXOK;
  306                 if (ahp->ah_txErrInterruptMask)
  307                         mask |= AR_IMR_TXERR;
  308                 if (ahp->ah_txDescInterruptMask)
  309                         mask |= AR_IMR_TXDESC;
  310                 if (ahp->ah_txEolInterruptMask)
  311                         mask |= AR_IMR_TXEOL;
  312                 if (ahp->ah_txUrnInterruptMask)
  313                         mask |= AR_IMR_TXURN;
  314         }
  315         if (ints & (HAL_INT_BMISC)) {
  316                 mask |= AR_IMR_BCNMISC;
  317                 if (ints & HAL_INT_TIM)
  318                         mask2 |= AR_IMR_S2_TIM;
  319                 if (ints & HAL_INT_DTIM)
  320                         mask2 |= AR_IMR_S2_DTIM;
  321                 if (ints & HAL_INT_DTIMSYNC)
  322                         mask2 |= AR_IMR_S2_DTIMSYNC;
  323                 if (ints & HAL_INT_CABEND)
  324                         mask2 |= (AR_IMR_S2_CABEND );
  325                 if (ints & HAL_INT_CST)
  326                         mask2 |= AR_IMR_S2_CST;
  327                 if (ints & HAL_INT_TSFOOR)
  328                         mask2 |= AR_IMR_S2_TSFOOR;
  329         }
  330 
  331         if (ints & (HAL_INT_GTT | HAL_INT_CST)) {
  332                 mask |= AR_IMR_BCNMISC;
  333                 if (ints & HAL_INT_GTT)
  334                         mask2 |= AR_IMR_S2_GTT;
  335                 if (ints & HAL_INT_CST)
  336                         mask2 |= AR_IMR_S2_CST;
  337         }
  338 
  339         /* Write the new IMR and store off our SW copy. */
  340         HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask);
  341         OS_REG_WRITE(ah, AR_IMR, mask);
  342         /* Flush write */
  343         (void) OS_REG_READ(ah, AR_IMR);
  344 
  345         mask = OS_REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |
  346                                         AR_IMR_S2_DTIM |
  347                                         AR_IMR_S2_DTIMSYNC |
  348                                         AR_IMR_S2_CABEND |
  349                                         AR_IMR_S2_CABTO  |
  350                                         AR_IMR_S2_TSFOOR |
  351                                         AR_IMR_S2_GTT |
  352                                         AR_IMR_S2_CST);
  353         OS_REG_WRITE(ah, AR_IMR_S2, mask | mask2);
  354 
  355         ahp->ah_maskReg = ints;
  356 
  357         /* Re-enable interrupts if they were enabled before. */
  358         if (ints & HAL_INT_GLOBAL) {
  359                 HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__);
  360                 OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
  361 
  362                 if (! AR_SREV_HOWL(ah)) {
  363                         mask = AR_INTR_MAC_IRQ;
  364                         if (ints & HAL_INT_GPIO)
  365                                 mask |= SM(AH5416(ah)->ah_gpioMask,
  366                                     AR_INTR_ASYNC_MASK_GPIO);
  367                         OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, mask);
  368                         OS_REG_WRITE(ah, AR_INTR_ASYNC_MASK, mask);
  369 
  370                         mask = AR_INTR_SYNC_DEFAULT;
  371                         if (ints & HAL_INT_GPIO)
  372                                 mask |= SM(AH5416(ah)->ah_gpioMask,
  373                                     AR_INTR_SYNC_MASK_GPIO);
  374                         OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, mask);
  375                         OS_REG_WRITE(ah, AR_INTR_SYNC_MASK, mask);
  376                 }
  377         }
  378 
  379         return omask;
  380 }

Cache object: 745a9394513f42a8232f8d595f54c507


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.