Beispiel #1
0
void
ar9300_configure_spectral_scan(struct ath_hal *ah, HAL_SPECTRAL_PARAM *ss)
{
    u_int32_t val, i;
    struct ath_hal_9300 *ahp = AH9300(ah);
    bool asleep = ahp->ah_chip_full_sleep;
    int16_t nf_buf[NUM_NF_READINGS];

    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
        ar9300_set_power_mode(ah, HAL_PM_AWAKE, true);
    }

    ar9300_prep_spectral_scan(ah);

    if (ss->ss_spectral_pri) {
        for (i = 0; i < NUM_NF_READINGS; i++) {
            nf_buf[i] = NOISE_PWR_DBM_2_INT(ss->ss_nf_cal[i]);
        }
        ar9300_load_nf(ah, nf_buf);
#ifdef DEMO_MODE
        ar9300_disable_strong_signal(ah);
        ar9300_disable_weak_signal(ah);
        ar9300_set_radar_dc_thresh(ah);
        ar9300_set_cca_threshold(ah, MAX_CCA_THRESH);
        /*ar9300_disable_restart(ah);*/
#endif
    }   

    val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);

    if (ss->ss_fft_period != HAL_SPECTRAL_PARAM_NOVAL) {
        val &= ~AR_PHY_SPECTRAL_SCAN_FFT_PERIOD;
        val |= SM(ss->ss_fft_period, AR_PHY_SPECTRAL_SCAN_FFT_PERIOD);
    }

    if (ss->ss_period != HAL_SPECTRAL_PARAM_NOVAL) {
        val &= ~AR_PHY_SPECTRAL_SCAN_PERIOD;
        val |= SM(ss->ss_period, AR_PHY_SPECTRAL_SCAN_PERIOD);
    }

    if (ss->ss_count != HAL_SPECTRAL_PARAM_NOVAL) {
        val &= ~AR_PHY_SPECTRAL_SCAN_COUNT;
        /* Remnants of a Merlin bug, 128 translates to 0 for
         * continuous scanning. Instead we do piecemeal captures
         * of 64 samples for Osprey.
         */
        if (ss->ss_count == 128) {
            val |= SM(0, AR_PHY_SPECTRAL_SCAN_COUNT);
        } else {
            val |= SM(ss->ss_count, AR_PHY_SPECTRAL_SCAN_COUNT);
        }
    }

    if (ss->ss_period != HAL_SPECTRAL_PARAM_NOVAL) {
        val &= ~AR_PHY_SPECTRAL_SCAN_PERIOD;
        val |= SM(ss->ss_period, AR_PHY_SPECTRAL_SCAN_PERIOD);
    }

    if (ss->ss_short_report == true) {
        val |= AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
    } else {
        val &= ~AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
    }
    
    /* if noise power cal, force high priority */
    if (ss->ss_spectral_pri) {
        val |= AR_PHY_SPECTRAL_SCAN_PRIORITY_HI;
    } else {
        val &= ~AR_PHY_SPECTRAL_SCAN_PRIORITY_HI;
    }
    
    /* enable spectral scan */
    OS_REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val | AR_PHY_SPECTRAL_SCAN_ENABLE);

    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
        ar9300_set_power_mode(ah, HAL_PM_FULL_SLEEP, true);
    }
}
/*
 * Control Adaptive Noise Immunity Parameters
 */
HAL_BOOL
ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state = ahp->ah_curani;
    const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
    int32_t value, value2;
    u_int level = param;
    u_int is_on;

    if (chan == NULL && cmd != HAL_ANI_MODE) {
        HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
            "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd);
        return AH_FALSE;
    }

    switch (cmd & ahp->ah_ani_function) {
    case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: 
        {
            int m1_thresh_low, m2_thresh_low;
            int m1_thresh, m2_thresh;
            int m2_count_thr, m2_count_thr_low;
            int m1_thresh_low_ext, m2_thresh_low_ext;
            int m1_thresh_ext, m2_thresh_ext;
            /*
             * is_on == 1 means ofdm weak signal detection is ON
             * (default, less noise imm)
             * is_on == 0 means ofdm weak signal detection is OFF
             * (more noise imm)
             */
            is_on = param ? 1 : 0;

            if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah))
                goto skip_ws_det;

            /*
             * make register setting for default (weak sig detect ON)
             * come from INI file
             */
            m1_thresh_low    = is_on ?
                ani_state->ini_def.m1_thresh_low    : m1_thresh_low_off;
            m2_thresh_low    = is_on ?
                ani_state->ini_def.m2_thresh_low    : m2_thresh_low_off;
            m1_thresh       = is_on ?
                ani_state->ini_def.m1_thresh       : m1_thresh_off;
            m2_thresh       = is_on ?
                ani_state->ini_def.m2_thresh       : m2_thresh_off;
            m2_count_thr     = is_on ?
                ani_state->ini_def.m2_count_thr     : m2_count_thr_off;
            m2_count_thr_low  = is_on ?
                ani_state->ini_def.m2_count_thr_low  : m2_count_thr_low_off;
            m1_thresh_low_ext = is_on ?
                ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off;
            m2_thresh_low_ext = is_on ?
                ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off;
            m1_thresh_ext    = is_on ?
                ani_state->ini_def.m1_thresh_ext    : m1_thresh_ext_off;
            m2_thresh_ext    = is_on ?
                ani_state->ini_def.m2_thresh_ext    : m2_thresh_ext_off;
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
                AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
                AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH,
                m1_thresh);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH,
                m2_thresh);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR,
                m2_count_thr);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
                AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
                AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
                AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH,
                m1_thresh_ext);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH,
                m2_thresh_ext);
