Beispiel #1
0
/*
 * Checks to see if an interrupt is pending on our NIC
 *
 * Returns: TRUE    if an interrupt is pending
 *          FALSE   if not
 */
HAL_BOOL
ar9300_is_interrupt_pending(struct ath_hal *ah)
{
    u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT;
    u_int32_t host_isr;

    /*
     * Some platforms trigger our ISR before applying power to
     * the card, so make sure.
     */
    host_isr = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE));
    if ((host_isr & AR_INTR_ASYNC_USED) && (host_isr != AR_INTR_SPURIOUS)) {
        return AH_TRUE;
    }

    host_isr = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE));
    if (AR_SREV_POSEIDON(ah)) {
        sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR;
    }
    else if (AR_SREV_WASP(ah)) {
        sync_en_def = AR9340_INTR_SYNC_DEFAULT;
    }

    if ((host_isr & (sync_en_def | AR_INTR_SYNC_MASK_GPIO)) &&
        (host_isr != AR_INTR_SPURIOUS)) {
        return AH_TRUE;
    }

    return AH_FALSE;
}
Beispiel #2
0
/*
 * Once configured for I/O - set output lines
 */
HAL_BOOL
ar9300GpioSet(struct ath_hal *ah, u_int32_t gpio, u_int32_t val)
{
    HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);

    OS_REG_RMW(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUT), ((val&1) << gpio), AR_GPIO_BIT(gpio));

    return AH_TRUE;
}
Beispiel #3
0
/*
 * Configure GPIO Output lines
 */
HAL_BOOL
ar9300GpioCfgOutput(
    struct ath_hal *ah,
    u_int32_t gpio,
    HAL_GPIO_OUTPUT_MUX_TYPE halSignalType)
{
#define N(a)    (sizeof(a) / sizeof(a[0]))
#ifndef AR9340_EMULATION
    u_int32_t    ah_signal_type;
    u_int32_t    gpio_shift;

    static const u_int32_t    MuxSignalConversionTable[] = {
        /* HAL_GPIO_OUTPUT_MUX_AS_OUTPUT             */
        AR_GPIO_OUTPUT_MUX_AS_OUTPUT,
        /* HAL_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED */
        AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED,
        /* HAL_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED     */
        AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
        /* HAL_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    */
        AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED,
        /* HAL_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      */
        AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED,
        /* HAL_GPIO_OUTPUT_MUX_AS_WLAN_ACTIVE        */
        AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL,
        /* HAL_GPIO_OUTPUT_MUX_AS_TX_FRAME           */
        AR_GPIO_OUTPUT_MUX_AS_TX_FRAME,
    };

    HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);

    // Convert HAL signal type definitions to hardware-specific values.
    if ((halSignalType >= 0) && (halSignalType < N(MuxSignalConversionTable)))
    {
        ah_signal_type = MuxSignalConversionTable[halSignalType];
    }
    else
    {
        return AH_FALSE;
    }

    // Configure the MUX
    ar9300GpioCfgOutputMux(ah, gpio, ah_signal_type);

    // 2 bits per output mode
    gpio_shift = 2*gpio;

    OS_REG_RMW(ah,
               AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT),
               (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
               (AR_GPIO_OE_OUT_DRV << gpio_shift));

#endif
    return AH_TRUE;
#undef N
}
Beispiel #4
0
/*
 * Once configured for I/O - get input lines
 */
u_int32_t
ar9300GpioGet(struct ath_hal *ah, u_int32_t gpio)
{
    u_int32_t gpio_in;
    HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);

    if (gpio >= AH_PRIVATE(ah)->ah_caps.halNumGpioPins) {
        return 0xffffffff;
    }

    gpio_in = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_IN));
    return (MS(gpio_in, AR_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
}
Beispiel #5
0
static void
ar9300GpioCfgOutputMux(struct ath_hal *ah, u_int32_t gpio, u_int32_t type)
{
    int          addr;
    u_int32_t    gpio_shift;

    // each MUX controls 6 GPIO pins
    if (gpio > 11) {
        addr = AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX3);
    } else if (gpio > 5) {
        addr = AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX2);
    } else {
        addr = AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1);
    }

    /*
     * 5 bits per GPIO pin.
     * Bits 0..4 for 1st pin in that mux,
     * bits 5..9 for 2nd pin, etc.
     */
    gpio_shift = (gpio % 6) * 5;

    OS_REG_RMW(ah, addr, (type << gpio_shift), (0x1f << gpio_shift));
}
Beispiel #6
0
/*
 * Configure GPIO Input lines
 */
