From 24750ea64efc60431fef5f190cfb5f8bdbc6371b Mon Sep 17 00:00:00 2001
From: nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Wed, 20 Oct 2010 00:08:17 +0000
Subject: [PATCH] ath9k: fix tx power display

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@23541 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 .../520-ath9k_ar9003_regulatory_power.patch   |  18 ++
 .../patches/521-ath9k_hw_tx_power.patch       | 279 ++++++++++++++++++
 .../patches/522-ath9k_tx_power_init.patch     | 115 ++++++++
 3 files changed, 412 insertions(+)
 create mode 100644 package/mac80211/patches/520-ath9k_ar9003_regulatory_power.patch
 create mode 100644 package/mac80211/patches/521-ath9k_hw_tx_power.patch
 create mode 100644 package/mac80211/patches/522-ath9k_tx_power_init.patch

diff --git a/package/mac80211/patches/520-ath9k_ar9003_regulatory_power.patch b/package/mac80211/patches/520-ath9k_ar9003_regulatory_power.patch
new file mode 100644
index 000000000..6d0ecef86
--- /dev/null
+++ b/package/mac80211/patches/520-ath9k_ar9003_regulatory_power.patch
@@ -0,0 +1,18 @@
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -2133,6 +2133,7 @@ static void ath9k_hw_ar9300_set_txpower(
+ 					u8 twiceMaxRegulatoryPower,
+ 					u8 powerLimit)
+ {
++	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ 	struct ath_common *common = ath9k_hw_common(ah);
+ 	u8 targetPowerValT2[ar9300RateSize];
+ 	unsigned int i = 0;
+@@ -2180,6 +2181,7 @@ static void ath9k_hw_ar9300_set_txpower(
+ 		i = ALL_TARGET_HT20_0_8_16; /* ht20 */
+ 
+ 	ah->txpower_limit = targetPowerValT2[i];
++	regulatory->max_power_level = ratesArray[i];
+ 
+ 	ar9003_hw_calibration_apply(ah, chan->channel);
+ }
diff --git a/package/mac80211/patches/521-ath9k_hw_tx_power.patch b/package/mac80211/patches/521-ath9k_hw_tx_power.patch
new file mode 100644
index 000000000..b220750c3
--- /dev/null
+++ b/package/mac80211/patches/521-ath9k_hw_tx_power.patch
@@ -0,0 +1,279 @@
+--- a/drivers/net/wireless/ath/ath9k/eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/eeprom.h
+@@ -680,7 +680,8 @@ struct eeprom_ops {
+ 	void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);
+ 	void (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan,
+ 			   u16 cfgCtl, u8 twiceAntennaReduction,
+-			   u8 twiceMaxRegulatoryPower, u8 powerLimit);
++			   u8 twiceMaxRegulatoryPower, u8 powerLimit,
++			   bool test);
+ 	u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
+ };
+ 
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -726,7 +726,7 @@ static void ath9k_hw_4k_set_txpower(stru
+ 				    u16 cfgCtl,
+ 				    u8 twiceAntennaReduction,
+ 				    u8 twiceMaxRegulatoryPower,
+-				    u8 powerLimit)
++				    u8 powerLimit, bool test)
+ {
+ 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ 	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
+@@ -768,6 +768,9 @@ static void ath9k_hw_4k_set_txpower(stru
+ 
+ 	regulatory->max_power_level = ratesArray[i];
+ 
++	if (test)
++	    return;
++
+ 	if (AR_SREV_9280_20_OR_LATER(ah)) {
+ 		for (i = 0; i < Ar5416RateSize; i++)
+ 			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
+--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+@@ -853,7 +853,7 @@ static void ath9k_hw_ar9287_set_txpower(
+ 					struct ath9k_channel *chan, u16 cfgCtl,
+ 					u8 twiceAntennaReduction,
+ 					u8 twiceMaxRegulatoryPower,
+-					u8 powerLimit)
++					u8 powerLimit, bool test)
+ {
+ 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ 	struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+@@ -883,6 +883,16 @@ static void ath9k_hw_ar9287_set_txpower(
+ 			ratesArray[i] = AR9287_MAX_RATE_POWER;
+ 	}
+ 
++	if (IS_CHAN_2GHZ(chan))
++		i = rate1l;
++	else
++		i = rate6mb;
++
++	regulatory->max_power_level = ratesArray[i];
++
++	if (test)
++		return;
++
+ 	if (AR_SREV_9280_20_OR_LATER(ah)) {
+ 		for (i = 0; i < Ar5416RateSize; i++)
+ 			ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
+@@ -971,17 +981,6 @@ static void ath9k_hw_ar9287_set_txpower(
+ 			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+ 			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+ 	}
+-
+-	if (IS_CHAN_2GHZ(chan))
+-		i = rate1l;
+-	else
+-		i = rate6mb;
+-
+-	if (AR_SREV_9280_20_OR_LATER(ah))
+-		regulatory->max_power_level =
+-			ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
+-	else
+-		regulatory->max_power_level = ratesArray[i];
+ }
+ 
+ static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
+--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
+@@ -1258,7 +1258,7 @@ static void ath9k_hw_def_set_txpower(str
+ 				    u16 cfgCtl,
+ 				    u8 twiceAntennaReduction,
+ 				    u8 twiceMaxRegulatoryPower,
+-				    u8 powerLimit)
++				    u8 powerLimit, bool test)
+ {
+ #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
+ 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+@@ -1291,6 +1291,33 @@ static void ath9k_hw_def_set_txpower(str
+ 			ratesArray[i] = AR5416_MAX_RATE_POWER;
+ 	}
+ 
++	i = rate6mb;
++
++	if (IS_CHAN_HT40(chan))
++		i = rateHt40_0;
++	else if (IS_CHAN_HT20(chan))
++		i = rateHt20_0;
++
++	regulatory->max_power_level = ratesArray[i];
++
++	switch(ar5416_get_ntxchains(ah->txchainmask)) {
++	case 1:
++		break;
++	case 2:
++		regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
++		break;
++	case 3:
++		regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
++		break;
++	default:
++		ath_print(ath9k_hw_common(ah), ATH_DBG_EEPROM,
++			  "Invalid chainmask configuration\n");
++		break;
++	}
++
++	if (test)
++		return;
++
+ 	if (AR_SREV_9280_20_OR_LATER(ah)) {
+ 		for (i = 0; i < Ar5416RateSize; i++) {
+ 			int8_t pwr_table_offset;
+@@ -1387,34 +1414,6 @@ static void ath9k_hw_def_set_txpower(str
+ 	REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+ 		  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
+ 		  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+-
+-	i = rate6mb;
+-
+-	if (IS_CHAN_HT40(chan))
+-		i = rateHt40_0;
+-	else if (IS_CHAN_HT20(chan))
+-		i = rateHt20_0;
+-
+-	if (AR_SREV_9280_20_OR_LATER(ah))
+-		regulatory->max_power_level =
+-			ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2;
+-	else
+-		regulatory->max_power_level = ratesArray[i];
+-
+-	switch(ar5416_get_ntxchains(ah->txchainmask)) {
+-	case 1:
+-		break;
+-	case 2:
+-		regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+-		break;
+-	case 3:
+-		regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+-		break;
+-	default:
+-		ath_print(ath9k_hw_common(ah), ATH_DBG_EEPROM,
+-			  "Invalid chainmask configuration\n");
+-		break;
+-	}
+ }
+ 
+ static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -2131,7 +2131,7 @@ static void ath9k_hw_ar9300_set_txpower(
+ 					struct ath9k_channel *chan, u16 cfgCtl,
+ 					u8 twiceAntennaReduction,
+ 					u8 twiceMaxRegulatoryPower,
+-					u8 powerLimit)
++					u8 powerLimit, bool test)
+ {
+ 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ 	struct ath_common *common = ath9k_hw_common(ah);
+@@ -2160,9 +2160,6 @@ static void ath9k_hw_ar9300_set_txpower(
+ 		i++;
+ 	}
+ 
+-	/* Write target power array to registers */
+-	ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
+-
+ 	/*
+ 	 * This is the TX power we send back to driver core,
+ 	 * and it can use to pass to userspace to display our
+@@ -2181,8 +2178,13 @@ static void ath9k_hw_ar9300_set_txpower(
+ 		i = ALL_TARGET_HT20_0_8_16; /* ht20 */
+ 
+ 	ah->txpower_limit = targetPowerValT2[i];
+-	regulatory->max_power_level = ratesArray[i];
++	regulatory->max_power_level = targetPowerValT2[i];
+ 
++	if (test)
++		return;
++
++	/* Write target power array to registers */
++	ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
+ 	ar9003_hw_calibration_apply(ah, chan->channel);
+ }
+ 
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1178,7 +1178,7 @@ static bool ath9k_hw_channel_change(stru
+ 			     channel->max_antenna_gain * 2,
+ 			     channel->max_power * 2,
+ 			     min((u32) MAX_RATE_POWER,
+-			     (u32) regulatory->power_limit));
++			     (u32) regulatory->power_limit), false);
+ 
+ 	ath9k_hw_rfbus_done(ah);
+ 
+@@ -2177,7 +2177,7 @@ bool ath9k_hw_disable(struct ath_hw *ah)
+ }
+ EXPORT_SYMBOL(ath9k_hw_disable);
+ 
+-void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
++void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
+ {
+ 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ 	struct ath9k_channel *chan = ah->curchan;
+@@ -2190,7 +2190,7 @@ void ath9k_hw_set_txpowerlimit(struct at
+ 				 channel->max_antenna_gain * 2,
+ 				 channel->max_power * 2,
+ 				 min((u32) MAX_RATE_POWER,
+-				 (u32) regulatory->power_limit));
++				 (u32) regulatory->power_limit), test);
+ }
+ EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
+ 
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -860,7 +860,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hw *
+ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits);
+ bool ath9k_hw_phy_disable(struct ath_hw *ah);
+ bool ath9k_hw_disable(struct ath_hw *ah);
+-void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
++void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test);
+ void ath9k_hw_setopmode(struct ath_hw *ah);
+ void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
+ void ath9k_hw_setbssidmask(struct ath_hw *ah);
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -24,7 +24,7 @@ static void ath_update_txpow(struct ath_
+ 	struct ath_hw *ah = sc->sc_ah;
+ 
+ 	if (sc->curtxpow != sc->config.txpowlimit) {
+-		ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit);
++		ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
+ 		/* read back in case value is clamped */
+ 		sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
+ 	}
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -614,7 +614,7 @@ static int ar9003_hw_process_ini(struct 
+ 				 channel->max_antenna_gain * 2,
+ 				 channel->max_power * 2,
+ 				 min((u32) MAX_RATE_POWER,
+-				 (u32) regulatory->power_limit));
++				 (u32) regulatory->power_limit), false);
+ 
+ 	return 0;
+ }
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -875,7 +875,7 @@ static int ar5008_hw_process_ini(struct 
+ 				 channel->max_antenna_gain * 2,
+ 				 channel->max_power * 2,
+ 				 min((u32) MAX_RATE_POWER,
+-				 (u32) regulatory->power_limit));
++				 (u32) regulatory->power_limit), false);
+ 
+ 	/* Write analog registers */
+ 	if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
+--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
++++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+@@ -29,7 +29,7 @@ static void ath_update_txpow(struct ath9
+ 	struct ath_hw *ah = priv->ah;
+ 
+ 	if (priv->curtxpow != priv->txpowlimit) {
+-		ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit);
++		ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit, false);
+ 		/* read back in case value is clamped */
+ 		priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
+ 	}
diff --git a/package/mac80211/patches/522-ath9k_tx_power_init.patch b/package/mac80211/patches/522-ath9k_tx_power_init.patch
new file mode 100644
index 000000000..b8138af25
--- /dev/null
+++ b/package/mac80211/patches/522-ath9k_tx_power_init.patch
@@ -0,0 +1,115 @@
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -650,6 +650,37 @@ err_hw:
+ 	return ret;
+ }
+ 
++static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
++{
++	struct ieee80211_supported_band *sband;
++	struct ieee80211_channel *chan;
++	struct ath_hw *ah = sc->sc_ah;
++	struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
++	int i;
++
++	sband = &sc->sbands[band];
++	for (i = 0; i < sband->n_channels; i++) {
++		chan = &sband->channels[i];
++		ah->curchan = &ah->channels[chan->hw_value];
++		ath9k_cmn_update_ichannel(ah->curchan, chan, NL80211_CHAN_HT20);
++		ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true);
++		chan->max_power = reg->max_power_level / 2;
++	}
++}
++
++static void ath9k_init_txpower_limits(struct ath_softc *sc)
++{
++	struct ath_hw *ah = sc->sc_ah;
++	struct ath9k_channel *curchan = ah->curchan;
++
++	if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
++		ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ);
++	if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
++		ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ);
++
++	ah->curchan = curchan;
++}
++
+ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
+ {
+ 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+@@ -765,6 +796,8 @@ int ath9k_init_device(u16 devid, struct 
+ 	if (error != 0)
+ 		goto error_rx;
+ 
++	ath9k_init_txpower_limits(sc);
++
+ 	/* Register with mac80211 */
+ 	error = ieee80211_register_hw(hw);
+ 	if (error)
+--- a/drivers/net/wireless/ath/ath9k/common.c
++++ b/drivers/net/wireless/ath/ath9k/common.c
+@@ -107,12 +107,10 @@ static u32 ath9k_get_extchanmode(struct 
+ /*
+  * Update internal channel flags.
+  */
+-void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
+-			       struct ath9k_channel *ichan)
++void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
++			       struct ieee80211_channel *chan,
++			       enum nl80211_channel_type channel_type)
+ {
+-	struct ieee80211_channel *chan = hw->conf.channel;
+-	struct ieee80211_conf *conf = &hw->conf;
+-
+ 	ichan->channel = chan->center_freq;
+ 	ichan->chan = chan;
+ 
+@@ -124,9 +122,8 @@ void ath9k_cmn_update_ichannel(struct ie
+ 		ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
+ 	}
+ 
+-	if (conf_is_ht(conf))
+-		ichan->chanmode = ath9k_get_extchanmode(chan,
+-							conf->channel_type);
++	if (channel_type != NL80211_CHAN_NO_HT)
++		ichan->chanmode = ath9k_get_extchanmode(chan, channel_type);
+ }
+ EXPORT_SYMBOL(ath9k_cmn_update_ichannel);
+ 
+@@ -142,7 +139,7 @@ struct ath9k_channel *ath9k_cmn_get_curc
+ 
+ 	chan_idx = curchan->hw_value;
+ 	channel = &ah->channels[chan_idx];
+-	ath9k_cmn_update_ichannel(hw, channel);
++	ath9k_cmn_update_ichannel(channel, curchan, hw->conf.channel_type);
+ 
+ 	return channel;
+ }
+--- a/drivers/net/wireless/ath/ath9k/common.h
++++ b/drivers/net/wireless/ath/ath9k/common.h
+@@ -62,8 +62,9 @@ enum ath_stomp_type {
+ 
+ int ath9k_cmn_padpos(__le16 frame_control);
+ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
+-void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
+-			       struct ath9k_channel *ichan);
++void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
++			       struct ieee80211_channel *chan,
++			       enum nl80211_channel_type channel_type);
+ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
+ 					       struct ath_hw *ah);
+ int ath9k_cmn_count_streams(unsigned int chainmask, int max);
+--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
++++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+@@ -1405,7 +1405,9 @@ static int ath9k_htc_config(struct ieee8
+ 		ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
+ 			  curchan->center_freq);
+ 
+-		ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
++		ath9k_cmn_update_ichannel(&priv->ah->channels[pos],
++					  hw->conf.channel,
++					  hw->conf.channel_type);
+ 
+ 		if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
+ 			ath_print(common, ATH_DBG_FATAL,
-- 
2.20.1