skip_ws_det:
            if (is_on) {
                OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
                    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
            } else {
                OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
                    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
            }
            if (!(is_on != ani_state->ofdm_weak_sig_detect_off)) {
                HALDEBUG(ah, HAL_DEBUG_ANI,
                    "%s: ** ch %d: ofdm weak signal: %s=>%s\n",
                    __func__, chan->ic_freq,
                    !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
                    is_on ? "on" : "off");
                if (is_on) {
                    ahp->ah_stats.ast_ani_ofdmon++;
                } else {
                    ahp->ah_stats.ast_ani_ofdmoff++;
                }
                ani_state->ofdm_weak_sig_detect_off = !is_on;
            }
            break;
        }
    case HAL_ANI_FIRSTEP_LEVEL:
        if (level >= ARRAY_LENGTH(firstep_table)) {
            HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
                "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n",
                __func__, level, (unsigned) ARRAY_LENGTH(firstep_table));
            return AH_FALSE;
        }
        /*
         * make register setting relative to default
         * from INI file & cap value
         */
        value =
            firstep_table[level] -
            firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
            ani_state->ini_def.firstep;
        if (value < HAL_SIG_FIRSTEP_SETTING_MIN) {
            value = HAL_SIG_FIRSTEP_SETTING_MIN;
        }
        if (value > HAL_SIG_FIRSTEP_SETTING_MAX) {
            value = HAL_SIG_FIRSTEP_SETTING_MAX;
        }
        OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value);
        /*
         * we need to set first step low register too
         * make register setting relative to default from INI file & cap value
         */
        value2 =
            firstep_table[level] -
            firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
            ani_state->ini_def.firstep_low;
        if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) {
            value2 = HAL_SIG_FIRSTEP_SETTING_MIN;
        }
        if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) {
            value2 = HAL_SIG_FIRSTEP_SETTING_MAX;
        }
        OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
            AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);

        if (level != ani_state->firstep_level) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
                __func__, chan->ic_freq, ani_state->firstep_level, level,
                HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep);
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: level %d=>%d[def:%d] "
                "firstep_low[level]=%d ini=%d\n",
                __func__, chan->ic_freq, ani_state->firstep_level, level,
                HAL_ANI_DEF_FIRSTEP_LVL, value2,
                ani_state->ini_def.firstep_low);
            if (level > ani_state->firstep_level) {
                ahp->ah_stats.ast_ani_stepup++;
            } else if (level < ani_state->firstep_level) {
                ahp->ah_stats.ast_ani_stepdown++;
            }
            ani_state->firstep_level = level;
        }
        break;
    case HAL_ANI_SPUR_IMMUNITY_LEVEL:
        if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) {
            HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
                "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level "
                "out of range (%u > %u)\n",
                __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table));
            return AH_FALSE;
        }
        /*
         * make register setting relative to default from INI file & cap value
         */
        value =
            cycpwr_thr1_table[level] -
            cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
            ani_state->ini_def.cycpwr_thr1;
        if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) {
            value = HAL_SIG_SPUR_IMM_SETTING_MIN;
        }
        if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) {
            value = HAL_SIG_SPUR_IMM_SETTING_MAX;
        }
        OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value);

        /*
         * set AR_PHY_EXT_CCA for extension channel
         * make register setting relative to default from INI file & cap value
         */
        value2 =
            cycpwr_thr1_table[level] -
            cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
            ani_state->ini_def.cycpwr_thr1_ext;
        if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) {
            value2 = HAL_SIG_SPUR_IMM_SETTING_MIN;
        }
        if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) {
            value2 = HAL_SIG_SPUR_IMM_SETTING_MAX;
        }
        OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2);

        if (level != ani_state->spur_immunity_level) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: level %d=>%d[def:%d] "
                "cycpwr_thr1[level]=%d ini=%d\n",
                __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
                HAL_ANI_DEF_SPUR_IMMUNE_LVL, value,
                ani_state->ini_def.cycpwr_thr1);
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: level %d=>%d[def:%d] "
                "cycpwr_thr1_ext[level]=%d ini=%d\n",
                __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
                HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2,
                ani_state->ini_def.cycpwr_thr1_ext);
            if (level > ani_state->spur_immunity_level) {
                ahp->ah_stats.ast_ani_spurup++;
            } else if (level < ani_state->spur_immunity_level) {
                ahp->ah_stats.ast_ani_spurdown++;
            }
            ani_state->spur_immunity_level = level;
        }
        break;
    case HAL_ANI_MRC_CCK:
        /*
         * is_on == 1 means MRC CCK ON (default, less noise imm)
         * is_on == 0 means MRC CCK is OFF (more noise imm)
         */
        is_on = param ? 1 : 0;
        if (!AR_SREV_POSEIDON(ah)) {
            OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
                AR_PHY_MRC_CCK_ENABLE, is_on);
            OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
                AR_PHY_MRC_CCK_MUX_REG, is_on);
        }
        if (!(is_on != ani_state->mrc_cck_off)) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq,
                !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off");
            if (is_on) {
                ahp->ah_stats.ast_ani_ccklow++;
            } else {
                ahp->ah_stats.ast_ani_cckhigh++;
            }
            ani_state->mrc_cck_off = !is_on;
        }
        break;
    case HAL_ANI_PRESENT:
        break;
#ifdef AH_PRIVATE_DIAG
    case HAL_ANI_MODE:
        if (param == 0) {
            ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI;
            /* Turn off HW counters if we have them */
            ar9300_ani_detach(ah);
            if (AH_PRIVATE(ah)->ah_curchan == NULL) {
                return AH_TRUE;
            }
            /* if we're turning off ANI, reset regs back to INI settings */
            if (ah->ah_config.ath_hal_enable_ani) {
                HAL_ANI_CMD savefunc = ahp->ah_ani_function;
                /* temporarly allow all functions so we can reset */
                ahp->ah_ani_function = HAL_ANI_ALL;
                HALDEBUG(ah, HAL_DEBUG_ANI,
                    "%s: disable all ANI functions\n", __func__);
                ar9300_ani_set_odfm_noise_immunity_level(
                    ah, HAL_ANI_OFDM_DEF_LEVEL);
                ar9300_ani_set_cck_noise_immunity_level(
                    ah, HAL_ANI_CCK_DEF_LEVEL);
                ahp->ah_ani_function = savefunc;
            }
        } else {            /* normal/auto mode */
            HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__);
            ahp->ah_proc_phy_err |= HAL_PROCESS_ANI;
            if (AH_PRIVATE(ah)->ah_curchan == NULL) {
                return AH_TRUE;
            }
            ar9300_enable_mib_counters(ah);
            ar9300_ani_reset(ah, AH_FALSE);
            ani_state = ahp->ah_curani;
        }
        HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n",
                 ahp->ah_proc_phy_err);
        break;
    case HAL_ANI_PHYERR_RESET:
        ahp->ah_stats.ast_ani_ofdmerrs = 0;
        ahp->ah_stats.ast_ani_cckerrs = 0;
        break;
#endif /* AH_PRIVATE_DIAG */
    default:
#if HAL_ANI_DEBUG
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: invalid cmd 0x%02x (allowed=0x%02x)\n",
            __func__, cmd, ahp->ah_ani_function);
#endif
        return AH_FALSE;
    }

#if HAL_ANI_DEBUG
    HALDEBUG(ah, HAL_DEBUG_ANI,
        "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d "
        "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n",
        __func__, ani_state->spur_immunity_level,
        !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
        ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off",
        ani_state->listen_time, ani_state->cycle_count,
        ani_state->listen_time, ani_state->ofdm_phy_err_count,
        ani_state->cck_phy_err_count);
#endif

#ifndef REMOVE_PKT_LOG
    /* do pktlog */
    {
        struct log_ani log_data;

        /* Populate the ani log record */
        log_data.phy_stats_disable = DO_ANI(ah);
        log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level;
        log_data.spur_immun_lvl = ani_state->spur_immunity_level;
        log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off;
        log_data.cck_weak_thr = ani_state->cck_noise_immunity_level;
        log_data.fir_lvl = ani_state->firstep_level;
        log_data.listen_time = ani_state->listen_time;
        log_data.cycle_count = ani_state->cycle_count;
        /* express ofdm_phy_err_count as errors/second */
        log_data.ofdm_phy_err_count = ani_state->listen_time ?
            ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0;
        /* express cck_phy_err_count as errors/second */
        log_data.cck_phy_err_count =  ani_state->listen_time ?
            ani_state->cck_phy_err_count * 1000 / ani_state->listen_time  : 0;
        log_data.rssi = ani_state->rssi;

        /* clear interrupt context flag */
        ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0);
    }
#endif

    return AH_TRUE;
}
/*
 * Restore the ANI parameters in the HAL and reset the statistics.
 * This routine should be called for every hardware reset and for
 * every channel change.
 */
