static void
ar9300_ani_restart(struct ath_hal *ah)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;

    if (!DO_ANI(ah)) {
        return;
    }

    ani_state = ahp->ah_curani;

    ani_state->listen_time = 0;

    OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
    OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

    /* Clear the mib counters and save them in the stats */
    ar9300_update_mib_mac_stats(ah);

    ani_state->ofdm_phy_err_count = 0;
    ani_state->cck_phy_err_count = 0;
}
void
ar9300_disable_mib_counters(struct ath_hal *ah)
{
    HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Disabling MIB counters\n", __func__);

    OS_REG_WRITE(ah, AR_MIBC,  AR_MIBC_FMC | AR_MIBC_CMC);

    /* Clear the mib counters and save them in the stats */
    ar9300_update_mib_mac_stats(ah);

    OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
    OS_REG_WRITE(ah, AR_FILT_CCK, 0);
}
void
ar9300_enable_mib_counters(struct ath_hal *ah)
{
    HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Enable MIB counters\n", __func__);
    /* Clear the mib counters and save them in the stats */
    ar9300_update_mib_mac_stats(ah);

    OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
    OS_REG_WRITE(ah, AR_FILT_CCK, 0);
    OS_REG_WRITE(ah, AR_MIBC,
        ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f);
    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

}
/*
 * Process a MIB interrupt.  We may potentially be invoked because
 * any of the MIB counters overflow/trigger so don't assume we're
 * here because a PHY error counter triggered.
 */
void
ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    u_int32_t phy_cnt1, phy_cnt2;

#if 0
    HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__);
#endif

    /* Reset these counters regardless */
    OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
    OS_REG_WRITE(ah, AR_FILT_CCK, 0);
    if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) {
        OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
    }

    /* Clear the mib counters and save them in the stats */
    ar9300_update_mib_mac_stats(ah);
    ahp->ah_stats.ast_nodestats = *stats;

    if (!DO_ANI(ah)) {
        /*
         * We must always clear the interrupt cause by resetting
         * the phy error regs.
         */
        OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
        OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
        return;
    }

    /* NB: these are not reset-on-read */
    phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
    phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
#if HAL_ANI_DEBUG
    HALDEBUG(ah, HAL_DEBUG_ANI,
        "%s: Errors: OFDM=0x%08x-0x0=%d   CCK=0x%08x-0x0=%d\n",
        __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2);
#endif
    if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
        ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
        /* NB: always restart to insure the h/w counters are reset */
        ar9300_ani_restart(ah);
    }
}
/*
 * Do periodic processing.  This routine is called from a timer
 */
void
ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
                const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;
    int32_t listen_time;
    u_int32_t ofdm_phy_err_rate, cck_phy_err_rate;
    u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt;
    HAL_BOOL old_phy_noise_spur;

    ani_state = ahp->ah_curani;
    ahp->ah_stats.ast_nodestats = *stats;        /* XXX optimize? */

    if (ani_state == NULL) {
        /* should not happen */
        HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
            "%s: can't poll - no ANI not initialized for this channel\n",
            __func__);
        return;
    }

    /*
     * ar9300_ani_ar_poll is never called while scanning but we may have been
     * scanning and now just restarted polling.  In this case we need to
     * restore historical values.
     */
    if (ani_state->must_restore) {
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: must restore - calling ar9300_ani_restart\n", __func__);
        ar9300_ani_reset(ah, AH_FALSE);
        return;
    }

    listen_time = ar9300_ani_get_listen_time(ah, ani_stats);
    if (listen_time <= 0) {
        ahp->ah_stats.ast_ani_lneg++;
        /* restart ANI period if listen_time is invalid */
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: listen_time=%d - calling ar9300_ani_restart\n",
            __func__, listen_time);
        ar9300_ani_restart(ah);
        return;
    }
    /* XXX beware of overflow? */
    ani_state->listen_time += listen_time;

    /* Clear the mib counters and save them in the stats */
    ar9300_update_mib_mac_stats(ah);
    /* NB: these are not reset-on-read */
    ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1);
    cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2);



    /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
    ahp->ah_stats.ast_ani_ofdmerrs +=
        ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
    ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt;

    ahp->ah_stats.ast_ani_cckerrs +=
        cck_phy_err_cnt - ani_state->cck_phy_err_count;
    ani_state->cck_phy_err_count = cck_phy_err_cnt;

