From aa77eadf0e39ec842b50a9622af5dd7ff2480773 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 18 Jul 2016 20:18:55 +0200 Subject: [PATCH] mt76x2: add TPC support add per-packet tx power adjustment support Signed-off-by: Lorenzo Bianconi --- mt76.h | 1 + mt76x2.h | 4 ++++ mt76x2_mac.c | 7 +++++++ mt76x2_mac.h | 2 ++ mt76x2_main.c | 1 + mt76x2_tx.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 67 insertions(+) diff --git a/mt76.h b/mt76.h index e4e4dee6..7eb92af3 100644 --- a/mt76.h +++ b/mt76.h @@ -126,6 +126,7 @@ struct mt76_wcid { __le16 tx_rate; bool tx_rate_set; u8 tx_rate_nss; + s8 max_txpwr_adj; }; struct mt76_txq { diff --git a/mt76x2.h b/mt76x2.h index 4ddc7405..9b68f179 100644 --- a/mt76x2.h +++ b/mt76x2.h @@ -210,4 +210,8 @@ void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, void mt76x2_update_channel(struct mt76_dev *dev); +s8 mt76x3_tx_get_max_txpwr_adj(struct mt76x2_dev *dev, + const struct ieee80211_tx_rate *rate); +s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj); + #endif diff --git a/mt76x2_mac.c b/mt76x2_mac.c index f8a59c96..4ca13f08 100644 --- a/mt76x2_mac.c +++ b/mt76x2_mac.c @@ -163,6 +163,7 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, u16 rate_ht_mask = MT76_SET(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); u16 txwi_flags = 0; u8 nss; + s8 txpwr_adj, max_txpwr_adj; memset(txwi, 0, sizeof(*txwi)); @@ -176,12 +177,18 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, spin_lock_bh(&dev->mt76.lock); if (rate->idx < 0 || !rate->count) { txwi->rate = wcid->tx_rate; + max_txpwr_adj = wcid->max_txpwr_adj; nss = wcid->tx_rate_nss; } else { txwi->rate = mt76x2_mac_tx_rate_val(dev, rate, &nss); + max_txpwr_adj = mt76x3_tx_get_max_txpwr_adj(dev, rate); } spin_unlock_bh(&dev->mt76.lock); + txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->txpower_conf, + max_txpwr_adj); + txwi->ctl2 = MT76_SET(MT_TX_PWR_ADJ, txpwr_adj); + if (mt76xx_rev(dev) >= MT76XX_REV_E4) txwi->txstream = 0x13; else if (mt76xx_rev(dev) >= MT76XX_REV_E3 && diff --git a/mt76x2_mac.h b/mt76x2_mac.h index 01578652..43dd141b 100644 --- a/mt76x2_mac.h +++ b/mt76x2_mac.h @@ -108,6 +108,8 @@ struct mt76x2_rxwi { #define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0) #define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4) +#define MT_TX_PWR_ADJ GENMASK(3, 0) + enum mt76x2_phy_bandwith { MT_PHY_BW_20, MT_PHY_BW_40, diff --git a/mt76x2_main.c b/mt76x2_main.c index a79e30ea..5ef100f0 100644 --- a/mt76x2_main.c +++ b/mt76x2_main.c @@ -478,6 +478,7 @@ mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rate.idx = rates->rate[0].idx; rate.flags = rates->rate[0].flags; mt76x2_mac_wcid_set_rate(dev, &msta->wcid, &rate); + msta->wcid.max_txpwr_adj = mt76x3_tx_get_max_txpwr_adj(dev, &rate); } static void mt76x2_set_coverage_class(struct ieee80211_hw *hw, diff --git a/mt76x2_tx.c b/mt76x2_tx.c index 5e1c84ac..f832ee07 100644 --- a/mt76x2_tx.c +++ b/mt76x2_tx.c @@ -58,6 +58,58 @@ void mt76x2_tx_complete(struct mt76x2_dev *dev, struct sk_buff *skb) } } +s8 mt76x3_tx_get_max_txpwr_adj(struct mt76x2_dev *dev, + const struct ieee80211_tx_rate *rate) +{ + s8 max_txpwr; + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + u8 mcs = ieee80211_rate_get_vht_mcs(rate); + + if (mcs == 8 || mcs == 9) { + max_txpwr = dev->rate_power.vht[8]; + } else { + u8 nss, idx; + + nss = ieee80211_rate_get_vht_nss(rate); + idx = ((nss - 1) << 3) + mcs; + max_txpwr = dev->rate_power.ht[idx & 0xf]; + } + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + max_txpwr = dev->rate_power.ht[rate->idx & 0xf]; + } else { + enum nl80211_band band = dev->mt76.chandef.chan->band; + + if (band == NL80211_BAND_2GHZ) { + const struct ieee80211_rate *r; + struct wiphy *wiphy = mt76_hw(dev)->wiphy; + struct mt76_rate_power *rp = &dev->rate_power; + + r = &wiphy->bands[band]->bitrates[rate->idx]; + if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) + max_txpwr = rp->cck[r->hw_value & 0x3]; + else + max_txpwr = rp->ofdm[r->hw_value & 0x7]; + } else { + max_txpwr = dev->rate_power.ofdm[rate->idx & 0x7]; + } + } + + return max_txpwr; +} + +s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj) +{ + txpwr = min_t(s8, txpwr, dev->txpower_conf); + txpwr -= (dev->target_power + dev->target_power_delta[0]); + txpwr = min_t(s8, txpwr, max_txpwr_adj); + + if (txpwr >= 0) + return min_t(s8, txpwr, 7); + else + return (txpwr < -16) ? 8 : (txpwr + 32) / 2; +} + int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta,