mt7996_mcu_set_txpower_sku() uploads the per-rate power limit table, but the firmware applies it only after the driver enables the SKU power limit. mt7915 does that in mt7915_mcu_set_sku_en(); mt7996 never does, so the radio keeps the EEPROM target power and the configured tx power has no effect. Add the power control command and enable the table per band in mt7996_run(), as the MediaTek vendor driver does. The backoff table stays disabled. This driver does not build the per-path limits; it pads that part of the message with zeros. Fixes: f75e4779d215 ("wifi: mt76: mt7996: add txpower setting support") Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/main.c | 5 +++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 34 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 23 +++++++++++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 1 + 4 files changed, 63 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index d17d1dbb2038..c04e980f6ee7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -34,6 +34,11 @@ int mt7996_run(struct mt7996_phy *phy) if (ret) return ret; + ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL, + true); + if (ret) + return ret; + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); ieee80211_queue_delayed_work(dev->mphy.hw, &phy->mt76->mac_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index a534d07ea1e8..310ce18ec12c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -5488,6 +5488,40 @@ int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled) sizeof(req), true); } +int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data) +{ + struct mt7996_dev *dev = phy->dev; + struct tx_power_ctrl req = { + .tag = cpu_to_le16(power_ctrl_id), + .len = cpu_to_le16(sizeof(req) - 4), + .power_ctrl_id = power_ctrl_id, + .band_idx = phy->mt76->band_idx, + }; + + switch (power_ctrl_id) { + case UNI_TXPOWER_SKU_POWER_LIMIT_CTRL: + req.sku_enable = !!data; + break; + case UNI_TXPOWER_PERCENTAGE_CTRL: + req.percentage_ctrl_enable = !!data; + break; + case UNI_TXPOWER_PERCENTAGE_DROP_CTRL: + req.power_drop_level = data; + break; + case UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL: + req.bf_backoff_enable = !!data; + break; + case UNI_TXPOWER_ATE_MODE_CTRL: + req.ate_mode_enable = !!data; + break; + default: + return -EINVAL; + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TXPOWER), + &req, sizeof(req), false); +} + int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy) { #define TX_POWER_LIMIT_TABLE_RATE 0 diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 74b70fb6da3d..87573688171b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -1036,8 +1036,31 @@ enum { UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG, }; +struct tx_power_ctrl { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 power_ctrl_id; + union { + bool sku_enable; + bool ate_mode_enable; + bool percentage_ctrl_enable; + bool bf_backoff_enable; + u8 power_drop_level; + }; + u8 band_idx; + u8 rsv[1]; +} __packed; + enum { + UNI_TXPOWER_SKU_POWER_LIMIT_CTRL = 0, + UNI_TXPOWER_PERCENTAGE_CTRL = 1, + UNI_TXPOWER_PERCENTAGE_DROP_CTRL = 2, + UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL = 3, UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4, + UNI_TXPOWER_ATE_MODE_CTRL = 6, }; enum { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 2a0cdb56f822..dcfdcd5975c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -778,6 +778,7 @@ int mt7996_mcu_get_temperature(struct mt7996_phy *phy); int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); +int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data); int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy); int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val); int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, -- 2.47.3