mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 07:33:19 +02:00
wifi: mt76: mt7915: enable .sta_set_txpwr support
This adds support for adjusting the Txpower level while pushing traffic to an associated station. The allowed range is from 0 to the maximum power of channel. Signed-off-by: Ryder Lee <ryder.lee@mediatek.com> Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
bd2404d428
commit
66b181b8a9
|
|
@ -355,6 +355,9 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)
|
|||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY);
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
|
||||
|
||||
if (!is_mt7915(&dev->mt76))
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR);
|
||||
|
||||
if (!mdev->dev->of_node ||
|
||||
!of_property_read_bool(mdev->dev->of_node,
|
||||
"mediatek,disable-radar-background"))
|
||||
|
|
|
|||
|
|
@ -1134,6 +1134,39 @@ static void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw,
|
|||
mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
|
||||
}
|
||||
|
||||
static int mt7915_sta_set_txpwr(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct mt7915_phy *phy = mt7915_hw_phy(hw);
|
||||
struct mt7915_dev *dev = mt7915_hw_dev(hw);
|
||||
s16 txpower = sta->deflink.txpwr.power;
|
||||
int ret;
|
||||
|
||||
if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC)
|
||||
txpower = 0;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
/* NOTE: temporarily use 0 as minimum limit, which is a
|
||||
* global setting and will be applied to all stations.
|
||||
*/
|
||||
ret = mt7915_mcu_set_txpower_frame_min(phy, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* This only applies to data frames while pushing traffic,
|
||||
* whereas the management frames or other packets that are
|
||||
* using fixed rate can be configured via TxD.
|
||||
*/
|
||||
ret = mt7915_mcu_set_txpower_frame(phy, vif, sta, txpower);
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = {
|
||||
"tx_ampdu_cnt",
|
||||
"tx_stop_q_empty_cnt",
|
||||
|
|
@ -1499,6 +1532,7 @@ const struct ieee80211_ops mt7915_ops = {
|
|||
.set_bitrate_mask = mt7915_set_bitrate_mask,
|
||||
.set_coverage_class = mt7915_set_coverage_class,
|
||||
.sta_statistics = mt7915_sta_statistics,
|
||||
.sta_set_txpwr = mt7915_sta_set_txpwr,
|
||||
.sta_set_4addr = mt7915_sta_set_4addr,
|
||||
.sta_set_decap_offload = mt7915_sta_set_decap_offload,
|
||||
.add_twt_setup = mt7915_mac_add_twt_setup,
|
||||
|
|
|
|||
|
|
@ -3105,6 +3105,88 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
|
|||
&req, sizeof(req), false);
|
||||
}
|
||||
|
||||
int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower)
|
||||
{
|
||||
struct mt7915_dev *dev = phy->dev;
|
||||
struct {
|
||||
u8 format_id;
|
||||
u8 rsv;
|
||||
u8 band_idx;
|
||||
s8 txpower_min;
|
||||
} __packed req = {
|
||||
.format_id = TX_POWER_LIMIT_FRAME_MIN,
|
||||
.band_idx = phy->band_idx,
|
||||
.txpower_min = txpower * 2, /* 0.5db */
|
||||
};
|
||||
|
||||
return mt76_mcu_send_msg(&dev->mt76,
|
||||
MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
|
||||
sizeof(req), true);
|
||||
}
|
||||
|
||||
int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, s8 txpower)
|
||||
{
|
||||
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
|
||||
struct mt7915_dev *dev = phy->dev;
|
||||
struct mt76_phy *mphy = phy->mt76;
|
||||
struct {
|
||||
u8 format_id;
|
||||
u8 rsv[3];
|
||||
u8 band_idx;
|
||||
s8 txpower_max;
|
||||
__le16 wcid;
|
||||
s8 txpower_offs[48];
|
||||
} __packed req = {
|
||||
.format_id = TX_POWER_LIMIT_FRAME,
|
||||
.band_idx = phy->band_idx,
|
||||
.txpower_max = DIV_ROUND_UP(mphy->txpower_cur, 2),
|
||||
.wcid = cpu_to_le16(msta->wcid.idx),
|
||||
};
|
||||
int ret, n_chains = hweight8(mphy->antenna_mask);
|
||||
s8 txpower_sku[MT7915_SKU_RATE_NUM];
|
||||
|
||||
ret = mt7915_mcu_get_txpower_sku(phy, txpower_sku, sizeof(txpower_sku));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txpower = txpower * 2 - mt76_tx_power_nss_delta(n_chains);
|
||||
if (txpower > mphy->txpower_cur || txpower < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (txpower) {
|
||||
u32 offs, len, i;
|
||||
|
||||
if (sta->deflink.ht_cap.ht_supported) {
|
||||
const u8 *sku_len = mt7915_sku_group_len;
|
||||
|
||||
offs = sku_len[SKU_CCK] + sku_len[SKU_OFDM];
|
||||
len = sku_len[SKU_HT_BW20] + sku_len[SKU_HT_BW40];
|
||||
|
||||
if (sta->deflink.vht_cap.vht_supported) {
|
||||
offs += len;
|
||||
len = sku_len[SKU_VHT_BW20] * 4;
|
||||
|
||||
if (sta->deflink.he_cap.has_he) {
|
||||
offs += len + sku_len[SKU_HE_RU26] * 3;
|
||||
len = sku_len[SKU_HE_RU242] * 4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++, offs++)
|
||||
req.txpower_offs[i] =
|
||||
DIV_ROUND_UP(txpower - txpower_sku[offs], 2);
|
||||
}
|
||||
|
||||
return mt76_mcu_send_msg(&dev->mt76,
|
||||
MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
|
||||
sizeof(req), true);
|
||||
}
|
||||
|
||||
int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
|
||||
{
|
||||
struct mt7915_dev *dev = phy->dev;
|
||||
|
|
@ -3116,7 +3198,7 @@ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
|
|||
u8 dbdc_idx;
|
||||
s8 val[MT7915_SKU_RATE_NUM];
|
||||
} __packed req = {
|
||||
.format_id = 4,
|
||||
.format_id = TX_POWER_LIMIT_TABLE,
|
||||
.dbdc_idx = phy != &dev->phy,
|
||||
};
|
||||
struct mt76_power_limits limits_array;
|
||||
|
|
@ -3166,11 +3248,11 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
|
|||
u8 band;
|
||||
u8 _rsv;
|
||||
} __packed req = {
|
||||
.format_id = 7,
|
||||
.format_id = TX_POWER_LIMIT_INFO,
|
||||
.category = RATE_POWER_INFO,
|
||||
.band = phy != &dev->phy,
|
||||
};
|
||||
s8 res[MT7915_SKU_RATE_NUM][2];
|
||||
s8 txpower_sku[MT7915_SKU_RATE_NUM][2];
|
||||
struct sk_buff *skb;
|
||||
int ret, i;
|
||||
|
||||
|
|
@ -3180,9 +3262,9 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(res, skb->data + 4, sizeof(res));
|
||||
memcpy(txpower_sku, skb->data + 4, sizeof(txpower_sku));
|
||||
for (i = 0; i < len; i++)
|
||||
txpower[i] = res[i][req.band];
|
||||
txpower[i] = txpower_sku[i][req.band_idx];
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
|
|
@ -3220,7 +3302,7 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
|
|||
u8 dbdc_idx;
|
||||
u8 rsv;
|
||||
} __packed req = {
|
||||
.format_id = 0,
|
||||
.format_id = TX_POWER_LIMIT_ENABLE,
|
||||
.dbdc_idx = phy != &dev->phy,
|
||||
.sku_enable = enable,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -419,6 +419,14 @@ enum {
|
|||
#define RATE_CFG_PHY_TYPE GENMASK(27, 24)
|
||||
#define RATE_CFG_HE_LTF GENMASK(31, 28)
|
||||
|
||||
enum {
|
||||
TX_POWER_LIMIT_ENABLE,
|
||||
TX_POWER_LIMIT_TABLE = 0x4,
|
||||
TX_POWER_LIMIT_INFO = 0x7,
|
||||
TX_POWER_LIMIT_FRAME = 0x11,
|
||||
TX_POWER_LIMIT_FRAME_MIN = 0x12,
|
||||
};
|
||||
|
||||
enum {
|
||||
SPR_ENABLE = 0x1,
|
||||
SPR_ENABLE_SD = 0x3,
|
||||
|
|
|
|||
|
|
@ -528,6 +528,10 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band);
|
|||
int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable);
|
||||
int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy);
|
||||
int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len);
|
||||
int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower);
|
||||
int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, s8 txpower);
|
||||
int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action);
|
||||
int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val);
|
||||
int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user