HAL_BOOL
ar9300GpioCfgInput(struct ath_hal *ah, u_int32_t gpio)
{
#ifndef AR9340_EMULATION
    u_int32_t    gpio_shift;

    HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);

    /* TODO: configure input mux for AR9300 */
    /* If configured as input, set output to tristate */
    gpio_shift = 2*gpio;

    OS_REG_RMW(ah,
               AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT),
               (AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
               (AR_GPIO_OE_OUT_DRV << gpio_shift));

#endif
    return AH_TRUE;
}
Beispiel #7
0
/*
 * Set the GPIO Interrupt
 * Sync and Async interrupts are both set/cleared.
 * Async GPIO interrupts may not be raised when the chip is put to sleep.
 */
void
ar9300GpioSetIntr(struct ath_hal *ah, u_int gpio, u_int32_t ilevel)
{
#ifndef AR9340_EMULATION
    struct ath_hal_9300 *ahp = AH9300(ah);
    u_int32_t val, mask;


    HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);


    if (ilevel == HAL_GPIO_INTR_DISABLE) {
        val = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE)),
            AR_INTR_ASYNC_ENABLE_GPIO);
        val &= ~AR_GPIO_BIT(gpio);
        OS_REG_RMW_FIELD(
            ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE), AR_INTR_ASYNC_ENABLE_GPIO, val);

        mask = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK)), AR_INTR_ASYNC_MASK_GPIO);
        mask &= ~AR_GPIO_BIT(gpio);
        OS_REG_RMW_FIELD(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK), AR_INTR_ASYNC_MASK_GPIO, mask);

        /*
         * Clear synchronous GPIO interrupt registers and pending
         * interrupt flag
         */
        val = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE)),
            AR_INTR_SYNC_ENABLE_GPIO);
        val &= ~AR_GPIO_BIT(gpio);
        OS_REG_RMW_FIELD(
            ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), AR_INTR_SYNC_ENABLE_GPIO, val);

        mask = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK)), AR_INTR_SYNC_MASK_GPIO);
        mask &= ~AR_GPIO_BIT(gpio);
        OS_REG_RMW_FIELD(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), AR_INTR_SYNC_MASK_GPIO, mask);

        val = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)), AR_INTR_SYNC_ENABLE_GPIO);
        val |= AR_GPIO_BIT(gpio);
        OS_REG_RMW_FIELD(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE), AR_INTR_SYNC_ENABLE_GPIO, val);
    } else {
        val = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL)), AR_GPIO_INTR_POL_VAL);
        if (ilevel == HAL_GPIO_INTR_HIGH) {
            /* 0 == interrupt on pin high */
            val &= ~AR_GPIO_BIT(gpio);
        } else if (ilevel == HAL_GPIO_INTR_LOW) {
            /* 1 == interrupt on pin low */
            val |= AR_GPIO_BIT(gpio);
        }
        OS_REG_RMW_FIELD(ah, AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL), AR_GPIO_INTR_POL_VAL, val);

        /* Change the interrupt mask. */
        val = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE)),
            AR_INTR_ASYNC_ENABLE_GPIO);
        val |= AR_GPIO_BIT(gpio);
        OS_REG_RMW_FIELD(
            ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE), AR_INTR_ASYNC_ENABLE_GPIO, val);

        mask = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK)), AR_INTR_ASYNC_MASK_GPIO);
        mask |= AR_GPIO_BIT(gpio);
        OS_REG_RMW_FIELD(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK), AR_INTR_ASYNC_MASK_GPIO, mask);

        /* Set synchronous GPIO interrupt registers as well */
        val = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE)),
            AR_INTR_SYNC_ENABLE_GPIO);
        val |= AR_GPIO_BIT(gpio);
        OS_REG_RMW_FIELD(
            ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), AR_INTR_SYNC_ENABLE_GPIO, val);

        mask = MS(OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK)), AR_INTR_SYNC_MASK_GPIO);
        mask |= AR_GPIO_BIT(gpio);
        OS_REG_RMW_FIELD(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), AR_INTR_SYNC_MASK_GPIO, mask);
    }

    /* Save GPIO interrupt mask */
    HALASSERT(mask == val);
    ahp->ah_gpioMask = mask;