void
ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;
    const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
    int index;

    HALASSERT(chan != AH_NULL);

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

    /*
     * we need to re-point to the correct ANI state since the channel
     * may have changed due to a fast channel change
    */
    index = ar9300_get_ani_channel_index(ah, chan);
    ani_state = &ahp->ah_ani[index];
    HALASSERT(ani_state != AH_NULL);
    ahp->ah_curani = ani_state;

    ahp->ah_stats.ast_ani_reset++;

    ani_state->phy_noise_spur = 0;

    /* only allow a subset of functions in AP mode */
    if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
        if (IS_CHAN_2GHZ(ichan)) {
            ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL |
                                    HAL_ANI_FIRSTEP_LEVEL |
                                    HAL_ANI_MRC_CCK);
        } else {
            ahp->ah_ani_function = 0;
        }
    }
    /* always allow mode (on/off) to be controlled */
    ahp->ah_ani_function |= HAL_ANI_MODE;

    if (is_scanning ||
        (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA &&
         AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS))
    {
        /*
         * If we're scanning or in AP mode, the defaults (ini) should be
         * in place.
         * For an AP we assume the historical levels for this channel are
         * probably outdated so start from defaults instead.
         */
        if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL ||
            ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL)
        {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: Restore defaults: opmode %u chan %d Mhz/0x%x "
                "is_scanning=%d restore=%d ofdm:%d cck:%d\n",
                __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
                chan->ic_flags, is_scanning, ani_state->must_restore,
                ani_state->ofdm_noise_immunity_level,
                ani_state->cck_noise_immunity_level);
            /*
             * for STA/IBSS, we want to restore the historical values later
             * (when we're not scanning)
             */
            if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA ||
                AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS)
            {
                ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
                    HAL_ANI_DEF_SPUR_IMMUNE_LVL);
                ar9300_ani_control(
                    ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL);
                ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
                    HAL_ANI_USE_OFDM_WEAK_SIG);
                ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK);
                ani_state->must_restore = AH_TRUE;
            } else {
                ar9300_ani_set_odfm_noise_immunity_level(
                    ah, HAL_ANI_OFDM_DEF_LEVEL);
                ar9300_ani_set_cck_noise_immunity_level(
                    ah, HAL_ANI_CCK_DEF_LEVEL);
            }
        }
    } else {
        /*
         * restore historical levels for this channel
         */
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d "
            "restore=%d ofdm:%d cck:%d\n",
            __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
            chan->ic_flags, is_scanning, ani_state->must_restore,
            ani_state->ofdm_noise_immunity_level,
            ani_state->cck_noise_immunity_level);
        ar9300_ani_set_odfm_noise_immunity_level(
            ah, ani_state->ofdm_noise_immunity_level);
        ar9300_ani_set_cck_noise_immunity_level(
            ah, ani_state->cck_noise_immunity_level);
        ani_state->must_restore = AH_FALSE;
    }

    /* enable phy counters */
    ar9300_ani_restart(ah);
    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);
}
ar9300_eeprom_t *Ar9300EepromStructGet(void)
{
    struct ath_hal_9300 *ahp = AH9300(AH);
    return & (ahp->ah_eeprom);
}
Beispiel #5
0
/*
 * Return the current statistics.
 */
