ah->ah_config.ofdm_trig_high = 500;
ah->ah_config.cck_trig_high = 200;
ah->ah_config.cck_trig_low = 100;
- ah->ah_config.enable_ani = 0;
+ ah->ah_config.enable_ani = 1;
ah->ah_config.noise_immunity_level = 4;
ah->ah_config.ofdm_weaksignal_det = 1;
ah->ah_config.cck_weaksignal_thr = 0;
}
}
+/*
+ * Process a MIB interrupt. We may potentially be invoked because
+ * any of the MIB counters overflow/trigger so don't assume we're
+ * here because a PHY error counter triggered.
+ */
void ath9k_hw_procmibevent(struct ath_hal *ah,
const struct ath9k_node_stats *stats)
{
u32 phyCnt1, phyCnt2;
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n");
-
+ /* Reset these counters regardless */
REG_WRITE(ah, AR_FILT_OFDM, 0);
REG_WRITE(ah, AR_FILT_CCK, 0);
if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
+ /* Clear the mib counters and save them in the stats */
ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
ahp->ah_stats.ast_nodestats = *stats;
if (!DO_ANI(ah))
return;
+ /* NB: these are not reset-on-read */
phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
struct ar5416AniState *aniState = ahp->ah_curani;
u32 ofdmPhyErrCnt, cckPhyErrCnt;
+ /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
ahp->ah_stats.ast_ani_ofdmerrs +=
ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
cckPhyErrCnt - aniState->cckPhyErrCount;
aniState->cckPhyErrCount = cckPhyErrCnt;
+ /*
+ * NB: figure out which counter triggered. If both
+ * trigger we'll only deal with one as the processing
+ * clobbers the error counter so the trigger threshold
+ * check will never be true.
+ */
if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
ath9k_hw_ani_ofdm_err_trigger(ah);
if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
ath9k_hw_ani_cck_err_trigger(ah);
-
+ /* NB: always restart to insure the h/w counters are reset */
ath9k_ani_restart(ah);
}
}
bool bChannelChange,
int *status)
{
-#define FAIL(_code) do { ecode = _code; goto bad; } while (0)
u32 saveLedState;
struct ath_hal_5416 *ahp = AH5416(ah);
struct ath9k_channel *curchan = ah->ah_curchan;
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
"%s: invalid channel %u/0x%x; no mapping\n",
__func__, chan->channel, chan->channelFlags);
- FAIL(-EINVAL);
+ ecode = -EINVAL;
+ goto bad;
}
- if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
- return false;
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
+ ecode = -EIO;
+ goto bad;
+ }
if (curchan)
ath9k_hw_getnf(ah, curchan);
if (!ath9k_hw_chip_reset(ah, chan)) {
DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n",
__func__);
- FAIL(-EIO);
+ ecode = -EINVAL;
+ goto bad;
}
if (AR_SREV_9280(ah)) {
}
ecode = ath9k_hw_process_ini(ah, chan, macmode);
- if (ecode != 0)
+ if (ecode != 0) {
+ ecode = -EINVAL;
goto bad;
+ }
if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
ath9k_hw_set_delta_slope(ah, chan);
if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"%s: error setting board options\n", __func__);
- FAIL(-EIO);
+ ecode = -EIO;
+ goto bad;
}
ath9k_hw_decrease_chain_power(ah, chan);
REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
if (AR_SREV_9280_10_OR_LATER(ah)) {
- if (!(ath9k_hw_ar9280_set_channel(ah, chan)))
- FAIL(-EIO);
+ if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
+ ecode = -EIO;
+ goto bad;
+ }
} else {
- if (!(ath9k_hw_set_channel(ah, chan)))
- FAIL(-EIO);
+ if (!(ath9k_hw_set_channel(ah, chan))) {
+ ecode = -EIO;
+ goto bad;
+ }
}
for (i = 0; i < AR_NUM_DCU; i++)
ath9k_hw_init_bb(ah, chan);
- if (!ath9k_hw_init_cal(ah, chan))
- FAIL(-ENODEV);
+ if (!ath9k_hw_init_cal(ah, chan)){
+ ecode = -EIO;;
+ goto bad;
+ }
rx_chainmask = ahp->ah_rxchainmask;
if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
if (status)
*status = ecode;
return false;
-#undef FAIL
}
bool ath9k_hw_phy_disable(struct ath_hal *ah)
}
}
-int16_t
+/* We can tune this as we go by monitoring really low values */
+#define ATH9K_NF_TOO_LOW -60
+
+/* AR5416 may return very high value (like -31 dBm), in those cases the nf
+ * is incorrect and we should use the static NF value. Later we can try to
+ * find out why they are reporting these values */
+static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
+{
+ if (nf > ATH9K_NF_TOO_LOW) {
+ DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+ "%s: noise floor value detected (%d) is "
+ "lower than what we think is a "
+ "reasonable value (%d)\n",
+ __func__, nf, ATH9K_NF_TOO_LOW);
+ return false;
+ }
+ return true;
+}
+
+s16
ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
{
struct ath9k_channel *ichan;
+ s16 nf;
ichan = ath9k_regd_check_channel(ah, chan);
if (ichan == NULL) {
DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
"%s: invalid channel %u/0x%x; no mapping\n",
__func__, chan->channel, chan->channelFlags);
- return 0;
+ return ATH_DEFAULT_NOISE_FLOOR;
}
if (ichan->rawNoiseFloor == 0) {
enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
- return NOISE_FLOOR[mode];
+ nf = NOISE_FLOOR[mode];
} else
- return ichan->rawNoiseFloor;
+ nf = ichan->rawNoiseFloor;
+
+ if (!ath9k_hw_nf_in_range(ah, nf))
+ nf = ATH_DEFAULT_NOISE_FLOOR;
+
+ return nf;
}
bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)