#endif
}
Beispiel #8
0
/*
 * Reads the Interrupt Status Register value from the NIC, thus deasserting
 * the interrupt line, and returns both the masked and unmasked mapped ISR
 * values.  The value returned is mapped to abstract the hw-specific bit
 * locations in the Interrupt Status Register.
 *
 * Returns: A hardware-abstracted bitmap of all non-masked-out
 *          interrupts pending, as well as an unmasked value
 */
#define MAP_ISR_S2_HAL_CST          6 /* Carrier sense timeout */
#define MAP_ISR_S2_HAL_GTT          6 /* Global transmit timeout */
#define MAP_ISR_S2_HAL_TIM          3 /* TIM */
#define MAP_ISR_S2_HAL_CABEND       0 /* CABEND */
#define MAP_ISR_S2_HAL_DTIMSYNC     7 /* DTIMSYNC */
#define MAP_ISR_S2_HAL_DTIM         7 /* DTIM */
#define MAP_ISR_S2_HAL_TSFOOR       4 /* Rx TSF out of range */
#define MAP_ISR_S2_HAL_BBPANIC      6 /* Panic watchdog IRQ from BB */
HAL_BOOL
ar9300_get_pending_interrupts(
    struct ath_hal *ah,
    HAL_INT *masked,
    HAL_INT_TYPE type,
    u_int8_t msi,
    HAL_BOOL nortc)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    HAL_BOOL  ret_val = AH_TRUE;
    u_int32_t isr = 0;
    u_int32_t mask2 = 0;
    u_int32_t sync_cause = 0;
    u_int32_t async_cause;
    u_int32_t msi_pend_addr_mask = 0;
    u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT;
    HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;

    *masked = 0;

    if (!nortc) {
        if (HAL_INT_MSI == type) {
            if (msi == HAL_MSIVEC_RXHP) {
                OS_REG_WRITE(ah, AR_ISR, AR_ISR_HP_RXOK);
                *masked = HAL_INT_RXHP;
                goto end;
            } else if (msi == HAL_MSIVEC_RXLP) {
                OS_REG_WRITE(ah, AR_ISR,
                    (AR_ISR_LP_RXOK | AR_ISR_RXMINTR | AR_ISR_RXINTM));
                *masked = HAL_INT_RXLP;
                goto end;
            } else if (msi == HAL_MSIVEC_TX) {
                OS_REG_WRITE(ah, AR_ISR, AR_ISR_TXOK);
                *masked = HAL_INT_TX;
                goto end;
            } else if (msi == HAL_MSIVEC_MISC) {
                /*
                 * For the misc MSI event fall through and determine the cause.
                 */
            }
        }
    }

    /* Make sure mac interrupt is pending in async interrupt cause register */
    async_cause = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE));
    if (async_cause & AR_INTR_ASYNC_USED) {
        /*
         * RTC may not be on since it runs on a slow 32khz clock
         * so check its status to be sure
         */
        if (!nortc &&
            (OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) ==
             AR_RTC_STATUS_ON)
        {
            isr = OS_REG_READ(ah, AR_ISR);
        }
    }

    if (AR_SREV_POSEIDON(ah)) {
        sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR;
    }
    else if (AR_SREV_WASP(ah)) {
        sync_en_def = AR9340_INTR_SYNC_DEFAULT;
    }

    /* Store away the async and sync cause registers */
    /* XXX Do this before the filtering done below */