HAL_ANI_STATS *
ar9300_ani_get_current_stats(struct ath_hal *ah)
{
    return &AH9300(ah)->ah_stats;
}
static inline void
ar9300_init_rate_txpower_ofdm(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
                          u_int8_t rates_array[], int rt_offset,
                          u_int8_t chainmask)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    int16_t twice_array_gain, cdd_power = 0;
    int i, j;
    u_int8_t ofdm_rt_2_pwr_idx[8] =
    {
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_36,
        ALL_TARGET_LEGACY_48,
        ALL_TARGET_LEGACY_54,
    };

    /*
     *  For FCC adjust the upper limit for CDD factoring in the array gain.
     *  The array gain is the same as TxBF, hence reuse the same defines. 
     */
    for (i = rt_offset; i < rt_offset + AR9300_NUM_OFDM_RATES; i++) {

        /* Get the correct OFDM rate to Power table Index */
        j = ofdm_rt_2_pwr_idx[i- rt_offset]; 

        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower[i][0] = rates_array[j];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower[i][1] = rates_array[j];
            if (is_reg_dmn_fcc(ahp->reg_dmn)){
                twice_array_gain = (ahp->twice_antenna_gain >=
                ahp->twice_antenna_reduction)?
                -(AR9300_TXBF_2TX_ARRAY_GAIN) :
                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
               (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
                cdd_power = ahp->upper_limit[1] + twice_array_gain;
                if (ahp->txpower[i][1] > cdd_power){
                    ahp->txpower[i][1] = cdd_power;
                }
            }
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower[i][2] = rates_array[j];
            if (is_reg_dmn_fcc(ahp->reg_dmn)) {
                twice_array_gain =
                (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
                -(AR9300_TXBF_3TX_ARRAY_GAIN):
                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
                (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
                cdd_power = ahp->upper_limit[2] + twice_array_gain;
                if (ahp->txpower[i][2] > cdd_power){
                    ahp->txpower[i][2] = cdd_power;
                }
            } 
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
    }
}
static inline void
ar9300_init_rate_txpower_stbc(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
                        HAL_BOOL is40,
                        int rt_ss_offset, int rt_ds_offset,
                        int rt_ts_offset, u_int8_t chainmask)
{

    struct ath_hal_9300 *ahp = AH9300(ah);
    int i;
    int16_t twice_array_gain, stbc_power = 0;
    u_int8_t mcs_index = 0;

    /* Upper Limit with STBC */
    switch (chainmask) {
    case OSPREY_1_CHAINMASK:
        stbc_power = ahp->upper_limit[0];
        break;
    case OSPREY_2LOHI_CHAINMASK:
    case OSPREY_2LOMID_CHAINMASK:
        stbc_power = ahp->upper_limit[1];
        break;
    case OSPREY_3_CHAINMASK:
        stbc_power = ahp->upper_limit[2];
        /* Ony FCC requires that we back off with 3 transmit chains */
        if (is_reg_dmn_fcc(ahp->reg_dmn)) {
            twice_array_gain =
                (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
                -(AR9300_STBC_3TX_ARRAY_GAIN) :
                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
                (ahp->twice_antenna_gain + AR9300_STBC_3TX_ARRAY_GAIN)), 0));
            stbc_power = ahp->upper_limit[2] + twice_array_gain;
        }
        break;

    default:
        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                 __func__, chainmask);
        break;
    }


    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
            /* 3 TX/1 stream  STBC gain adjustment */
            if (ahp->txpower_stbc[i][2] > stbc_power){
                ahp->txpower_stbc[i][2] = stbc_power;
            }
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
            /* 3 TX/2 stream  STBC gain adjustment */
            if (ahp->txpower_stbc[i][2] > stbc_power){
                ahp->txpower_stbc[i][2] = stbc_power;
	    } 
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    return;
}
static void
ar9300_force_agc_gain(struct ath_hal *ah)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    int i;
    static const struct {
        int rxtx1, rxtx2;
    } chn_reg[AR9300_MAX_CHAINS] = {
        {AR_PHY_65NM_CH0_RXTX1, AR_PHY_65NM_CH0_RXTX2},
        {AR_PHY_65NM_CH1_RXTX1, AR_PHY_65NM_CH1_RXTX2},
        {AR_PHY_65NM_CH2_RXTX1, AR_PHY_65NM_CH2_RXTX2}
    };
    /* 
     * for Osprey 1.0, force Rx gain through long shift (analog) interface
     * this works for Osprey 2.0 too
     * TODO: for Osprey 2.0, we can set gain via baseband registers 
     */
    for (i = 0; i < AR9300_MAX_CHAINS; i++) {
        if (ahp->ah_rx_chainmask & (1 << i)) {
            if (AH_PRIVATE(ah)->ah_curchan != NULL &&
                IS_CHAN_2GHZ(AH_PRIVATE(ah)->ah_curchan)) 
            {
                // For 2G band:
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_RX1DB_BIQUAD_LONG_SHIFT, 0x1);  // 10db=3
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_RX6DB_BIQUAD_LONG_SHIFT, 0x2);  // 10db=2
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_LNAGAIN_LONG_SHIFT,      0x7);  // 10db=6
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_MXRGAIN_LONG_SHIFT,      0x3);  // 10db=3
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_VGAGAIN_LONG_SHIFT,      0x0);  // 10db=0
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx1, 
                    AR_PHY_SCFIR_GAIN_LONG_SHIFT,   0x1);  // 10db=1
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx1, 
                    AR_PHY_MANRXGAIN_LONG_SHIFT,    0x1);  // 10db=1
                /* force external LNA on to disable strong signal mechanism */
                OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), 
                    AR_PHY_SWITCH_TABLE_R0,  0x1); 
                OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), 
                    AR_PHY_SWITCH_TABLE_R1,  0x1); 
                OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), 
                    AR_PHY_SWITCH_TABLE_R12, 0x1); 
            } else {
                // For 5G band:
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_RX1DB_BIQUAD_LONG_SHIFT, 0x2); // was 3=10/15db,
                                                          // 2=+1db
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_RX6DB_BIQUAD_LONG_SHIFT, 0x2); // was 1
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_LNAGAIN_LONG_SHIFT,      0x7);
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_MXRGAIN_LONG_SHIFT,      0x3); // was 2=15db, 3=10db
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx2, 
                    AR_PHY_VGAGAIN_LONG_SHIFT,      0x6);
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx1, 
                    AR_PHY_SCFIR_GAIN_LONG_SHIFT,   0x1);
                OS_REG_RMW_FIELD(ah, chn_reg[i].rxtx1, 
                    AR_PHY_MANRXGAIN_LONG_SHIFT,    0x1);
                /* force external LNA on to disable strong signal mechanism */
                OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), 
                    AR_PHY_SWITCH_TABLE_R0,  0x0); 
                OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), 
                    AR_PHY_SWITCH_TABLE_R1,  0x0); 
                OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN(i), 
                    AR_PHY_SWITCH_TABLE_R12, 0x0); 
            }
        }
    }
}
Beispiel #9
0
int papredistortionSingleTable(struct ath_hal *ah, HAL_CHANNEL *chan, int txChainMask)
{
	int chainNum;
	unsigned int PA_table[24], smallSignalGain; 
    int status = 0, disable_papd=1, chain_fail[3]={0,0,0};
    int paprd_retry_count;

	UserPrint("Run PA predistortion algorithm: txChainMask=0x%X.\n", txChainMask);

    /*
     * Before doing PAPRD training, we must disable pal spare of 
     * hw greeen tx function
     */
	ar9300_hwgreentx_set_pal_spare(AH,0);//ar9300_set_pal_spare(AH,0);
	LinkTransmitPAPDWarmUp(txChainMask);
	status=	ar9300_paprd_init_table(ah, chan);
	if(status==-1)
	{
		ar9300_enable_paprd(ah, AH_FALSE, chan);
		UserPrint("Warning:: PA predistortion failed in InitTable\n");
		return -1;
	}
    {
        struct ath_hal_9300 *ahp = AH9300(ah);
        UserPrint("Training power_x2 is %d, channel %d\n", ahp->paprd_training_power, chan->channel);
    }

	for(chainNum=0; chainNum<3; chainNum++)
	{
		unsigned int i, desired_gain, gain_index;
		if(txChainMask&(1<<chainNum)) 
		{
		    paprd_retry_count = 0;
			while (paprd_retry_count < 5)
		    {
			    ar9300_paprd_setup_gain_table(ah,chainNum);
			    LinkTransmitPAPD(ah, chainNum);
			    ar9300_paprd_is_done(ah);
			    status = ar9300_paprd_create_curve(ah, chan, chainNum);
			    if (status != HAL_EINPROGRESS)
			    {    
			        if(status==0) 
                    {
                        ar9300_populate_paprd_single_table(ah, chan, chainNum);
                        if (!AR_SREV_HONEYBEE(ah) && !AR_SREV_DRAGONFLY(ah)) {
                                if (txChainMask == 0x2 || txChainMask == 0x4){
                                    ar9300_populate_paprd_single_table(ah, chan, 0);
                                }
                        }
                        disable_papd = 0;
                    }
                    else
                    {
                        disable_papd = 1;
                        chain_fail[chainNum] = 1;
                    }
                    break;
                }
                else
                {
                    /* need re-train paprd */
                    paprd_retry_count++;
                }
            }
            if (paprd_retry_count > 5)
                UserPrint("Warning: ch%d PAPRD re-train fail\n", (1 << chainNum));
		}
	}
	if(disable_papd==0)
    {
		ar9300_enable_paprd(ah, AH_TRUE, chan);
        /*
         * restore PAL spare of hw green tx function 
         */
		ar9300_hwgreentx_set_pal_spare(AH,1);
    }
	else
    {
		ar9300_enable_paprd(ah, AH_FALSE, chan);
        UserPrint("Warning:: PA predistortion failed. chain_fail_flag %d %d %d\n", chain_fail[0], chain_fail[1], chain_fail[2]);
        /*
         * restore PAL spare of hw green tx function 
         */
		ar9300_hwgreentx_set_pal_spare(AH,1);
        return -1;
    }

	
	return 0;
}
Beispiel #10
0
void ar9300FillRadiotapHdr(struct ath_hal *ah,
                           struct ah_rx_radiotap_header *rh,
                           struct ah_ppi_data *ppi,
                           struct ath_desc *ds,
                           void *buf_addr)
{
    struct ar9300_rxs *rxsp = AR9300RXS(buf_addr);
    int i, j;

    if (rh != NULL) {
        // Fill out Radiotap header
        OS_MEMZERO(rh, sizeof(struct ah_rx_radiotap_header));

        rh->tsf = ar9300GetTsf64(ah);

        rh->wr_rate = MS(rxsp->status1, AR_RxRate);
        rh->wr_chan_freq = (AH_PRIVATE(ah)->ah_curchan) ? AH_PRIVATE(ah)->ah_curchan->channel : 0;
        // Fill out extended channel info.
        rh->wr_xchannel.freq = rh->wr_chan_freq;
        rh->wr_xchannel.flags = AH_PRIVATE(ah)->ah_curchan->channelFlags;
        rh->wr_xchannel.maxpower = AH_PRIVATE(ah)->ah_curchan->maxRegTxPower;
        rh->wr_xchannel.chan = ath_hal_mhz2ieee(ah, rh->wr_chan_freq, rh->wr_xchannel.flags);

        rh->wr_antsignal = MS(rxsp->status5, AR_RxRSSICombined);

        /* Radiotap Rx flags */
        if (AH9300(ah)->ah_getPlcpHdr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PLCP;
        }
        if (rxsp->status11 & AR_CRCErr) {
            /* for now set both */
            rh->wr_flags |= AH_RADIOTAP_F_BADFCS;
            rh->wr_rx_flags |= AH_RADIOTAP_F_RX_BADFCS;
        }
        if (rxsp->status4 & AR_GI) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_HALFGI;
            rh->wr_mcs.flags |= RADIOTAP_MCS_FLAGS_SHORT_GI;
        }
        if (rxsp->status4 & AR_2040) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_40;
            rh->wr_mcs.flags |= RADIOTAP_MCS_FLAGS_40MHZ;
        }
        if (rxsp->status4 & AR_Parallel40) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_40P;
        }
        if (rxsp->status11 & AR_RxAggr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_AGGR;
        }
        if (rxsp->status11 & AR_RxFirstAggr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_FIRSTAGGR;
        }
        if (rxsp->status11 & AR_RxMoreAggr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_MOREAGGR;
        }
        if (rxsp->status2 & AR_RxMore) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_MORE;
        }
        if (rxsp->status11 & AR_PreDelimCRCErr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PREDELIM_CRCERR;
        }
        if (rxsp->status11 & AR_PostDelimCRCErr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_POSTDELIM_CRCERR;
        }
        if (rxsp->status11 & AR_DecryptCRCErr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_DECRYPTCRCERR;
        }
        if (rxsp->status4 & AR_RxStbc) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_STBC;
        }
        if (rxsp->status11 & AR_PHYErr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PHYERR;
            rh->ath_ext.phyerr_code = MS(rxsp->status11, AR_PHYErrCode);
        }

        /* add the extension part */
        rh->vendor_ext.oui[0] = (ATH_OUI & 0xff);
        rh->vendor_ext.oui[1] = ((ATH_OUI >> 8) & 0xff);
        rh->vendor_ext.oui[2] = ((ATH_OUI >> 16) & 0xff);
        rh->vendor_ext.skip_length = sizeof(struct ah_rx_vendor_radiotap_header);
        /* sub_namespace - simply set to 0 since we don't use multiple namespaces */
        rh->vendor_ext.sub_namespace = 0;

        rh->ath_ext.version = AH_RADIOTAP_VERSION;

        rh->ath_ext.ch_info.num_chains =
            AR9300_NUM_CHAINS(AH9300(ah)->ah_rxchainmask);

        /*
         * Two-pass strategy to fill in RSSI and EVM:
         * First pass: copy the info from each chain from the
         * descriptor into the corresponding index of the
         * radiotap header's ch_info array.
         * Second pass: use the rxchainmask to determine
         * which chains are valid.  Shift ch_info array
         * elements down to fill in indices that were off
         * in the rxchainmask.
         */
        if (rxsp->status11 & AR_PostDelimCRCErr) {
            for (i = 0; i < RADIOTAP_MAX_CHAINS ; i++) {
               rh->ath_ext.ch_info.rssi_ctl[i] = HAL_RSSI_BAD;
               rh->ath_ext.ch_info.rssi_ext[i] = HAL_RSSI_BAD;
            }
        } else {
            rh->ath_ext.ch_info.rssi_ctl[0] = MS(rxsp->status1, AR_RxRSSIAnt00);
            rh->ath_ext.ch_info.rssi_ctl[1] = MS(rxsp->status1, AR_RxRSSIAnt01);
            rh->ath_ext.ch_info.rssi_ctl[2] = MS(rxsp->status1, AR_RxRSSIAnt02);

            rh->ath_ext.ch_info.rssi_ext[0] = MS(rxsp->status5, AR_RxRSSIAnt10);
            rh->ath_ext.ch_info.rssi_ext[1] = MS(rxsp->status5, AR_RxRSSIAnt11);
            rh->ath_ext.ch_info.rssi_ext[2] = MS(rxsp->status5, AR_RxRSSIAnt12);

            rh->ath_ext.ch_info.evm[0] = rxsp->AR_RxEVM0;
            rh->ath_ext.ch_info.evm[1] = rxsp->AR_RxEVM1;
            rh->ath_ext.ch_info.evm[2] = rxsp->AR_RxEVM2;
        }

        for (i = 0, j = 0; i < RADIOTAP_MAX_CHAINS ; i++) {
            if (AH9300(ah)->ah_rxchainmask & (0x1 << i)) {
                /*
                 * This chain is enabled.  Does its data need
                 * to be shifted down into a lower array index?
                 */
                if (i != j) {
                    rh->ath_ext.ch_info.rssi_ctl[j] =
                        rh->ath_ext.ch_info.rssi_ctl[i];
                    rh->ath_ext.ch_info.rssi_ext[j] =
                        rh->ath_ext.ch_info.rssi_ext[i];
                    /*
                     * EVM fields only need to be shifted if PCU_SEL_EVM bit is set.
                     * Otherwise EVM fields hold the value of PLCP headers which
                     * are not related to chainmask.
                     */
                    if (!(AH9300(ah)->ah_getPlcpHdr)) {
                        rh->ath_ext.ch_info.evm[j] = rh->ath_ext.ch_info.evm[i];
                    }
                }
                j++;
            }
        }

        rh->ath_ext.n_delims = MS(rxsp->status2, AR_NumDelim);
    }// if rh != NULL
