diff options
| -rw-r--r-- | package/mac80211/patches/526-ath9k_improve_nf_cal.patch | 399 | 
1 files changed, 399 insertions, 0 deletions
| diff --git a/package/mac80211/patches/526-ath9k_improve_nf_cal.patch b/package/mac80211/patches/526-ath9k_improve_nf_cal.patch new file mode 100644 index 000000000..2bc11a1d2 --- /dev/null +++ b/package/mac80211/patches/526-ath9k_improve_nf_cal.patch @@ -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; | 