#if HAL_ANI_DEBUG
    HALDEBUG(ah, HAL_DEBUG_ANI,
        "%s: Errors: OFDM=0x%08x-0x0=%d   CCK=0x%08x-0x0=%d\n",
        __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt,
        cck_phy_err_cnt, cck_phy_err_cnt);
#endif

    /*
     * If ani is not enabled, return after we've collected
     * statistics
     */
    if (!DO_ANI(ah)) {
        return;
    }

    ofdm_phy_err_rate =
        ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time;
    cck_phy_err_rate =
        ani_state->cck_phy_err_count * 1000 / ani_state->listen_time;

    HALDEBUG(ah, HAL_DEBUG_ANI,
        "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
        __func__, listen_time,
        ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
        ani_state->cck_noise_immunity_level, cck_phy_err_rate,
        ani_state->ofdms_turn);

    if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) {
        old_phy_noise_spur = ani_state->phy_noise_spur;
        if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
            cck_phy_err_rate <= ani_state->cck_trig_low) {
            if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) {
                ani_state->phy_noise_spur = 0;
            }
        } else {
            ani_state->phy_noise_spur = 1;
        }
        if (old_phy_noise_spur != ani_state->phy_noise_spur) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                     "%s: enviroment change from %d to %d\n",
                     __func__, old_phy_noise_spur, ani_state->phy_noise_spur);
        }
    }

    if (ani_state->listen_time > 5 * ahp->ah_ani_period) {
        /*
         * Check to see if need to lower immunity if
         * 5 ani_periods have passed
         */
        if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
            cck_phy_err_rate <= ani_state->cck_trig_low)
        {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d)  "
                "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n",
                __func__, ani_state->listen_time,
                ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
                ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level,
                cck_phy_err_rate, ani_state->cck_trig_low);
            ar9300_ani_lower_immunity(ah);
            ani_state->ofdms_turn = !ani_state->ofdms_turn;
        }
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - "
            "calling ar9300_ani_restart\n",
            __func__, ani_state->listen_time,
            ofdm_phy_err_rate, cck_phy_err_rate);
        ar9300_ani_restart(ah);
     } else if (ani_state->listen_time > ahp->ah_ani_period) {
        /* check to see if need to raise immunity */
        if (ofdm_phy_err_rate > ani_state->ofdm_trig_high &&
            (cck_phy_err_rate <= ani_state->cck_trig_high ||
             ani_state->ofdms_turn))
        {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> "
                "ar9300_ani_ofdm_err_trigger\n",
                __func__, ani_state->listen_time,
                ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
                ani_state->ofdm_trig_high);
            ar9300_ani_ofdm_err_trigger(ah);
            ar9300_ani_restart(ah);
            ani_state->ofdms_turn = AH_FALSE;
        } else if (cck_phy_err_rate > ani_state->cck_trig_high) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> "
                "ar9300_ani_cck_err_trigger\n",
                __func__, ani_state->listen_time,
                ani_state->cck_noise_immunity_level, cck_phy_err_rate,
                ani_state->cck_trig_high);
            ar9300_ani_cck_err_trigger(ah);
            ar9300_ani_restart(ah);
            ani_state->ofdms_turn = AH_TRUE;
        }
    }
}
Exemple #6
0
/*
 * Return an approximation of the time spent ``listening'' by
 * deducting the cycles spent tx'ing and rx'ing from the total
 * cycle count since our last call.  A return value <0 indicates
 * an invalid/inconsistent time.
 */
static int32_t
ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;
    u_int32_t tx_frame_count, rx_frame_count, cycle_count;
    int32_t listen_time;

    tx_frame_count = OS_REG_READ(ah, AR_TFCNT);
    rx_frame_count = OS_REG_READ(ah, AR_RFCNT);
    cycle_count = OS_REG_READ(ah, AR_CCCNT);

    ani_state = ahp->ah_curani;
