ath9k: add TPC to TX path for AR9002 based chips
authorLorenzo Bianconi <lorenzo.bianconi83@gmail.com>
Tue, 30 Dec 2014 22:10:19 +0000 (23:10 +0100)
committerKalle Valo <kvalo@codeaurora.org>
Thu, 15 Jan 2015 12:47:16 +0000 (14:47 +0200)
Add TPC capability to TX descriptor path for AR9002 based chips. Scale
per-packet TX power according to eeprom power bias, power adjustments for
HT40 mode and open loop CCK rates. Cap per-packet TX power according to
TX power per-rate tables

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/ath/ath9k/xmit.c

index 52d63de4a93d319a8640c7f192d758fa3f5a4c78..9c332f9c3fc51c2d7b7d6fe7609214e0f5ba4d95 100644 (file)
@@ -1097,24 +1097,65 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop)
 }
 
 static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
-                              u8 rateidx)
+                              u8 rateidx, bool is_40, bool is_cck)
 {
        u8 max_power;
+       struct sk_buff *skb;
+       struct ath_frame_info *fi;
+       struct ieee80211_tx_info *info;
        struct ath_hw *ah = sc->sc_ah;
 
-       if (sc->tx99_state)
+       if (sc->tx99_state || !ah->tpc_enabled)
                return MAX_RATE_POWER;
 
+       skb = bf->bf_mpdu;
+       fi = get_frame_info(skb);
+       info = IEEE80211_SKB_CB(skb);
+
        if (!AR_SREV_9300_20_OR_LATER(ah)) {
-               /* ar9002 does not support TPC for the moment */
-               return MAX_RATE_POWER;
-       }
+               int txpower = fi->tx_power;
 
-       if (!bf->bf_state.bfs_paprd) {
-               struct sk_buff *skb = bf->bf_mpdu;
-               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-               struct ath_frame_info *fi = get_frame_info(skb);
+               if (is_40) {
+                       u8 power_ht40delta;
+                       struct ar5416_eeprom_def *eep = &ah->eeprom.def;
 
+                       if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) {
+                               bool is_2ghz;
+                               struct modal_eep_header *pmodal;
+
+                               is_2ghz = info->band == IEEE80211_BAND_2GHZ;
+                               pmodal = &eep->modalHeader[is_2ghz];
+                               power_ht40delta = pmodal->ht40PowerIncForPdadc;
+                       } else {
+                               power_ht40delta = 2;
+                       }
+                       txpower += power_ht40delta;
+               }
+
+               if (AR_SREV_9287(ah) || AR_SREV_9285(ah) ||
+                   AR_SREV_9271(ah)) {
+                       txpower -= 2 * AR9287_PWR_TABLE_OFFSET_DB;
+               } else if (AR_SREV_9280_20_OR_LATER(ah)) {
+                       s8 power_offset;
+
+                       power_offset = ah->eep_ops->get_eeprom(ah,
+                                                       EEP_PWR_TABLE_OFFSET);
+                       txpower -= 2 * power_offset;
+               }
+
+               if (OLC_FOR_AR9280_20_LATER && is_cck)
+                       txpower -= 2;
+
+               txpower = max(txpower, 0);
+               max_power = min_t(u8, ah->tx_power[rateidx], txpower);
+
+               /* XXX: clamp minimum TX power at 1 for AR9160 since if
+                * max_power is set to 0, frames are transmitted at max
+                * TX power
+                */
+               if (!max_power && !AR_SREV_9280_20_OR_LATER(ah))
+                       max_power = 1;
+       } else if (!bf->bf_state.bfs_paprd) {
                if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC))
                        max_power = min(ah->tx_power_stbc[rateidx],
                                        fi->tx_power);
@@ -1152,7 +1193,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
        info->rtscts_rate = fi->rtscts_rate;
 
        for (i = 0; i < ARRAY_SIZE(bf->rates); i++) {
-               bool is_40, is_sgi, is_sp;
+               bool is_40, is_sgi, is_sp, is_cck;
                int phy;
 
                if (!rates[i].count || (rates[i].idx < 0))
@@ -1198,7 +1239,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
                        if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
                                info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
 
-                       info->txpower[i] = ath_get_rate_txpower(sc, bf, rix);
+                       info->txpower[i] = ath_get_rate_txpower(sc, bf, rix,
+                                                               is_40, false);
                        continue;
                }
 
@@ -1227,7 +1269,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
                info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
                        phy, rate->bitrate * 100, len, rix, is_sp);
 
-               info->txpower[i] = ath_get_rate_txpower(sc, bf, rix);
+               is_cck = IS_CCK_RATE(info->rates[i].Rate);
+               info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, false,
+                                                       is_cck);
        }
 
        /* For AR5416 - RTS cannot be followed by a frame larger than 8K */