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); }
/* * 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); } } } }
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; }
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
// // 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 {
/* * 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; }
/* * 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); } }
/* * 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, ¢ers); 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 */ }
/* * 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; }
/* * 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++; } }
/* * 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; }
/* * 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); }
/* * 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 }