Beispiel #11
0
//
// save any information required to support calibration
//
static int Ar9300EepromSave()
{
    ar9300_eeprom_t *mptr;        // pointer to data
    int msize;
    unsigned char header[compression_header_length], cheader[compression_header_length], before[compression_header_length];
    char best[MOUTPUT];
    int osize;
    int it;
    ar9300_eeprom_t *dptr;
    int dsize;
    int first;
    int last;
    int ib;
    int bsize;
    int breference;
    int balgorithm;
    int offset[MVALUE],value[MVALUE];
    int overhead;
    ar9300_eeprom_t xptr;
    int nextaddress;
    int major, minor;
    int ccode,creference,cmajor,cminor,clength;
    unsigned short checksum;
    unsigned char csum[2];
    int error;
    int written;
	int ntry;
    unsigned char ones[compression_header_length]={0xff,0xff,0xff,0xff};
    int status;
	int calmem;
	int restored;
	int trysave;
    //
    // get a pointer to the current data structure
    //
    mptr=Ar9300EepromStructGet();
    msize=ar9300_eeprom_struct_size();

	calmem=SaveMemory;
	if(calmem==calibration_data_none)
	{
		calmem=ar9300_calibration_data_get(AH);
	}
	if(calmem==calibration_data_none)
	{
	    if(ar9300_eeprom_size(AH)>0)
		{
			calmem=calibration_data_eeprom;
		}
		else if(ar9300_calibration_data_read_flash(AH, 0x1000, header, 1)==AH_TRUE)
		{
			calmem=calibration_data_flash;
		}
		else
		{
			calmem=calibration_data_otp;
		}
	}

	 // Calculate Checksum
 	checksum=ar9300_compression_checksum((unsigned char*)mptr,msize);
	printf("checksum is %x\n",checksum);
#if AH_BYTE_ORDER == AH_BIG_ENDIAN
//	ar9300_eeprom_t *eeprom_ptr;
//	eeprom_ptr=Ar9300EepromStructGet();
    ar9300_eeprom_template_swap();
    ar9300_swap_eeprom(mptr);
#endif
   
    // For AP with flash calibration data storage save structure uncompressed.
#ifdef MDK_AP
    if(calmem==calibration_data_flash)
    {
        int fd;
        int offset;
        // for(it=0;it<many;it++)
        //    printf("a = %x, data = %x \n",(address-it), buffer[it]);
        if((fd = open("/dev/caldata", O_RDWR)) < 0) {
            perror("Could not open flash\n");
            status = -1 ;
            goto return_status;
        }

        // First 0x1000 are reserved for ethernet mac address and other config writes.
        offset = 0x20000+instance*AR9300_EEPROM_SIZE+FLASH_BASE_CALDATA_OFFSET;  // Need for boards with more than one radio
        lseek(fd, offset, SEEK_SET);
        if (write(fd, mptr, msize) < 1) {
            perror("\nwrite\n");
            status = -2 ;
            goto return_status;
        }
		close(fd);

        status = msize ;
        goto return_status;
    }    
#endif
    
    //
    // try all of our compression schemes, 
    // starting with the assumption that uncompressed is best
    //
    balgorithm=_compress_none;
    breference= -1;
    bsize=msize;
	nextaddress= -1;
    //
	// restore the existing eeprom structure to a temporary buffer
	// because we need it later for several reasons. Returns 0
	// if a default template was loaded because there was no data in memory.
	// Return -1 on error. Otherwise returns the next available address.
	//
#ifdef USE_AQUILA_HAL
 	trysave=ar9300CalibrationDataGet(0);	
 	ar9300CalibrationDataSet(0,calmem);	
#else
	trysave=AH9300(AH)->calibration_data_try;	
	AH9300(AH)->calibration_data_try = calmem;	
#endif
	restored=ar9300_eeprom_restore_internal(AH, &xptr, msize);
	if(restored==0)
	{
		nextaddress= -1;
	}
	else
	{
		nextaddress=restored;
	}
	ar9300_calibration_data_set(AH,calmem);
#ifdef USE_AQUILA_HAL
	ar9300CalibrationDataSet(0,trysave);
#else
	AH9300(AH)->calibration_data_try = trysave;	
#endif
	//
	// do we over write or append
	// if overwrite, move the starting address to the top of the memory
	//
	if((Overwrite && ar9300_eeprom_volatile(AH)) || nextaddress<0)
	{ 
		if(SaveAddress==0)
		{
			nextaddress=ar9300_eeprom_base_address(AH);
		}
		else
		{
			nextaddress=SaveAddress;
		}
	}
    //
	// if compression is requested or if the uncompressed data won't fit
	//
	if(Compress || nextaddress-msize-compression_header_length-compression_checksum_length<=ar9300_eeprom_low_limit(AH))
	{
		//
		// try difference with each standard default structure
		//
		if(TemplateAllowedMany<=0)
		{
			for(it=0; it<ar9300_eeprom_struct_default_many(); it++)
			{
				dptr=ar9300_eeprom_struct_default(it);
				dsize=msize;
				if(dptr!=0 && dsize<MOUTPUT && dsize==msize)
				{
					CheckCompression((char *)mptr,msize,(char *)dptr,dptr->template_version,&balgorithm,&breference,&bsize,best,MOUTPUT);
				}
			}
		}
		else
		{
			for(it=0; it<TemplateAllowedMany; it++)
			{
				dptr=ar9300_eeprom_struct_default_find_by_id(TemplateAllowed[it]);
				dsize=msize;
				if(dptr!=0 && dsize<MOUTPUT && dsize==msize)
				{
					CheckCompression((char *)mptr,msize,(char *)dptr,dptr->template_version,&balgorithm,&breference,&bsize,best,MOUTPUT);
				}
			}
		}
		//
		// also try difference with existing eeprom if it was restored from memory
		//
		if((!(Overwrite && ar9300_eeprom_volatile(AH))) && restored>0 && xptr.eeprom_version==mptr->eeprom_version)
		{
			CheckCompression((char *)mptr,msize,(char *)&xptr,reference_current,&balgorithm,&breference,&bsize,best,MOUTPUT);
		}
	}
    //
    // if the uncompressed size is the smallest, might as well go with it
    //
    if(bsize>=msize)
    {
        balgorithm=_compress_none;
        breference= reference_current;
        bsize=msize;
        memcpy(best,mptr,msize);        // the uncompressed data
		//
		// if using OTP we have to find the first free spot.
		// if using eeprom, we can overwrite
		//
    }
    //
    // Now we know the best method and we have the data, so write it
    //
    ErrorPrint(EepromAlgorithm,balgorithm,breference,bsize,nextaddress);
    if(bsize>0 || restored==0)
    {
        written=0;
        osize=bsize;
		ntry=0;
        while(written==0 &&
			nextaddress-osize-compression_header_length-compression_checksum_length>ar9300_eeprom_low_limit(AH))
        {
			ntry++;
            if(ntry>3)
            {
                ErrorPrint(EepromTooMany);
                status = -2;
                goto return_status;
            }
            //
            // read the spot where we're going to write the header
			// this is so we can check on error if the chip managed to write anything at all
            //
            (void)ar9300_calibration_data_read_array(AH,nextaddress,(unsigned char*)before,compression_header_length);
            //
            // create and write header
            //
            major=NartVersionMajor();
            minor=NartVersionMinor();
            CompressionHeaderPack(header, balgorithm, breference, bsize, major, minor);
            error=CalibrationDataWriteAndVerify(nextaddress,header,compression_header_length);
            if(error==0)
			{
				//
				// write data
				//
				nextaddress-=compression_header_length;
				error=CalibrationDataWriteAndVerify(nextaddress,(unsigned char*)best,osize);
				nextaddress-=osize;
				if(error==0)
				{
					//
					// create and write checksum
					//
					checksum=ar9300_compression_checksum((unsigned char*)best,bsize);
                    csum[0]=checksum&0xff;
                    csum[1]=(checksum>>8)&0xff;
					error=CalibrationDataWriteAndVerify(nextaddress,csum,compression_checksum_length);
					nextaddress-=compression_checksum_length;
					if(error==0)
					{
						//
						// everything written successfully, so we're done
						//
						written=1;
					}
					else
					{
						 //
						 // and try again
						 //
					}
				}
				else
				{
Beispiel #12
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;
}
Beispiel #13
0
/*
 * Enable radar detection and set the radar parameters per the
 * values in pe
 */
void
ar9300_enable_dfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
{
    u_int32_t val;
    struct ath_hal_private  *ahp = AH_PRIVATE(ah);
    HAL_CHANNEL_INTERNAL *ichan = ahp->ah_curchan;
    struct ath_hal_9300 *ah9300 = AH9300(ah);
    bool asleep = ah9300->ah_chip_full_sleep;
    int reg_writes = 0;

    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
        ar9300_set_power_mode(ah, HAL_PM_AWAKE, true);
    }

    val = OS_REG_READ(ah, AR_PHY_RADAR_0);
    val |= AR_PHY_RADAR_0_FFT_ENA | AR_PHY_RADAR_0_ENA;
    if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
        val &= ~AR_PHY_RADAR_0_FIRPWR;
        val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
    }
    if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
        val &= ~AR_PHY_RADAR_0_RRSSI;
        val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
    }
    if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
        val &= ~AR_PHY_RADAR_0_HEIGHT;
        val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
    }
    if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
        val &= ~AR_PHY_RADAR_0_PRSSI;
        if (AR_SREV_AR9580(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {
            if (ah->ah_use_cac_prssi) {
                val |= SM(AR9300_DFS_PRSSI_CAC, AR_PHY_RADAR_0_PRSSI);
            } else {
                val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
            }
        } else {
            val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
        }
    }
    if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
        val &= ~AR_PHY_RADAR_0_INBAND;
        val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
    }
    OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);

    val = OS_REG_READ(ah, AR_PHY_RADAR_1);
    val |= AR_PHY_RADAR_1_MAX_RRSSI | AR_PHY_RADAR_1_BLOCK_CHECK;
    if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
        val &= ~AR_PHY_RADAR_1_MAXLEN;
        val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
    }
    if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
        val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
        val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
    }
    if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
        val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
        val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
    }
    OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);

    if (ath_hal_getcapability(ah, HAL_CAP_EXT_CHAN_DFS, 0, 0) == HAL_OK) {
        val = OS_REG_READ(ah, AR_PHY_RADAR_EXT);
        if (IS_CHAN_HT40(ichan)) {
            /* Enable extension channel radar detection */
            OS_REG_WRITE(ah, AR_PHY_RADAR_EXT, val | AR_PHY_RADAR_EXT_ENA);
        } else {
            /* HT20 mode, disable extension channel radar detect */
            OS_REG_WRITE(ah, AR_PHY_RADAR_EXT, val & ~AR_PHY_RADAR_EXT_ENA);
        }
    }
    /*
        apply DFS postamble array from INI
        column 0 is register ID, column 1 is  HT20 value, colum2 is HT40 value
    */

    if (AR_SREV_AR9580(ah) || AR_SREV_WASP(ah) || AR_SREV_OSPREY_22(ah) || AR_SREV_SCORPION(ah)) {
        REG_WRITE_ARRAY(&ah9300->ah_ini_dfs,IS_CHAN_HT40(ichan)? 2:1, reg_writes);
    }