#ifdef	AH_INTERRUPT_DEBUGGING
	ah->ah_intrstate[0] = OS_REG_READ(ah, AR_ISR);
	ah->ah_intrstate[1] = OS_REG_READ(ah, AR_ISR_S0);
	ah->ah_intrstate[2] = OS_REG_READ(ah, AR_ISR_S1);
	ah->ah_intrstate[3] = OS_REG_READ(ah, AR_ISR_S2);
	ah->ah_intrstate[4] = OS_REG_READ(ah, AR_ISR_S3);
	ah->ah_intrstate[5] = OS_REG_READ(ah, AR_ISR_S4);
	ah->ah_intrstate[6] = OS_REG_READ(ah, AR_ISR_S5);

	/* XXX double reading? */
	ah->ah_syncstate = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE));
#endif

    sync_cause =
        OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)) &
        (sync_en_def | AR_INTR_SYNC_MASK_GPIO);

    if (!isr && !sync_cause && !async_cause) {
        ret_val = AH_FALSE;
        goto end;
    }

    HALDEBUG(ah, HAL_DEBUG_INTERRUPT,
        "%s: isr=0x%x, sync_cause=0x%x, async_cause=0x%x\n",
	__func__,
	isr,
	sync_cause,
	async_cause);

    if (isr) {
        if (isr & AR_ISR_BCNMISC) {
            u_int32_t isr2;
            isr2 = OS_REG_READ(ah, AR_ISR_S2);

            /* Translate ISR bits to HAL values */
            mask2 |= ((isr2 & AR_ISR_S2_TIM) >> MAP_ISR_S2_HAL_TIM);
            mask2 |= ((isr2 & AR_ISR_S2_DTIM) >> MAP_ISR_S2_HAL_DTIM);
            mask2 |= ((isr2 & AR_ISR_S2_DTIMSYNC) >> MAP_ISR_S2_HAL_DTIMSYNC);
            mask2 |= ((isr2 & AR_ISR_S2_CABEND) >> MAP_ISR_S2_HAL_CABEND);
            mask2 |= ((isr2 & AR_ISR_S2_GTT) << MAP_ISR_S2_HAL_GTT);
            mask2 |= ((isr2 & AR_ISR_S2_CST) << MAP_ISR_S2_HAL_CST);
            mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >> MAP_ISR_S2_HAL_TSFOOR);
            mask2 |= ((isr2 & AR_ISR_S2_BBPANIC) >> MAP_ISR_S2_HAL_BBPANIC);

            if (!p_cap->halIsrRacSupport) {
                /*
                 * EV61133 (missing interrupts due to ISR_RAC):
                 * If not using ISR_RAC, clear interrupts by writing to ISR_S2.
                 * This avoids a race condition where a new BCNMISC interrupt
                 * could come in between reading the ISR and clearing the
                 * interrupt via the primary ISR.  We therefore clear the
                 * interrupt via the secondary, which avoids this race.
                 */ 
                OS_REG_WRITE(ah, AR_ISR_S2, isr2);
                isr &= ~AR_ISR_BCNMISC;
            }
        }

        /* Use AR_ISR_RAC only if chip supports it. 
         * See EV61133 (missing interrupts due to ISR_RAC) 
         */
        if (p_cap->halIsrRacSupport) {
            isr = OS_REG_READ(ah, AR_ISR_RAC);
        }
        if (isr == 0xffffffff) {
            *masked = 0;
            ret_val = AH_FALSE;
            goto end;
        }
 
        *masked = isr & HAL_INT_COMMON;

        /*
         * When interrupt mitigation is switched on, we fake a normal RX or TX
         * interrupt when we received a mitigated interrupt. This way, the upper
         * layer do not need to know about feature.
         */
        if (ahp->ah_intr_mitigation_rx) {
            /* Only Rx interrupt mitigation. No Tx intr. mitigation. */
            if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) {
                *masked |= HAL_INT_RXLP;
            }
        }
        if (ahp->ah_intr_mitigation_tx) {
            if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) {
                *masked |= HAL_INT_TX;
            }
        }

        if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR)) {
            *masked |= HAL_INT_RXLP;
        }
        if (isr & AR_ISR_HP_RXOK) {
            *masked |= HAL_INT_RXHP;
        }
        if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) {
            *masked |= HAL_INT_TX;

            if (!p_cap->halIsrRacSupport) {
                u_int32_t s0, s1;
                /*
                 * EV61133 (missing interrupts due to ISR_RAC):
                 * If not using ISR_RAC, clear interrupts by writing to
                 * ISR_S0/S1.
                 * This avoids a race condition where a new interrupt
                 * could come in between reading the ISR and clearing the
                 * interrupt via the primary ISR.  We therefore clear the
                 * interrupt via the secondary, which avoids this race.
                 */ 
                s0 = OS_REG_READ(ah, AR_ISR_S0);
                OS_REG_WRITE(ah, AR_ISR_S0, s0);
                s1 = OS_REG_READ(ah, AR_ISR_S1);
                OS_REG_WRITE(ah, AR_ISR_S1, s1);

                isr &= ~(AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL);
            }
        }

        /*
         * Do not treat receive overflows as fatal for owl.
         */
        if (isr & AR_ISR_RXORN) {
#if __PKT_SERIOUS_ERRORS__
            HALDEBUG(ah, HAL_DEBUG_INTERRUPT,
                "%s: receive FIFO overrun interrupt\n", __func__);
#endif
        }

