ath9k: improve reliability of the noise floor calibration

SVN-Revision: 22126
This commit is contained in:
Felix Fietkau 2010-07-11 11:56:18 +00:00
parent 581dfd912c
commit b28b2b9590

View file

@ -0,0 +1,399 @@
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -1518,77 +1518,6 @@ static void ar5008_hw_do_getnf(struct at
nfarray[5] = sign_extend(nf, 9);
}
-static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
-{
- struct ath9k_nfcal_hist *h;
- int i, j;
- int32_t val;
- const u32 ar5416_cca_regs[6] = {
- AR_PHY_CCA,
- AR_PHY_CH1_CCA,
- AR_PHY_CH2_CCA,
- AR_PHY_EXT_CCA,
- AR_PHY_CH1_EXT_CCA,
- AR_PHY_CH2_EXT_CCA
- };
- u8 chainmask, rx_chain_status;
-
- rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
- if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
- chainmask = 0x9;
- else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
- if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
- chainmask = 0x1B;
- else
- chainmask = 0x09;
- } else {
- if (rx_chain_status & 0x4)
- chainmask = 0x3F;
- else if (rx_chain_status & 0x2)
- chainmask = 0x1B;
- else
- chainmask = 0x09;
- }
-
- h = ah->nfCalHist;
-
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar5416_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
- REG_WRITE(ah, ar5416_cca_regs[i], val);
- }
- }
-
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_ENABLE_NF);
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-
- for (j = 0; j < 5; j++) {
- if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
- AR_PHY_AGC_CONTROL_NF) == 0)
- break;
- udelay(50);
- }
-
- ENABLE_REGWRITE_BUFFER(ah);
-
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar5416_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (-50) << 1) & 0x1ff);
- REG_WRITE(ah, ar5416_cca_regs[i], val);
- }
- }
-
- REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
-}
-
/*
* Initialize the ANI register values with default (ini) values.
* This routine is called during a (full) hardware reset after
@@ -1666,6 +1595,14 @@ static void ar5008_hw_set_nf_limits(stru
void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+ const u32 ar5416_cca_regs[6] = {
+ AR_PHY_CCA,
+ AR_PHY_CH1_CCA,
+ AR_PHY_CH2_CCA,
+ AR_PHY_EXT_CCA,
+ AR_PHY_CH1_EXT_CCA,
+ AR_PHY_CH2_EXT_CCA
+ };
priv_ops->rf_set_freq = ar5008_hw_set_channel;
priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
@@ -1685,7 +1622,6 @@ void ar5008_hw_attach_phy_ops(struct ath
priv_ops->restore_chainmask = ar5008_restore_chainmask;
priv_ops->set_diversity = ar5008_set_diversity;
priv_ops->do_getnf = ar5008_hw_do_getnf;
- priv_ops->loadnf = ar5008_hw_loadnf;
if (modparam_force_new_ani) {
priv_ops->ani_control = ar5008_hw_ani_control_new;
@@ -1701,4 +1637,5 @@ void ar5008_hw_attach_phy_ops(struct ath
priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
ar5008_hw_set_nf_limits(ah);
+ memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
}
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1050,106 +1050,6 @@ static void ar9003_hw_set_nf_limits(stru
}
/*
- * Find out which of the RX chains are enabled
- */
-static u32 ar9003_hw_get_rx_chainmask(struct ath_hw *ah)
-{
- u32 chain = REG_READ(ah, AR_PHY_RX_CHAINMASK);
- /*
- * The bits [2:0] indicate the rx chain mask and are to be
- * interpreted as follows:
- * 00x => Only chain 0 is enabled
- * 01x => Chain 1 and 0 enabled
- * 1xx => Chain 2,1 and 0 enabled
- */
- return chain & 0x7;
-}
-
-static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
-{
- struct ath9k_nfcal_hist *h;
- unsigned i, j;
- int32_t val;
- const u32 ar9300_cca_regs[6] = {
- AR_PHY_CCA_0,
- AR_PHY_CCA_1,
- AR_PHY_CCA_2,
- AR_PHY_EXT_CCA,
- AR_PHY_EXT_CCA_1,
- AR_PHY_EXT_CCA_2,
- };
- u8 chainmask, rx_chain_status;
- struct ath_common *common = ath9k_hw_common(ah);
-
- rx_chain_status = ar9003_hw_get_rx_chainmask(ah);
-
- chainmask = 0x3F;
- h = ah->nfCalHist;
-
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar9300_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
- REG_WRITE(ah, ar9300_cca_regs[i], val);
- }
- }
-
- /*
- * Load software filtered NF value into baseband internal minCCApwr
- * variable.
- */
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_ENABLE_NF);
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-
- /*
- * Wait for load to complete, should be fast, a few 10s of us.
- * The max delay was changed from an original 250us to 10000us
- * since 250us often results in NF load timeout and causes deaf
- * condition during stress testing 12/12/2009
- */
- for (j = 0; j < 1000; j++) {
- if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
- AR_PHY_AGC_CONTROL_NF) == 0)
- break;
- udelay(10);
- }
-
- /*
- * We timed out waiting for the noisefloor to load, probably due to an
- * in-progress rx. Simply return here and allow the load plenty of time
- * to complete before the next calibration interval. We need to avoid
- * trying to load -50 (which happens below) while the previous load is
- * still in progress as this can cause rx deafness. Instead by returning
- * here, the baseband nf cal will just be capped by our present
- * noisefloor until the next calibration timer.
- */
- if (j == 1000) {
- ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
- "to load: AR_PHY_AGC_CONTROL=0x%x\n",
- REG_READ(ah, AR_PHY_AGC_CONTROL));
- return;
- }
-
- /*
- * Restore maxCCAPower register parameter again so that we're not capped
- * by the median we just loaded. This will be initial (and max) value
- * of next noise floor calibration the baseband does.
- */
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar9300_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (-50) << 1) & 0x1ff);
- REG_WRITE(ah, ar9300_cca_regs[i], val);
- }
- }
-}
-
-/*
* Initialize the ANI register values with default (ini) values.
* This routine is called during a (full) hardware reset after
* all the registers are initialised from the INI.
@@ -1216,6 +1116,14 @@ static void ar9003_hw_ani_cache_ini_regs
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+ const u32 ar9300_cca_regs[6] = {
+ AR_PHY_CCA_0,
+ AR_PHY_CCA_1,
+ AR_PHY_CCA_2,
+ AR_PHY_EXT_CCA,
+ AR_PHY_EXT_CCA_1,
+ AR_PHY_EXT_CCA_2,
+ };
priv_ops->rf_set_freq = ar9003_hw_set_channel;
priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
@@ -1232,10 +1140,10 @@ void ar9003_hw_attach_phy_ops(struct ath
priv_ops->set_diversity = ar9003_hw_set_diversity;
priv_ops->ani_control = ar9003_hw_ani_control;
priv_ops->do_getnf = ar9003_hw_do_getnf;
- priv_ops->loadnf = ar9003_hw_loadnf;
priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
ar9003_hw_set_nf_limits(ah);
+ memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
}
void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -167,6 +167,100 @@ void ath9k_hw_start_nfcal(struct ath_hw
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
}
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ struct ath9k_nfcal_hist *h;
+ unsigned i, j;
+ int32_t val;
+ u8 chainmask;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ chainmask = 0x3F;
+ else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+ chainmask = 0x9;
+ else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
+ if ((ah->rxchainmask & 0x2) || (ah->rxchainmask & 0x4))
+ chainmask = 0x1B;
+ else
+ chainmask = 0x09;
+ } else {
+ if (ah->rxchainmask & 0x4)
+ chainmask = 0x3F;
+ else if (ah->rxchainmask & 0x2)
+ chainmask = 0x1B;
+ else
+ chainmask = 0x09;
+ }
+ h = ah->nfCalHist;
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ val = REG_READ(ah, ah->nf_regs[i]);
+ val &= 0xFFFFFE00;
+ val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+ REG_WRITE(ah, ah->nf_regs[i], val);
+ }
+ }
+
+ /*
+ * Load software filtered NF value into baseband internal minCCApwr
+ * variable.
+ */
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_ENABLE_NF);
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+ /*
+ * Wait for load to complete, should be fast, a few 10s of us.
+ * The max delay was changed from an original 250us to 10000us
+ * since 250us often results in NF load timeout and causes deaf
+ * condition during stress testing 12/12/2009
+ */
+ for (j = 0; j < 1000; j++) {
+ if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+ AR_PHY_AGC_CONTROL_NF) == 0)
+ break;
+ udelay(10);
+ }
+
+ /*
+ * We timed out waiting for the noisefloor to load, probably due to an
+ * in-progress rx. Simply return here and allow the load plenty of time
+ * to complete before the next calibration interval. We need to avoid
+ * trying to load -50 (which happens below) while the previous load is
+ * still in progress as this can cause rx deafness. Instead by returning
+ * here, the baseband nf cal will just be capped by our present
+ * noisefloor until the next calibration timer.
+ */
+ if (j == 1000) {
+ ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
+ "to load: AR_PHY_AGC_CONTROL=0x%x\n",
+ REG_READ(ah, AR_PHY_AGC_CONTROL));
+ return;
+ }
+
+ /*
+ * Restore maxCCAPower register parameter again so that we're not capped
+ * by the median we just loaded. This will be initial (and max) value
+ * of next noise floor calibration the baseband does.
+ */
+ ENABLE_REGWRITE_BUFFER(ah);
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ val = REG_READ(ah, ah->nf_regs[i]);
+ val &= 0xFFFFFE00;
+ val |= (((u32) (-50) << 1) & 0x1ff);
+ REG_WRITE(ah, ah->nf_regs[i], val);
+ }
+ }
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+}
+
+
static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
{
struct ath_common *common = ath9k_hw_common(ah);
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -109,6 +109,7 @@ struct ath9k_pacal_info{
bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
void ath9k_hw_start_nfcal(struct ath_hw *ah);
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
int16_t ath9k_hw_getnf(struct ath_hw *ah,
struct ath9k_channel *chan);
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -264,12 +264,6 @@ static inline void ath9k_hw_do_getnf(str
ath9k_hw_private_ops(ah)->do_getnf(ah, nfarray);
}
-static inline void ath9k_hw_loadnf(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- ath9k_hw_private_ops(ah)->loadnf(ah, chan);
-}
-
static inline bool ath9k_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -510,7 +510,6 @@ struct ath_gen_timer_table {
* AR_RTC_PLL_CONTROL for a given channel
* @setup_calibration: set up calibration
* @iscal_supported: used to query if a type of calibration is supported
- * @loadnf: load noise floor read from each chain on the CCA registers
*
* @ani_reset: reset ANI parameters to default values
* @ani_lower_immunity: lower the noise immunity level. The level controls
@@ -564,7 +563,6 @@ struct ath_hw_private_ops {
bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd,
int param);
void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
- void (*loadnf)(struct ath_hw *ah, struct ath9k_channel *chan);
/* ANI */
void (*ani_reset)(struct ath_hw *ah, bool is_scanning);
@@ -658,6 +656,7 @@ struct ath_hw {
bool need_an_top2_fixup;
u16 tx_trig_level;
+ u32 nf_regs[6];
struct ath_nf_limits nf_2g;
struct ath_nf_limits nf_5g;
u16 rfsilent;