ath9k_hw: Configure appropriate Tx power when PAPRD fails
authorVasanthakumar Thiagarajan <vasanth@atheros.com>
Wed, 15 Dec 2010 15:30:53 +0000 (07:30 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 16 Dec 2010 20:22:31 +0000 (15:22 -0500)
Target Tx power available in eeprom is for PAPRD. If PAPRD
fails, paprd scale factor needs to be detected from this
target tx power.

Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_paprd.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c

index 0e9ea35f2fb46ef4a49795c07b7517f6e26560c9..f80ec7497d0fc8babcc2446a3f234e033d6fabcd 100644 (file)
@@ -4743,6 +4743,16 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
        } /* end ctl mode checking */
 }
 
+static inline u8 mcsidx_to_tgtpwridx(unsigned int mcs_idx, u8 base_pwridx)
+{
+       u8 mod_idx = mcs_idx % 8;
+
+       if (mod_idx <= 3)
+               return mod_idx ? (base_pwridx + 1) : base_pwridx;
+       else
+               return base_pwridx + 4 * (mcs_idx / 8) + mod_idx - 2;
+}
+
 static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
                                        struct ath9k_channel *chan, u16 cfgCtl,
                                        u8 twiceAntennaReduction,
@@ -4755,7 +4765,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
        u8 targetPowerValT2[ar9300RateSize];
        u8 target_power_val_t2_eep[ar9300RateSize];
        unsigned int i = 0, paprd_scale_factor = 0;
-       u8 pwr_idx, min_pwridx;
+       u8 pwr_idx, min_pwridx = 0;
 
        ar9003_hw_set_target_power_eeprom(ah, chan->channel, targetPowerValT2);
 
@@ -4771,6 +4781,24 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
                                le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20))
                                & AR9300_PAPRD_RATE_MASK;
 
+               paprd_scale_factor = ar9003_get_paprd_scale_factor(ah, chan);
+               min_pwridx = IS_CHAN_HT40(chan) ? ALL_TARGET_HT40_0_8_16 :
+                                                 ALL_TARGET_HT20_0_8_16;
+
+               if (!ah->paprd_table_write_done) {
+                       memcpy(target_power_val_t2_eep, targetPowerValT2,
+                              sizeof(targetPowerValT2));
+                       for (i = 0; i < 24; i++) {
+                               pwr_idx = mcsidx_to_tgtpwridx(i, min_pwridx);
+                               if (ah->paprd_ratemask & (1 << i)) {
+                                       if (targetPowerValT2[pwr_idx] &&
+                                           targetPowerValT2[pwr_idx] ==
+                                           target_power_val_t2_eep[pwr_idx])
+                                               targetPowerValT2[pwr_idx] -=
+                                                       paprd_scale_factor;
+                               }
+                       }
+               }
                memcpy(target_power_val_t2_eep, targetPowerValT2,
                       sizeof(targetPowerValT2));
        }
@@ -4782,10 +4810,6 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
                                           powerLimit);
 
        if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) {
-               paprd_scale_factor = ar9003_get_paprd_scale_factor(ah, chan);
-               min_pwridx = IS_CHAN_HT40(chan) ? ALL_TARGET_HT40_0_8_16 :
-                                                 ALL_TARGET_HT20_0_8_16;
-
                for (i = 0; i < ar9300RateSize; i++) {
                        if ((ah->paprd_ratemask & (1 << i)) &&
                            (abs(targetPowerValT2[i] -
index 26cf31cca3aca6e3d01e18f5278bfd52b426f369..79554c524b68baa6f9bd14a5790160e4e93d5799 100644 (file)
 
 void ar9003_paprd_enable(struct ath_hw *ah, bool val)
 {
+       struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+       struct ath9k_channel *chan = ah->curchan;
+
+       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);
+       }
+
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
                      AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
        if (ah->caps.tx_chainmask & BIT(1))
index 0f373be9ef8c0beded58b721b3a76ef24a219b8e..ddda76fcd18009b5d19036c2019c1cfdfe995008 100644 (file)
@@ -1272,6 +1272,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_mark_phy_inactive(ah);
 
+       ah->paprd_table_write_done = false;
+
        /* Only required on the first reset */
        if (AR_SREV_9271(ah) && ah->htc_reset_init) {
                REG_WRITE(ah,
index 3a6101ba98378232485096da90a83e892407912a..21e37d157d3a514b13ba6838b6c01596c4410496 100644 (file)
@@ -836,6 +836,7 @@ struct ath_hw {
        unsigned int paprd_target_power;
        unsigned int paprd_training_power;
        unsigned int paprd_ratemask;
+       bool paprd_table_write_done;
        u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];
        u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];
        /*
index 4d647169439ceedd0f3f5e9ada05bb364c0ab412..cb53fbb951f1226811ad26a905fed740628a31be 100644 (file)
@@ -533,7 +533,7 @@ set_timer:
        if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
                if (!ah->caldata->paprd_done)
                        ieee80211_queue_work(sc->hw, &sc->paprd_work);
-               else
+               else if (!ah->paprd_table_write_done)
                        ath_paprd_activate(sc);
        }
 }