#ifdef ATH_HAL_DFS_CHIRPING_FIX_APH128
    HDPRINTF(ah, HAL_DBG_DFS,"DFS change the timing value\n");
    if (AR_SREV_AR9580(ah) && IS_CHAN_HT40(ichan)) {
        OS_REG_WRITE(ah, AR_PHY_TIMING6, 0x3140c00a);	
    }
#endif
    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
        ar9300_set_power_mode(ah, HAL_PM_FULL_SLEEP, true);
    }
}
Beispiel #14
0
/*
 * Take the MHz channel value and set the Channel value
 *
 * ASSUMES: Writes enabled to analog bus
 *
 * Actual Expression,
 *
 * For 2GHz channel,
 * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
 * (freq_ref = 40MHz)
 *
 * For 5GHz channel,
 * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
 * (freq_ref = 40MHz/(24>>amode_ref_sel))
 *
 * For 5GHz channels which are 5MHz spaced,
 * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
 * (freq_ref = 40MHz)
 */
static HAL_BOOL
ar9300_set_channel(struct ath_hal *ah, struct ieee80211_channel *chan)
{
    u_int16_t b_mode, frac_mode = 0, a_mode_ref_sel = 0;
    u_int32_t freq, channel_sel, reg32;
    u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz;
    CHAN_CENTERS centers;
    int load_synth_channel;
#ifdef	AH_DEBUG_ALQ
    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
#endif

    /*
     * Put this behind AH_DEBUG_ALQ for now until the Hornet
     * channel_sel code below is made to work.
     */
#ifdef	AH_DEBUG_ALQ
    OS_MARK(ah, AH_MARK_SETCHANNEL, ichan->channel);
#endif

    ar9300_get_channel_centers(ah, chan, &centers);
    freq = centers.synth_center;

    if (freq < 4800) {     /* 2 GHz, fractional mode */
        b_mode = 1; /* 2 GHz */

        if (AR_SREV_HORNET(ah)) {
#if 0
            u_int32_t ichan =
              ieee80211_mhz2ieee(ah, chan->ic_freq, chan->ic_flags);
            HALASSERT(ichan > 0 && ichan <= 14);
            if (clk_25mhz) {
                channel_sel = ar9300_chansel_xtal_25M[ichan - 1];
            } else {
                channel_sel = ar9300_chansel_xtal_40M[ichan - 1];
            }
#endif
            uint32_t i;

            /*
             * Pay close attention to this bit!
             *
             * We need to map the actual desired synth frequency to
             * one of the channel select array entries.
             *
             * For HT20, it'll align with the channel we select.
             *
             * For HT40 though it won't - the centre frequency
             * will not be the frequency of chan->ic_freq or ichan->freq;
             * it needs to be whatever frequency maps to 'freq'.
             */
            i = ath_hal_mhz2ieee_2ghz(ah, freq);
            HALASSERT(i > 0 && i <= 14);
            if (clk_25mhz) {
                channel_sel = ar9300_chansel_xtal_25M[i - 1];
            } else {
                channel_sel = ar9300_chansel_xtal_40M[i - 1];
            }
        } else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
            u_int32_t channel_frac;
            /* 
             * freq_ref = (40 / (refdiva >> a_mode_ref_sel));
             *     (where refdiva = 1 and amoderefsel = 0)
             * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
             * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
             */
            channel_sel = (freq * 4) / 120;
            channel_frac = (((freq * 4) % 120) * 0x20000) / 120;
            channel_sel = (channel_sel << 17) | (channel_frac);
        } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {
            u_int32_t channel_frac;
            if (clk_25mhz) {
                /* 
                 * freq_ref = (50 / (refdiva >> a_mode_ref_sel));
                 *     (where refdiva = 1 and amoderefsel = 0)
                 * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
                 * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
                 */
                if (AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {
                    /* Doubler is off for Scorpion */
                    channel_sel = (freq * 4) / 75;
                    channel_frac = (((freq * 4) % 75) * 0x20000) / 75;
                } else {
                    channel_sel = (freq * 2) / 75;
                    channel_frac = (((freq * 2) % 75) * 0x20000) / 75;
                }
            } else {
                /* 
                 * freq_ref = (50 / (refdiva >> a_mode_ref_sel));
                 *     (where refdiva = 1 and amoderefsel = 0)
                 * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
                 * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
                 */
                if (AR_SREV_SCORPION(ah)) {
                    /* Doubler is off for Scorpion */
                    channel_sel = (freq * 4) / 120;
                    channel_frac = (((freq * 4) % 120) * 0x20000) / 120;
                } else {
                    channel_sel = (freq * 2) / 120;
                    channel_frac = (((freq * 2) % 120) * 0x20000) / 120;
                }
            }
            channel_sel = (channel_sel << 17) | (channel_frac);
        } else {
            channel_sel = CHANSEL_2G(freq);
        }
    } else {
        b_mode = 0; /* 5 GHz */
        if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && clk_25mhz){
            u_int32_t channel_frac;
            /* 
             * freq_ref = (50 / (refdiva >> amoderefsel));
             *     (refdiva = 1, amoderefsel = 0)
             * ndiv = ((chan_mhz * 2) / 3) / freq_ref;
             * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
             */
            channel_sel = freq / 75 ;
            channel_frac = ((freq % 75) * 0x20000) / 75;
            channel_sel = (channel_sel << 17) | (channel_frac);
        } else {
            channel_sel = CHANSEL_5G(freq);
            /* Doubler is ON, so, divide channel_sel by 2. */
            channel_sel >>= 1;
        }
    }


	/* Enable fractional mode for all channels */
    frac_mode = 1;
    a_mode_ref_sel = 0;
    load_synth_channel = 0;
    
    reg32 = (b_mode << 29);
    OS_REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);

	/* Enable Long shift Select for Synthesizer */
    OS_REG_RMW_FIELD(ah,
        AR_PHY_65NM_CH0_SYNTH4, AR_PHY_SYNTH4_LONG_SHIFT_SELECT, 1);

    /* program synth. setting */
    reg32 =
        (channel_sel       <<  2) |
        (a_mode_ref_sel      << 28) |
        (frac_mode         << 30) |
        (load_synth_channel << 31);
    if (IEEE80211_IS_CHAN_QUARTER(chan)) {
        reg32 += CHANSEL_5G_DOT5MHZ;
    }
    OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
    /* Toggle Load Synth channel bit */
    load_synth_channel = 1;
    reg32 |= load_synth_channel << 31;
    OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);


    AH_PRIVATE(ah)->ah_curchan = chan;

    return AH_TRUE;
}
u_int8_t *ar9300_get_tpc_tables(struct ath_hal *ah)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
    u_int mode = ath_hal_get_curmode(ah, chan);
    const HAL_RATE_TABLE *rt;
    u_int8_t *data;
    struct rate_power_tbl *table;
    int i, j;

    /* Check whether TPC is enabled */
    if (!AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc) {
        ath_hal_printf(ah, "\n TPC Register method in use\n");
        return NULL;
    }
    
    rt = ar9300_get_rate_table(ah, mode);
    HALASSERT(rt != NULL);

    data = (u_int8_t *)ath_hal_malloc(ah,
                       1 + rt->rateCount * sizeof(struct rate_power_tbl));
    if (data == NULL)
        return NULL;

    OS_MEMZERO(data, 1 + rt->rateCount * sizeof(struct rate_power_tbl));
    /* store the rate count at the beginning */
    *data = rt->rateCount;
    table = (struct rate_power_tbl *)&data[1];

    for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
        for (i = 0; i < rt->rateCount; i++) {
            table[i].rateIdx = i;
            table[i].rateCode = rt->info[i].rate_code;
            table[i].rateKbps = rt->info[i].rateKbps;
            switch (j) {
            case 0:
                table[i].chain1 = rt->info[i].rate_code <= 0x87 ? 1 : 0;
                break;
            case 1:
                table[i].chain2 = rt->info[i].rate_code <= 0x8f ? 1 : 0;
                break;
            case 2:
                table[i].chain3 = 1;
                break;
            default:
                break;
            }
            if ((j == 0 && table[i].chain1) ||
                (j == 1 && table[i].chain2) ||
                (j == 2 && table[i].chain3))
                table[i].txpower[j] = ahp->txpower[i][j];
        }
    }


    for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
        for (i = 0; i < rt->rateCount; i++) {
            /* Do not display invalid configurations */
            if ((rt->info[i].rate_code < AR9300_MCS0_RATE_CODE) ||
                (rt->info[i].rate_code > AR9300_MCS23_RATE_CODE) ||
                ar9300_invalid_stbc_cfg(j, rt->info[i].rate_code) == AH_TRUE) {
                continue;
            }

            table[i].stbc = 1;
            table[i].txpower_stbc[j] = ahp->txpower_stbc[i][j];
        }
    }

    return data;
    /* the caller is responsible to free data */
}
Beispiel #16
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
}
extern void
ar9300_adjust_reg_txpower_cdd(struct ath_hal *ah, 
                      u_int8_t power_per_rate[])
                      
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    int16_t twice_array_gain, cdd_power = 0;
    int i;

    /*
     *  Adjust the upper limit for CDD factoring in the array gain .
     *  The array gain is the same as TxBF, hence reuse the same defines. 
     */
    switch (ahp->ah_tx_chainmask) {

    case OSPREY_1_CHAINMASK:
        cdd_power = ahp->upper_limit[0];
        break;
  
    case OSPREY_2LOHI_CHAINMASK:
    case OSPREY_2LOMID_CHAINMASK:
        twice_array_gain =
           (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
           -(AR9300_TXBF_2TX_ARRAY_GAIN) :
           ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
           (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
        cdd_power = ahp->upper_limit[1] + twice_array_gain;
        /* Adjust OFDM legacy rates as well */
        for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power; 
            } 
        }
            
        /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 20*/
        for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_7; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power; 
            } 
        } 

        /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 40*/
        for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_7; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power; 
            } 
        } 
        break;
        
    case OSPREY_3_CHAINMASK:
        twice_array_gain =
            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
            -(AR9300_TXBF_3TX_ARRAY_GAIN) :
            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
            (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
        cdd_power = ahp->upper_limit[2] + twice_array_gain;
        /* Adjust OFDM legacy rates as well */
        for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power; 
            } 
        }
        /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT20 */
        for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_15; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power;
            }
        }

        /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT40 */
        for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_15; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power;
            }
        }

        break;

    default:
        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                 __func__, ahp->ah_tx_chainmask);
        break;
    }

    return;
}
Beispiel #18
0
/*
 * 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;
        }
    }
}
static inline void
ar9300_init_rate_txpower_ht(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
                        HAL_BOOL is40,
                        u_int8_t rates_array[],
                        int rt_ss_offset, int rt_ds_offset,
                        int rt_ts_offset, u_int8_t chainmask)
{

    struct ath_hal_9300 *ahp = AH9300(ah);
    int i, j;
    u_int8_t mcs_index = 0;


    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
        /* Get the correct MCS rate to Power table Index */
        j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
                          mcs_rate_2_pwr_idx_ht20[mcs_index];
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower[i][0] = rates_array[j];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower[i][1] = rates_array[j];
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower[i][2] = rates_array[j];
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
        /* Get the correct MCS rate to Power table Index */
        j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
                                       mcs_rate_2_pwr_idx_ht20[mcs_index];
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower[i][0] = rates_array[j];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower[i][1] = rates_array[j];
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower[i][2] = rates_array[j];
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                         __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
        /* Get the correct MCS rate to Power table Index */
        j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
                                  mcs_rate_2_pwr_idx_ht20[mcs_index];
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower[i][0] = rates_array[j];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower[i][1] = rates_array[j];
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower[i][2] = rates_array[j];
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                 __func__, chainmask);
            break;
        }
        mcs_index++;
    }
}
Beispiel #20
0
/*
 * Return the current ANI state of the channel we're on
 */