#if ATH_SUPPORT_VOW_DCS 
    if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count ||
            ani_state->tx_frame_count > tx_frame_count ||
            ani_state->rx_frame_count > rx_frame_count) {
#else
    if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) {
#endif
        /*
         * Cycle counter wrap (or initial call); it's not possible
         * to accurately calculate a value because the registers
         * right shift rather than wrap--so punt and return 0.
         */
        listen_time = 0;
        ahp->ah_stats.ast_ani_lzero++;
#if HAL_ANI_DEBUG
        HDPRINTF(ah, HAL_DBG_ANI,
            "%s: 1st call: ani_state->cycle_count=%d\n",
            __func__, ani_state->cycle_count);
#endif
    } else {
        int32_t ccdelta = cycle_count - ani_state->cycle_count;
        int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count;
        int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count;
        listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah);
#if ATH_SUPPORT_VOW_DCS 
        ani_stats->cyclecnt_diff = ccdelta;
        ani_stats->txframecnt_diff = tfdelta;
        ani_stats->rxframecnt_diff = rfdelta;    
        ani_stats->valid  = AH_TRUE;
#endif
#if HAL_ANI_DEBUG
        HDPRINTF(ah, HAL_DBG_ANI,
            "%s: cyclecount=%d, rfcount=%d, tfcount=%d, listen_time=%d "
            "CLOCK_RATE=%d\n",
            __func__, ccdelta, rfdelta, tfdelta, listen_time, CLOCK_RATE(ah));
#endif
    }
#if ATH_SUPPORT_VOW_DCS 
    ani_stats->rxclr_cnt =  OS_REG_READ(ah, AR_RCCNT);
#endif   
    ani_state->cycle_count = cycle_count;
    ani_state->tx_frame_count = tx_frame_count;
    ani_state->rx_frame_count = rx_frame_count;
    return listen_time;
}

/*
 * Do periodic processing.  This routine is called from a timer
 */
void
ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
                HAL_CHANNEL *chan, HAL_ANISTATS *ani_stats)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;
    int32_t listen_time;
    u_int32_t ofdm_phy_err_rate, cck_phy_err_rate;
    u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt;
    bool old_phy_noise_spur;

    ani_state = ahp->ah_curani;
    ahp->ah_stats.ast_nodestats = *stats;        /* XXX optimize? */

    if (ani_state == NULL) {
        /* should not happen */
        HDPRINTF(ah, HAL_DBG_UNMASKABLE,
            "%s: can't poll - no ANI not initialized for this channel\n",
            __func__);
#if ATH_SUPPORT_VOW_DCS
        ani_stats->valid = false;
#endif
        return;
    }

    /*
     * ar9300_ani_ar_poll is never called while scanning but we may have been
     * scanning and now just restarted polling.  In this case we need to
     * restore historical values.
     */
    if (ani_state->must_restore) {
        HDPRINTF(ah, HAL_DBG_ANI,
            "%s: must restore - calling ar9300_ani_restart\n", __func__);
        ar9300_ani_reset(ah, false);
#if ATH_SUPPORT_VOW_DCS
        ani_stats->valid = false;
#endif
        return;
    }

    listen_time = ar9300_ani_get_listen_time(ah, ani_stats);
    if (listen_time <= 0) {
        ahp->ah_stats.ast_ani_lneg++;
        /* restart ANI period if listen_time is invalid */
        HDPRINTF(ah, HAL_DBG_ANI,
            "%s: listen_time=%d - calling ar9300_ani_restart\n",
            __func__, listen_time);
        ar9300_ani_restart(ah);
#if ATH_SUPPORT_VOW_DCS
        ani_stats->valid = false;
#endif
        return;
    }
    /* XXX beware of overflow? */
    ani_state->listen_time += listen_time;

    /* Clear the mib counters and save them in the stats */
    ar9300_update_mib_mac_stats(ah);
    /* NB: these are not reset-on-read */
    ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1);
    cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2);

#if ATH_SUPPORT_VOW_DCS
    ani_stats->listen_time = ani_state->listen_time;
    ani_stats->ofdmphyerr_cnt = ofdm_phy_err_cnt;
    ani_stats->cckphyerr_cnt = cck_phy_err_cnt;
    ani_stats->ofdmphyerrcnt_diff = ( ani_state->ofdm_phy_err_count <= ofdm_phy_err_cnt )?
                 ( ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count ) : ofdm_phy_err_cnt ;  
