From 8a97beff9839557b5baf2817e3f201133feeb1df Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Fri, 8 Jun 2018 18:21:57 +0000 Subject: [PATCH] [ath_hal] Return failure if noise floor calibration fails. If we fail noise floor calibration then we may end up with a deaf NIC which we can't recover without a full chip reset. Earlier chips seem to get less stuck in this condition versus AR9280/later and AR9300/later, but whilst here just fix up the AR5212 era chips to also return NF calibration failures. This HAL routine would only return failure if the channel was not configured. This is a no-op until the driver side code for doing resets and the HAL code for being told about the reset type (and then handling it!) is implemented. Tested: * AR9280, STA mode * AR2425, STA mode * AR9380, STA mode --- sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c | 9 +++++++++ .../dev/ath/ath_hal/ar9300/ar9300_freebsd.c | 5 +++++ .../dev/ath/ath_hal/ar9300/ar9300_reset.c | 16 +++++++++++++--- sys/dev/ath/ath_hal/ar5416/ar5416_cal.c | 17 +++++++++++++---- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c index a3e7fae8774..ff22fb80006 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c @@ -1188,6 +1188,15 @@ ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats, cck_phy_err_cnt - ani_state->cck_phy_err_count; ani_state->cck_phy_err_count = cck_phy_err_cnt; + /* + * Note - the ANI code is using the aggregate listen time. + * The AR_PHY_CNT1/AR_PHY_CNT2 registers here are also + * free running, not clear-on-read and are free-running. + * + * So, ofdm_phy_err_rate / cck_phy_err_rate are accumulating + * the same as listenTime is accumulating. + */ + #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c index bf2566c1e74..e066ff28023 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c @@ -704,11 +704,16 @@ ar9300_proc_rx_desc_freebsd(struct ath_hal *ah, struct ath_desc *ds, (void *) ds)); } +/* + * This is the primary way the ANI code gets the node statistics per packet. + */ void ar9300_ani_rxmonitor_freebsd(struct ath_hal *ah, const HAL_NODE_STATS *stats, const struct ieee80211_channel *chan) { + struct ath_hal_9300 *ahp = AH9300(ah); + ahp->ah_stats.ast_nodestats.ns_avgbrssi = stats->ns_avgbrssi; } void diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c index 15eaacde60f..40cdbdd173f 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c @@ -2493,15 +2493,23 @@ ar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; if (nf_done) { + int ret; /* * Load the NF from history buffer of the current channel. * NF is slow time-variant, so it is OK to use a historical value. */ ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); - ar9300_load_nf(ah, nf_buf); - + + ret = ar9300_load_nf(ah, nf_buf); /* start NF calibration, without updating BB NF register*/ - ar9300_start_nf_cal(ah); + ar9300_start_nf_cal(ah); + + /* + * If we failed the NF cal then tell the upper layer that we + * failed so we can do a full reset + */ + if (! ret) + return AH_FALSE; } } return AH_TRUE; @@ -4479,6 +4487,7 @@ First_NFCal(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, ar9300_reset_nf_hist_buff(ah, ichan); ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); ar9300_load_nf(ah, nf_buf); + /* XXX TODO: handle failure from load_nf */ stats = 0; } else { stats = 1; @@ -5303,6 +5312,7 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch /* XXX FreeBSD is ichan appropariate? It was curchan.. */ ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); ar9300_load_nf(ah, nf_buf); + /* XXX TODO: handle NF load failure */ if (nf_hist_buff_reset == 1) { nf_hist_buff_reset = 0; diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c index d4e34db3e9d..106833fe630 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c @@ -36,7 +36,7 @@ #define NUM_NOISEFLOOR_READINGS 6 /* 3 chains * (ctl + ext) */ static void ar5416StartNFCal(struct ath_hal *ah); -static void ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *); +static HAL_BOOL ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *); static int16_t ar5416GetNf(struct ath_hal *, struct ieee80211_channel *); static uint16_t ar5416GetDefaultNF(struct ath_hal *ah, const struct ieee80211_channel *chan); @@ -513,6 +513,7 @@ ar5416PerCalibrationN(struct ath_hal *ah, struct ieee80211_channel *chan, HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: NF calibration" " didn't finish; delaying CCA\n", __func__); } else { + int ret; /* * NF calibration result is valid. * @@ -520,10 +521,17 @@ ar5416PerCalibrationN(struct ath_hal *ah, struct ieee80211_channel *chan, * NF is slow time-variant, so it is OK to use a * historical value. */ - ar5416LoadNF(ah, AH_PRIVATE(ah)->ah_curchan); + ret = ar5416LoadNF(ah, AH_PRIVATE(ah)->ah_curchan); /* start NF calibration, without updating BB NF register*/ ar5416StartNFCal(ah); + + /* + * If we failed calibration then tell the driver + * we failed and it should do a full chip reset + */ + if (! ret) + return AH_FALSE; } } return AH_TRUE; @@ -578,7 +586,7 @@ ar5416StartNFCal(struct ath_hal *ah) OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); } -static void +static HAL_BOOL ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan) { static const uint32_t ar5416_cca_regs[] = { @@ -657,7 +665,7 @@ ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan) HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "Timeout while waiting for " "nf to load: AR_PHY_AGC_CONTROL=0x%x\n", OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); - return; + return AH_FALSE; } /* @@ -679,6 +687,7 @@ ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan) OS_REG_WRITE(ah, ar5416_cca_regs[i], val); } } + return AH_TRUE; } /*