#if 0
        /* XXX Verify if this is fixed for Osprey */
        if (!p_cap->halAutoSleepSupport) {
            u_int32_t isr5 = OS_REG_READ(ah, AR_ISR_S5_S);
            if (isr5 & AR_ISR_S5_TIM_TIMER) {
                *masked |= HAL_INT_TIM_TIMER;
            }
        }
#endif
        if (isr & AR_ISR_GENTMR) {
            u_int32_t s5;

            if (p_cap->halIsrRacSupport) {
                /* Use secondary shadow registers if using ISR_RAC */
                s5 = OS_REG_READ(ah, AR_ISR_S5_S);
            } else {
                s5 = OS_REG_READ(ah, AR_ISR_S5);
            }
            if (isr & AR_ISR_GENTMR) {

                HALDEBUG(ah, HAL_DEBUG_INTERRUPT,
                    "%s: GENTIMER, ISR_RAC=0x%x ISR_S2_S=0x%x\n", __func__,
                    isr, s5);
                ahp->ah_intr_gen_timer_trigger =
                    MS(s5, AR_ISR_S5_GENTIMER_TRIG);
                ahp->ah_intr_gen_timer_thresh =
                    MS(s5, AR_ISR_S5_GENTIMER_THRESH);
                if (ahp->ah_intr_gen_timer_trigger) {
                    *masked |= HAL_INT_GENTIMER;
                }
            }
            if (!p_cap->halIsrRacSupport) {
                /*
                 * EV61133 (missing interrupts due to ISR_RAC):
                 * If not using ISR_RAC, clear interrupts by writing to ISR_S5.
                 * This avoids a race condition where a new interrupt
                 * could come in between reading the ISR and clearing the
                 * interrupt via the primary ISR.  We therefore clear the
                 * interrupt via the secondary, which avoids this race.
                 */ 
                OS_REG_WRITE(ah, AR_ISR_S5, s5);
                isr &= ~AR_ISR_GENTMR;
            }
        }

        *masked |= mask2;

        if (!p_cap->halIsrRacSupport) {
            /*
             * EV61133 (missing interrupts due to ISR_RAC):
             * If not using ISR_RAC, clear the interrupts we've read by
             * writing back ones in these locations to the primary ISR
             * (except for interrupts that have a secondary isr register -
             * see above).
             */ 
            OS_REG_WRITE(ah, AR_ISR, isr);

            /* Flush prior write */
            (void) OS_REG_READ(ah, AR_ISR);
        }

#ifdef AH_SUPPORT_AR9300
        if (*masked & HAL_INT_BBPANIC) {
            ar9300_handle_bb_panic(ah);
        }
#endif
    }