struct ar9300_ani_state *
ar9300_ani_get_current_state(struct ath_hal *ah)
{
    return AH9300(ah)->ah_curani;
}
static inline void
ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
                        HAL_BOOL is40,
                        int rt_ss_offset, int rt_ds_offset,
                        int rt_ts_offset, u_int8_t chainmask)
{

    struct ath_hal_9300 *ahp = AH9300(ah);
    int i;
    int16_t twice_array_gain, cdd_power = 0;
    u_int8_t mcs_index = 0;

    /*
     *  Adjust the upper limit for CDD factoring in the array gain .
     *  The array gain is the same as TxBF, hence reuse the same defines. 
     */
    switch (chainmask) {
    case OSPREY_1_CHAINMASK:
        cdd_power = ahp->upper_limit[0];
        break;
  
    case OSPREY_2LOHI_CHAINMASK:
    case OSPREY_2LOMID_CHAINMASK:
        twice_array_gain =
            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
            -(AR9300_TXBF_2TX_ARRAY_GAIN) :
            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
            (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
        cdd_power = ahp->upper_limit[1] + twice_array_gain;
        break;
        
    case OSPREY_3_CHAINMASK:
        twice_array_gain =
            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
            -(AR9300_TXBF_3TX_ARRAY_GAIN) :
            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
            (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
        cdd_power = ahp->upper_limit[2] + twice_array_gain;
        break;

    default:
        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
        break;
    }


    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            break;

        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            /* 2 TX/1 stream  CDD gain adjustment */
            if (ahp->txpower[i][1] > cdd_power){
                ahp->txpower[i][1] = cdd_power;
            } 
            break;
        case OSPREY_3_CHAINMASK:
            /* 3 TX/1 stream  CDD gain adjustment */
            if (ahp->txpower[i][2] > cdd_power){
                ahp->txpower[i][2] = cdd_power;
            }
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            break;
        case OSPREY_3_CHAINMASK:
        /* 3 TX/2 stream  TxBF gain adjustment */
            if (ahp->txpower[i][2] > cdd_power){
                ahp->txpower[i][2] = cdd_power;
            } 
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                 __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    return;

}
Beispiel #22
0
/*
 * Return the current statistics.
 */
struct ar9300_stats *
ar9300_ani_get_current_stats(struct ath_hal *ah)
{
    return &AH9300(ah)->ah_stats;
}
A_INT32 Ar9300ChainMaskReduceGet()
{
	return ar9300EepromGet(AH9300(AH),EEP_CHAIN_MASK_REDUCE);
}
Beispiel #24
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
    }