--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/beacon.c
++++ b/drivers/net/wireless/ath/ath9k/beacon.c
+@@ -515,7 +515,7 @@ static void ath_beacon_config_ap(struct
+ sc->sc_flags |= SC_OP_TSF_RESET;
+ ath9k_beacon_init(sc, nexttbtt, intval);
+ sc->beacon.bmisscnt = 0;
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
+ }
+
+@@ -643,7 +643,7 @@ static void ath_beacon_config_sta(struct
+ ath9k_hw_set_sta_beacon_timers(ah, &bs);
+ ah->imask |= ATH9K_INT_BMISS;
+
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
+ }
+
+@@ -679,7 +679,7 @@ static void ath_beacon_config_adhoc(stru
+ ath9k_beacon_init(sc, nexttbtt, intval);
+ sc->beacon.bmisscnt = 0;
+
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
+ }
+
+@@ -821,11 +821,11 @@ void ath9k_set_beaconing_status(struct a
+ if (status) {
+ /* Re-enable beaconing */
+ ah->imask |= ATH9K_INT_SWBA;
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ } else {
+ /* Disable SWBA interrupt */
+ ah->imask &= ~ATH9K_INT_SWBA;
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ tasklet_kill(&sc->bcon_tasklet);
+ ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
+ }
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -151,7 +151,7 @@ static void ath9k_gen_timer_start(struct
+ if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
+ ath9k_hw_disable_interrupts(ah);
+ ah->imask |= ATH9K_INT_GENTIMER;
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
+ }
+ }
+@@ -166,7 +166,7 @@ static void ath9k_gen_timer_stop(struct
+ if (timer_table->timer_mask.val == 0) {
+ ath9k_hw_disable_interrupts(ah);
+ ah->imask &= ~ATH9K_INT_GENTIMER;
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
+ }
+ }
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -273,7 +273,7 @@ static bool ath_complete_reset(struct at
+
+ ath9k_cmn_update_txpow(ah, sc->curtxpow,
+ sc->config.txpowlimit, &sc->curtxpow);
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
+
+ if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) {
+@@ -833,7 +833,7 @@ irqreturn_t ath_isr(int irq, void *dev)
+
+ if (status & ATH9K_INT_RXEOL) {
+ ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ }
+
+ if (status & ATH9K_INT_MIB) {
+@@ -1409,7 +1409,7 @@ static void ath9k_calculate_summary_stat
+ ah->imask &= ~ATH9K_INT_TSFOOR;
+ }
+
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+
+ /* Set up ANI */
+ if (iter_data.naps > 0) {
+@@ -1566,7 +1566,7 @@ static void ath9k_enable_ps(struct ath_s
+ if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+ if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) {
+ ah->imask |= ATH9K_INT_TIM_TIMER;
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ }
+ ath9k_hw_setrxabort(ah, 1);
+ }
+@@ -1586,7 +1586,7 @@ static void ath9k_disable_ps(struct ath_
+ PS_WAIT_FOR_TX_ACK);
+ if (ah->imask & ATH9K_INT_TIM_TIMER) {
+ ah->imask &= ~ATH9K_INT_TIM_TIMER;
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ }
+ }
+
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -1977,7 +1977,7 @@ requeue:
+
+ if (!(ah->imask & ATH9K_INT_RXEOL)) {
+ ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
+- ath9k_hw_set_interrupts(ah, ah->imask);
++ ath9k_hw_set_interrupts(ah);
+ }
+
+ return 0;
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -827,9 +827,9 @@ void ath9k_hw_enable_interrupts(struct a
+ }
+ EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
+
+-void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
++void ath9k_hw_set_interrupts(struct ath_hw *ah)
+ {
+- enum ath9k_int omask = ah->imask;
++ enum ath9k_int ints = ah->imask;
+ u32 mask, mask2;
+ struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
+@@ -837,7 +837,7 @@ void ath9k_hw_set_interrupts(struct ath_
+ if (!(ints & ATH9K_INT_GLOBAL))
+ ath9k_hw_disable_interrupts(ah);
+
+- ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
++ ath_dbg(common, ATH_DBG_INTERRUPT, "New interrupt mask 0x%x\n", ints);
+
+ mask = ints & ATH9K_INT_COMMON;
+ mask2 = 0;
+--- a/drivers/net/wireless/ath/ath9k/mac.h
++++ b/drivers/net/wireless/ath/ath9k/mac.h
+@@ -734,7 +734,7 @@ int ath9k_hw_beaconq_setup(struct ath_hw
+
+ /* Interrupt Handling */
+ bool ath9k_hw_intrpend(struct ath_hw *ah);
+-void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
++void ath9k_hw_set_interrupts(struct ath_hw *ah);
+ void ath9k_hw_enable_interrupts(struct ath_hw *ah);
+ void ath9k_hw_disable_interrupts(struct ath_hw *ah);
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -71,7 +71,6 @@ struct ath_regulatory {
+ char alpha2[2];
+ u16 country_code;
+ u16 max_power_level;
+- u32 tp_scale;
+ u16 current_rd;
+ u16 current_rd_ext;
+ int16_t power_limit;
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -3040,6 +3040,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(st
+ return (pBase->miscConfiguration >> 0x3) & 0x1;
+ case EEP_ANT_DIV_CTL1:
+ return eep->base_ext1.ant_div_control;
++ case EEP_ANTENNA_GAIN_5G:
++ return eep->modalHeader5G.antennaGain;
++ case EEP_ANTENNA_GAIN_2G:
++ return eep->modalHeader2G.antennaGain;
+ default:
+ return 0;
+ }
+@@ -4727,20 +4731,14 @@ static u16 ar9003_hw_get_max_edge_power(
+ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ u8 *pPwrArray, u16 cfgCtl,
+- u8 twiceAntennaReduction,
+- u8 twiceMaxRegulatoryPower,
++ u8 antenna_reduction,
+ u16 powerLimit)
+ {
+- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep;
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
+- static const u16 tpScaleReductionTable[5] = {
+- 0, 3, 6, 9, MAX_RATE_POWER
+- };
+ int i;
+- int16_t twiceLargestAntenna;
+- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
++ u16 scaledPower = 0, minCtlPower;
+ static const u16 ctlModesFor11a[] = {
+ CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
+ };
+@@ -4758,28 +4756,7 @@ static void ar9003_hw_set_power_per_rate
+ bool is2ghz = IS_CHAN_2GHZ(chan);
+
+ ath9k_hw_get_channel_centers(ah, chan, ¢ers);
+-
+- /* Compute TxPower reduction due to Antenna Gain */
+- if (is2ghz)
+- twiceLargestAntenna = pEepData->modalHeader2G.antennaGain;
+- else
+- twiceLargestAntenna = pEepData->modalHeader5G.antennaGain;
+-
+- twiceLargestAntenna = (int16_t)min((twiceAntennaReduction) -
+- twiceLargestAntenna, 0);
+-
+- /*
+- * scaledPower is the minimum of the user input power level
+- * and the regulatory allowed power level
+- */
+- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+-
+- if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
+- maxRegAllowedPower -=
+- (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+- }
+-
+- scaledPower = min(powerLimit, maxRegAllowedPower);
++ scaledPower = powerLimit - antenna_reduction;
+
+ /*
+ * Reduce scaled Power by number of chains active to get
+@@ -4966,7 +4943,6 @@ static inline u8 mcsidx_to_tgtpwridx(uns
+ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
+ struct ath9k_channel *chan, u16 cfgCtl,
+ u8 twiceAntennaReduction,
+- u8 twiceMaxRegulatoryPower,
+ u8 powerLimit, bool test)
+ {
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+@@ -5019,7 +4995,6 @@ static void ath9k_hw_ar9300_set_txpower(
+ ar9003_hw_set_power_per_rate_table(ah, chan,
+ targetPowerValT2, cfgCtl,
+ twiceAntennaReduction,
+- twiceMaxRegulatoryPower,
+ powerLimit);
+
+ if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) {
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -429,7 +429,6 @@ static void ath9k_hw_init_defaults(struc
+
+ regulatory->country_code = CTRY_DEFAULT;
+ regulatory->power_limit = MAX_RATE_POWER;
+- regulatory->tp_scale = ATH9K_TP_SCALE_MAX;
+
+ ah->hw_version.magic = AR5416_MAGIC;
+ ah->hw_version.subvendorid = 0;
+@@ -1396,9 +1395,7 @@ static bool ath9k_hw_chip_reset(struct a
+ static bool ath9k_hw_channel_change(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+ {
+- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath_common *common = ath9k_hw_common(ah);
+- struct ieee80211_channel *channel = chan->chan;
+ u32 qnum;
+ int r;
+
+@@ -1423,14 +1420,7 @@ static bool ath9k_hw_channel_change(stru
+ return false;
+ }
+ ath9k_hw_set_clockrate(ah);
+-
+- ah->eep_ops->set_txpower(ah, chan,
+- ath9k_regd_get_ctl(regulatory, chan),
+- channel->max_antenna_gain * 2,
+- channel->max_power * 2,
+- min((u32) MAX_RATE_POWER,
+- (u32) regulatory->power_limit), false);
+-
++ ath9k_hw_apply_txpower(ah, chan);
+ ath9k_hw_rfbus_done(ah);
+
+ if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
+@@ -2466,23 +2456,56 @@ bool ath9k_hw_disable(struct ath_hw *ah)
+ }
+ EXPORT_SYMBOL(ath9k_hw_disable);
+
++static int get_antenna_gain(struct ath_hw *ah, struct ath9k_channel *chan)
++{
++ enum eeprom_param gain_param;
++
++ if (IS_CHAN_2GHZ(chan))
++ gain_param = EEP_ANTENNA_GAIN_2G;
++ else
++ gain_param = EEP_ANTENNA_GAIN_5G;
++
++ return ah->eep_ops->get_eeprom(ah, gain_param);
++}
++
++void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan)
++{
++ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
++ struct ieee80211_channel *channel;
++ int chan_pwr, new_pwr, max_gain;
++ int ant_gain, ant_reduction = 0;
++
++ if (!chan)
++ return;
++
++ channel = chan->chan;
++ chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
++ new_pwr = min_t(int, chan_pwr, reg->power_limit);
++ max_gain = new_pwr - chan_pwr + channel->max_antenna_gain * 2;
++
++ ant_gain = get_antenna_gain(ah, chan);
++ if (ant_gain > max_gain)
++ ant_reduction = ant_gain - max_gain;
++
++ ah->eep_ops->set_txpower(ah, chan,
++ ath9k_regd_get_ctl(reg, chan),
++ ant_reduction, new_pwr, false);
++}
++
+ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
+ {
+- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
++ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
+ struct ath9k_channel *chan = ah->curchan;
+ struct ieee80211_channel *channel = chan->chan;
+- int reg_pwr = min_t(int, MAX_RATE_POWER, limit);
+- int chan_pwr = channel->max_power * 2;
+
++ reg->power_limit = min_t(int, limit, MAX_RATE_POWER);
+ if (test)
+- reg_pwr = chan_pwr = MAX_RATE_POWER;
++ channel->max_power = MAX_RATE_POWER / 2;
+
+- regulatory->power_limit = reg_pwr;
++ ath9k_hw_apply_txpower(ah, chan);
+
+- ah->eep_ops->set_txpower(ah, chan,
+- ath9k_regd_get_ctl(regulatory, chan),
+- channel->max_antenna_gain * 2,
+- chan_pwr, reg_pwr, test);
++ if (test)
++ channel->max_power = DIV_ROUND_UP(reg->max_power_level, 2);
+ }
+ EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
+
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -389,14 +389,6 @@ enum ath9k_power_mode {
+ ATH9K_PM_UNDEFINED
+ };
+
+-enum ath9k_tp_scale {
+- ATH9K_TP_SCALE_MAX = 0,
+- ATH9K_TP_SCALE_50,
+- ATH9K_TP_SCALE_25,
+- ATH9K_TP_SCALE_12,
+- ATH9K_TP_SCALE_MIN
+-};
+-
+ enum ser_reg_mode {
+ SER_REG_MODE_OFF = 0,
+ SER_REG_MODE_ON = 1,
+@@ -964,6 +956,7 @@ void ath9k_hw_htc_resetinit(struct ath_h
+ /* PHY */
+ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
+ u32 *coef_mantissa, u32 *coef_exponent);
++void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan);
+
+ /*
+ * Code Specific to AR5008, AR9001 or AR9002,
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -350,6 +350,8 @@ static u32 ath9k_hw_4k_get_eeprom(struct
+ return pModal->antdiv_ctl1;
+ case EEP_TXGAIN_TYPE:
+ return pBase->txGainType;
++ case EEP_ANTENNA_GAIN_2G:
++ return pModal->antennaGainCh[0];
+ default:
+ return 0;
+ }
+@@ -462,8 +464,7 @@ static void ath9k_hw_set_4k_power_per_ra
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+- u16 AntennaReduction,
+- u16 twiceMaxRegulatoryPower,
++ u16 antenna_reduction,
+ u16 powerLimit)
+ {
+ #define CMP_TEST_GRP \
+@@ -472,20 +473,16 @@ static void ath9k_hw_set_4k_power_per_ra
+ || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
+
+- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ int i;
+- int16_t twiceLargestAntenna;
+ u16 twiceMinEdgePower;
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
+- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
++ u16 scaledPower = 0, minCtlPower;
+ u16 numCtlModes;
+ const u16 *pCtlMode;
+ u16 ctlMode, freq;
+ struct chan_centers centers;
+ struct cal_ctl_data_4k *rep;
+ struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
+- static const u16 tpScaleReductionTable[5] =
+- { 0, 3, 6, 9, MAX_RATE_POWER };
+ struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+ 0, { 0, 0, 0, 0}
+ };
+@@ -503,19 +500,7 @@ static void ath9k_hw_set_4k_power_per_ra
+
+ ath9k_hw_get_channel_centers(ah, chan, ¢ers);
+
+- twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0];
+- twiceLargestAntenna = (int16_t)min(AntennaReduction -
+- twiceLargestAntenna, 0);
+-
+- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+- if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
+- maxRegAllowedPower -=
+- (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+- }
+-
+- scaledPower = min(powerLimit, maxRegAllowedPower);
+- scaledPower = max((u16)0, scaledPower);
+-
++ scaledPower = powerLimit - antenna_reduction;
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+ pCtlMode = ctlModesFor11g;
+
+@@ -671,7 +656,6 @@ static void ath9k_hw_4k_set_txpower(stru
+ struct ath9k_channel *chan,
+ u16 cfgCtl,
+ u8 twiceAntennaReduction,
+- u8 twiceMaxRegulatoryPower,
+ u8 powerLimit, bool test)
+ {
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+@@ -691,7 +675,6 @@ static void ath9k_hw_4k_set_txpower(stru
+ ath9k_hw_set_4k_power_per_rate_table(ah, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+- twiceMaxRegulatoryPower,
+ powerLimit);
+
+ ath9k_hw_set_4k_power_cal_table(ah, chan);
+--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+@@ -336,6 +336,9 @@ static u32 ath9k_hw_ar9287_get_eeprom(st
+ return pBase->tempSensSlopePalOn;
+ else
+ return 0;
++ case EEP_ANTENNA_GAIN_2G:
++ return max_t(u8, pModal->antennaGainCh[0],
++ pModal->antennaGainCh[1]);
+ default:
+ return 0;
+ }
+@@ -554,8 +557,7 @@ static void ath9k_hw_set_ar9287_power_pe
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+- u16 AntennaReduction,
+- u16 twiceMaxRegulatoryPower,
++ u16 antenna_reduction,
+ u16 powerLimit)
+ {
+ #define CMP_CTL \
+@@ -569,12 +571,8 @@ static void ath9k_hw_set_ar9287_power_pe
+ #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6
+ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
+
+- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
+- static const u16 tpScaleReductionTable[5] =
+- { 0, 3, 6, 9, MAX_RATE_POWER };
+ int i;
+- int16_t twiceLargestAntenna;
+ struct cal_ctl_data_ar9287 *rep;
+ struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
+ targetPowerCck = {0, {0, 0, 0, 0} };
+@@ -582,7 +580,7 @@ static void ath9k_hw_set_ar9287_power_pe
+ targetPowerCckExt = {0, {0, 0, 0, 0} };
+ struct cal_target_power_ht targetPowerHt20,
+ targetPowerHt40 = {0, {0, 0, 0, 0} };
+- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
++ u16 scaledPower = 0, minCtlPower;
+ static const u16 ctlModesFor11g[] = {
+ CTL_11B, CTL_11G, CTL_2GHT20,
+ CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
+@@ -597,24 +595,7 @@ static void ath9k_hw_set_ar9287_power_pe
+ tx_chainmask = ah->txchainmask;
+
+ ath9k_hw_get_channel_centers(ah, chan, ¢ers);
+-
+- /* Compute TxPower reduction due to Antenna Gain */
+- twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
+- pEepData->modalHeader.antennaGainCh[1]);
+- twiceLargestAntenna = (int16_t)min((AntennaReduction) -
+- twiceLargestAntenna, 0);
+-
+- /*
+- * scaledPower is the minimum of the user input power level
+- * and the regulatory allowed power level.
+- */
+- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+-
+- if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
+- maxRegAllowedPower -=
+- (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+-
+- scaledPower = min(powerLimit, maxRegAllowedPower);
++ scaledPower = powerLimit - antenna_reduction;
+
+ /*
+ * Reduce scaled Power by number of chains active
+@@ -815,7 +796,6 @@ static void ath9k_hw_set_ar9287_power_pe
+ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
+ struct ath9k_channel *chan, u16 cfgCtl,
+ u8 twiceAntennaReduction,
+- u8 twiceMaxRegulatoryPower,
+ u8 powerLimit, bool test)
+ {
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+@@ -834,7 +814,6 @@ static void ath9k_hw_ar9287_set_txpower(
+ ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+- twiceMaxRegulatoryPower,
+ powerLimit);
+
+ ath9k_hw_set_ar9287_power_cal_table(ah, chan);
+--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
+@@ -400,6 +400,7 @@ static u32 ath9k_hw_def_get_eeprom(struc
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ struct modal_eep_header *pModal = eep->modalHeader;
+ struct base_eep_header *pBase = &eep->baseEepHeader;
++ int band = 0;
+
+ switch (param) {
+ case EEP_NFTHRESH_5:
+@@ -467,6 +468,14 @@ static u32 ath9k_hw_def_get_eeprom(struc
+ return pBase->pwr_table_offset;
+ else
+ return AR5416_PWR_TABLE_OFFSET_DB;
++ case EEP_ANTENNA_GAIN_2G:
++ band = 1;
++ /* fall through */
++ case EEP_ANTENNA_GAIN_5G:
++ return max_t(u8, max_t(u8,
++ pModal[band].antennaGainCh[0],
++ pModal[band].antennaGainCh[1]),
++ pModal[band].antennaGainCh[2]);
+ default:
+ return 0;
+ }
+@@ -986,21 +995,15 @@ static void ath9k_hw_set_def_power_per_r
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+- u16 AntennaReduction,
+- u16 twiceMaxRegulatoryPower,
++ u16 antenna_reduction,
+ u16 powerLimit)
+ {
+ #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
+ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */
+
+- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
+- static const u16 tpScaleReductionTable[5] =
+- { 0, 3, 6, 9, MAX_RATE_POWER };
+-
+ int i;
+- int16_t twiceLargestAntenna;
+ struct cal_ctl_data *rep;
+ struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+ 0, { 0, 0, 0, 0}
+@@ -1012,7 +1015,7 @@ static void ath9k_hw_set_def_power_per_r
+ struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+ 0, {0, 0, 0, 0}
+ };
+- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
++ u16 scaledPower = 0, minCtlPower;
+ static const u16 ctlModesFor11a[] = {
+ CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
+ };
+@@ -1031,27 +1034,7 @@ static void ath9k_hw_set_def_power_per_r
+
+ ath9k_hw_get_channel_centers(ah, chan, ¢ers);
+
+- twiceLargestAntenna = max(
+- pEepData->modalHeader
+- [IS_CHAN_2GHZ(chan)].antennaGainCh[0],
+- pEepData->modalHeader
+- [IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+-
+- twiceLargestAntenna = max((u8)twiceLargestAntenna,
+- pEepData->modalHeader
+- [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+-
+- twiceLargestAntenna = (int16_t)min(AntennaReduction -
+- twiceLargestAntenna, 0);
+-
+- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+-
+- if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
+- maxRegAllowedPower -=
+- (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+- }
+-
+- scaledPower = min(powerLimit, maxRegAllowedPower);
++ scaledPower = powerLimit - antenna_reduction;
+
+ switch (ar5416_get_ntxchains(tx_chainmask)) {
+ case 1:
+@@ -1256,7 +1239,6 @@ static void ath9k_hw_def_set_txpower(str
+ struct ath9k_channel *chan,
+ u16 cfgCtl,
+ u8 twiceAntennaReduction,
+- u8 twiceMaxRegulatoryPower,
+ u8 powerLimit, bool test)
+ {
+ #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
+@@ -1278,7 +1260,6 @@ static void ath9k_hw_def_set_txpower(str
+ ath9k_hw_set_def_power_per_rate_table(ah, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+- twiceMaxRegulatoryPower,
+ powerLimit);
+
+ ath9k_hw_set_def_power_cal_table(ah, chan);
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -763,10 +763,8 @@ static void ar5008_hw_set_channel_regs(s
+ static int ar5008_hw_process_ini(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+ {
+- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath_common *common = ath9k_hw_common(ah);
+ int i, regWrites = 0;
+- struct ieee80211_channel *channel = chan->chan;
+ u32 modesIndex, freqIndex;
+
+ switch (chan->chanmode) {
+@@ -903,14 +901,7 @@ static int ar5008_hw_process_ini(struct
+ ar5008_hw_set_channel_regs(ah, chan);
+ ar5008_hw_init_chain_masks(ah);
+ ath9k_olc_init(ah);
+-
+- /* Set TX power */
+- ah->eep_ops->set_txpower(ah, chan,
+- ath9k_regd_get_ctl(regulatory, chan),
+- channel->max_antenna_gain * 2,
+- channel->max_power * 2,
+- min((u32) MAX_RATE_POWER,
+- (u32) regulatory->power_limit), false);
++ ath9k_hw_apply_txpower(ah, chan);
+
+ /* Write analog registers */
+ if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
+--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+@@ -19,7 +19,6 @@
+
+ void ar9003_paprd_enable(struct ath_hw *ah, bool val)
+ {
+- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath9k_channel *chan = ah->curchan;
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+@@ -54,13 +53,7 @@ void ar9003_paprd_enable(struct ath_hw *
+
+ if (val) {
+ ah->paprd_table_write_done = true;
+-
+- ah->eep_ops->set_txpower(ah, chan,
+- ath9k_regd_get_ctl(regulatory, chan),
+- chan->chan->max_antenna_gain * 2,
+- chan->chan->max_power * 2,
+- min((u32) MAX_RATE_POWER,
+- (u32) regulatory->power_limit), false);
++ ath9k_hw_apply_txpower(ah, chan);
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -628,9 +628,7 @@ static void ar9003_hw_prog_ini(struct at
+ static int ar9003_hw_process_ini(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+ {
+- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ unsigned int regWrites = 0, i;
+- struct ieee80211_channel *channel = chan->chan;
+ u32 modesIndex;
+
+ switch (chan->chanmode) {
+@@ -683,14 +681,7 @@ static int ar9003_hw_process_ini(struct
+ ar9003_hw_override_ini(ah);
+ ar9003_hw_set_channel_regs(ah, chan);
+ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+-
+- /* Set TX power */
+- ah->eep_ops->set_txpower(ah, chan,
+- ath9k_regd_get_ctl(regulatory, chan),
+- channel->max_antenna_gain * 2,
+- channel->max_power * 2,
+- min((u32) MAX_RATE_POWER,
+- (u32) regulatory->power_limit), false);
++ ath9k_hw_apply_txpower(ah, chan);
+
+ return 0;
+ }
+--- a/drivers/net/wireless/ath/ath9k/common.c
++++ b/drivers/net/wireless/ath/ath9k/common.c
+@@ -161,10 +161,12 @@ EXPORT_SYMBOL(ath9k_cmn_count_streams);
+ void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
+ u16 new_txpow, u16 *txpower)
+ {
+- if (cur_txpow != new_txpow) {
++ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
++
++ if (reg->power_limit != new_txpow) {
+ ath9k_hw_set_txpowerlimit(ah, new_txpow, false);
+ /* read back in case value is clamped */
+- *txpower = ath9k_hw_regulatory(ah)->power_limit;
++ *txpower = reg->max_power_level;
+ }
+ }
+ EXPORT_SYMBOL(ath9k_cmn_update_txpow);
+--- a/drivers/net/wireless/ath/ath9k/eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/eeprom.h
+@@ -253,7 +253,9 @@ enum eeprom_param {
+ EEP_PAPRD,
+ EEP_MODAL_VER,
+ EEP_ANT_DIV_CTL1,
+- EEP_CHAIN_MASK_REDUCE
++ EEP_CHAIN_MASK_REDUCE,
++ EEP_ANTENNA_GAIN_2G,
++ EEP_ANTENNA_GAIN_5G
+ };
+
+ enum ar5416_rates {
+@@ -657,8 +659,7 @@ 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,
+- bool test);
++ u8 powerLimit, bool test);
+ u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
+ };
+
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -626,7 +626,6 @@ static void ath9k_init_band_txpower(stru
+ 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];
+@@ -635,7 +634,6 @@ static void ath9k_init_band_txpower(stru
+ 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;
+ }
+ }
+