#endif


    /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
    ahp->ah_stats.ast_ani_ofdmerrs +=
        ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
    ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt;

    ahp->ah_stats.ast_ani_cckerrs +=
        cck_phy_err_cnt - ani_state->cck_phy_err_count;
    ani_state->cck_phy_err_count = cck_phy_err_cnt;

#if HAL_ANI_DEBUG
    HDPRINTF(ah, HAL_DBG_ANI,
        "%s: Errors: OFDM=0x%08x-0x0=%d   CCK=0x%08x-0x0=%d\n",
        __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt,
        cck_phy_err_cnt, cck_phy_err_cnt);
#endif

    /*
     * If ani is not enabled, return after we've collected
     * statistics
     */
    if (!DO_ANI(ah)) {
        return;
    }

    ofdm_phy_err_rate =
        ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time;
    cck_phy_err_rate =
        ani_state->cck_phy_err_count * 1000 / ani_state->listen_time;

    HDPRINTF(ah, HAL_DBG_ANI,
        "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
        __func__, listen_time,
        ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
        ani_state->cck_noise_immunity_level, cck_phy_err_rate,
        ani_state->ofdms_turn);

    if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) {
        old_phy_noise_spur = ani_state->phy_noise_spur;
        if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
            cck_phy_err_rate <= ani_state->cck_trig_low) {
            if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) {
                ani_state->phy_noise_spur = 0;
            }
        } else {
            ani_state->phy_noise_spur = 1;
        }
        if (old_phy_noise_spur != ani_state->phy_noise_spur) {
            HDPRINTF(ah, HAL_DBG_ANI,
                     "%s: enviroment change from %d to %d\n",
                     __func__, old_phy_noise_spur, ani_state->phy_noise_spur);
        }
    }

    if (ani_state->listen_time > 5 * ahp->ah_ani_period) {
        /*
         * Check to see if need to lower immunity if
         * 5 ani_periods have passed
         */
        if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
            cck_phy_err_rate <= ani_state->cck_trig_low)
        {
            HDPRINTF(ah, HAL_DBG_ANI,
                "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d)  "
                "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n",
                __func__, ani_state->listen_time,
                ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
                ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level,
                cck_phy_err_rate, ani_state->cck_trig_low);
            ar9300_ani_lower_immunity(ah);
            ani_state->ofdms_turn = !ani_state->ofdms_turn;
        }
        HDPRINTF(ah, HAL_DBG_ANI,
            "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - "
            "calling ar9300_ani_restart\n",
            __func__, ani_state->listen_time,
            ofdm_phy_err_rate, cck_phy_err_rate);
        ar9300_ani_restart(ah);
     } else if (ani_state->listen_time > ahp->ah_ani_period) {
        /* check to see if need to raise immunity */
        if (ofdm_phy_err_rate > ani_state->ofdm_trig_high &&
            (cck_phy_err_rate <= ani_state->cck_trig_high ||
             ani_state->ofdms_turn))
        {
            HDPRINTF(ah, HAL_DBG_ANI,
                "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> "
                "ar9300_ani_ofdm_err_trigger\n",
                __func__, ani_state->listen_time,
                ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
                ani_state->ofdm_trig_high);
            ar9300_ani_ofdm_err_trigger(ah);
            ar9300_ani_restart(ah);
            ani_state->ofdms_turn = false;
        } else if (cck_phy_err_rate > ani_state->cck_trig_high) {
            HDPRINTF(ah, HAL_DBG_ANI,
                "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> "
                "ar9300_ani_cck_err_trigger\n",
                __func__, ani_state->listen_time,
                ani_state->cck_noise_immunity_level, cck_phy_err_rate,
                ani_state->cck_trig_high);
            ar9300_ani_cck_err_trigger(ah);
            ar9300_ani_restart(ah);
            ani_state->ofdms_turn = true;
        }
    }
}

/*
 * The poll function above calculates short noise spurs, caused by non-80211
 * devices, based on OFDM/CCK Phy errs.
 * If the noise is short enough, we don't want our ratectrl Algo to stop probing
 * higher rates, due to bad PER.
 */
bool
ar9300_is_ani_noise_spur(struct ath_hal *ah)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;

    ani_state = ahp->ah_curani;

    return ani_state->phy_noise_spur;
}