diff mbox series

[2/8] wifi: mt76: mt7996: add txpower setting support

Message ID 20231102100302.22160-2-shayne.chen@mediatek.com
State New
Headers show
Series [1/8] wifi: mt76: change txpower init to per-phy | expand

Commit Message

Shayne Chen Nov. 2, 2023, 10:02 a.m. UTC
Add support for setting txpower from upper layer and configuring per-rate
txpower limit table.

Co-developed-by: Allen Ye <allen.ye@mediatek.com>
Signed-off-by: Allen Ye <allen.ye@mediatek.com>
Co-developed-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
 .../net/wireless/mediatek/mt76/mt7996/main.c  |  8 +++
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   | 58 +++++++++++++++++++
 .../net/wireless/mediatek/mt76/mt7996/mcu.h   | 16 +++++
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  3 +
 4 files changed, 85 insertions(+)

Comments

Ben Greear Dec. 1, 2023, 11:40 p.m. UTC | #1
On 11/2/23 03:02, Shayne Chen wrote:
> Add support for setting txpower from upper layer and configuring per-rate
> txpower limit table.

Hello Shayne,

 From what I can tell, this patch causes STA vdevs to no longer send probe
requests when trying to associate.  I bisected to this in Felix's tree that holds
this patch.

Tested on x86-64, mtk7996 radio.  Specifically
debugged on 2.4Ghz radio, but I think it affects 5Ghz too.

Thanks,
Ben

> 
> Co-developed-by: Allen Ye <allen.ye@mediatek.com>
> Signed-off-by: Allen Ye <allen.ye@mediatek.com>
> Co-developed-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
> Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
> Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
> ---
>   .../net/wireless/mediatek/mt76/mt7996/main.c  |  8 +++
>   .../net/wireless/mediatek/mt76/mt7996/mcu.c   | 58 +++++++++++++++++++
>   .../net/wireless/mediatek/mt76/mt7996/mcu.h   | 16 +++++
>   .../wireless/mediatek/mt76/mt7996/mt7996.h    |  3 +
>   4 files changed, 85 insertions(+)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> index 9f12b47eb2bf..7336eaa7b9ae 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> @@ -396,6 +396,13 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
>   		ieee80211_wake_queues(hw);
>   	}
>   
> +	if (changed & (IEEE80211_CONF_CHANGE_POWER |
> +		       IEEE80211_CONF_CHANGE_CHANNEL)) {
> +		ret = mt7996_mcu_set_txpower_sku(phy);
> +		if (ret)
> +			return ret;
> +	}
> +
>   	mutex_lock(&dev->mt76.mutex);
>   
>   	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
> @@ -965,6 +972,7 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
>   	mt76_set_stream_caps(phy->mt76, true);
>   	mt7996_set_stream_vht_txbf_caps(phy);
>   	mt7996_set_stream_he_eht_caps(phy);
> +	mt7996_mcu_set_txpower_sku(phy);
>   
>   	mutex_unlock(&dev->mt76.mutex);
>   
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> index 8097924d460b..8141c24ade50 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> @@ -4353,3 +4353,61 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id)
>   	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req,
>   				 sizeof(req), true);
>   }
> +
> +int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
> +{
> +#define TX_POWER_LIMIT_TABLE_RATE	0
> +	struct mt7996_dev *dev = phy->dev;
> +	struct mt76_phy *mphy = phy->mt76;
> +	struct ieee80211_hw *hw = mphy->hw;
> +	struct tx_power_limit_table_ctrl {
> +		u8 __rsv1[4];
> +
> +		__le16 tag;
> +		__le16 len;
> +		u8 power_ctrl_id;
> +		u8 power_limit_type;
> +		u8 band_idx;
> +	} __packed req = {
> +		.tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL),
> +		.len = cpu_to_le16(sizeof(req) + MT7996_SKU_RATE_NUM - 4),
> +		.power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL,
> +		.power_limit_type = TX_POWER_LIMIT_TABLE_RATE,
> +		.band_idx = phy->mt76->band_idx,
> +	};
> +	struct mt76_power_limits la = {};
> +	struct sk_buff *skb;
> +	int i, tx_power;
> +
> +	tx_power = mt7996_get_power_bound(phy, hw->conf.power_level);
> +	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
> +					      &la, tx_power);
> +	mphy->txpower_cur = tx_power;
> +
> +	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
> +				 sizeof(req) + MT7996_SKU_RATE_NUM);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	skb_put_data(skb, &req, sizeof(req));
> +	/* cck and ofdm */
> +	skb_put_data(skb, &la.cck, sizeof(la.cck) + sizeof(la.ofdm));
> +	/* ht20 */
> +	skb_put_data(skb, &la.mcs[0], 8);
> +	/* ht40 */
> +	skb_put_data(skb, &la.mcs[1], 9);
> +
> +	/* vht */
> +	for (i = 0; i < 4; i++) {
> +		skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i]));
> +		skb_put_zero(skb, 2);  /* padding */
> +	}
> +
> +	/* he */
> +	skb_put_data(skb, &la.ru[0], sizeof(la.ru));
> +	/* eht */
> +	skb_put_data(skb, &la.eht[0], sizeof(la.eht));
> +
> +	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
> +				     MCU_WM_UNI_CMD(TXPOWER), true);
> +}
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> index a3eae32c8f10..1562c8a6a821 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> @@ -762,6 +762,18 @@ enum {
>   #define MT7996_MAX_BSS_OFFLOAD_SIZE	(MT7996_MAX_BEACON_SIZE +		\
>   					 MT7996_BEACON_UPDATE_SIZE)
>   
> +static inline s8
> +mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower)
> +{
> +	struct mt76_phy *mphy = phy->mt76;
> +	int n_chains = hweight16(mphy->chainmask);
> +
> +	txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2);
> +	txpower -= mt76_tx_power_nss_delta(n_chains);
> +
> +	return txpower;
> +}
> +
>   enum {
>   	UNI_BAND_CONFIG_RADIO_ENABLE,
>   	UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
> @@ -830,6 +842,10 @@ enum {
>   	UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
>   };
>   
> +enum {
> +	UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
> +};
> +
>   enum {
>   	UNI_CMD_ACCESS_REG_BASIC = 0x0,
>   	UNI_CMD_ACCESS_RF_REG_BASIC,
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> index d3eb564623ae..c62a42512bd6 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> @@ -42,6 +42,8 @@
>   #define MT7996_CFEND_RATE_DEFAULT	0x49	/* OFDM 24M */
>   #define MT7996_CFEND_RATE_11B		0x03	/* 11B LP, 11M */
>   
> +#define MT7996_SKU_RATE_NUM		417
> +
>   #define MT7996_MAX_TWT_AGRT		16
>   #define MT7996_MAX_STA_TWT_AGRT		8
>   #define MT7996_MAX_QUEUE		(__MT_RXQ_MAX +	__MT_MCUQ_MAX + 3)
> @@ -471,6 +473,7 @@ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
>   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_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
>   		       u8 rx_sel, u8 val);
>   int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
Shayne Chen Dec. 7, 2023, 5:15 p.m. UTC | #2
On Fri, 2023-12-01 at 15:40 -0800, Ben Greear wrote:
>  	 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>  On 11/2/23 03:02, Shayne Chen wrote:
> > Add support for setting txpower from upper layer and configuring
> per-rate
> > txpower limit table.
> 
> Hello Shayne,

Hi Ben,
> 
>  From what I can tell, this patch causes STA vdevs to no longer send
> probe
> requests when trying to associate.  I bisected to this in Felix's
> tree that holds
> this patch.
> 
> Tested on x86-64, mtk7996 radio.  Specifically
> debugged on 2.4Ghz radio, but I think it affects 5Ghz too.
> 
I have done some tests but didn't face this issue. Could you also use
the newer firmware to test if it still happens?

Thanks,
Shayne

> Thanks,
> Ben
> 
> > 
> > Co-developed-by: Allen Ye <allen.ye@mediatek.com>
> > Signed-off-by: Allen Ye <allen.ye@mediatek.com>
> > Co-developed-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
> > Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
> > Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
> > ---
> >   .../net/wireless/mediatek/mt76/mt7996/main.c  |  8 +++
> >   .../net/wireless/mediatek/mt76/mt7996/mcu.c   | 58
> +++++++++++++++++++
> >   .../net/wireless/mediatek/mt76/mt7996/mcu.h   | 16 +++++
> >   .../wireless/mediatek/mt76/mt7996/mt7996.h    |  3 +
> >   4 files changed, 85 insertions(+)
> > 
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> > index 9f12b47eb2bf..7336eaa7b9ae 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> > @@ -396,6 +396,13 @@ static int mt7996_config(struct ieee80211_hw
> *hw, u32 changed)
> >   ieee80211_wake_queues(hw);
> >   }
> >   
> > +if (changed & (IEEE80211_CONF_CHANGE_POWER |
> > +       IEEE80211_CONF_CHANGE_CHANNEL)) {
> > +ret = mt7996_mcu_set_txpower_sku(phy);
> > +if (ret)
> > +return ret;
> > +}
> > +
> >   mutex_lock(&dev->mt76.mutex);
> >   
> >   if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
> > @@ -965,6 +972,7 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32
> tx_ant, u32 rx_ant)
> >   mt76_set_stream_caps(phy->mt76, true);
> >   mt7996_set_stream_vht_txbf_caps(phy);
> >   mt7996_set_stream_he_eht_caps(phy);
> > +mt7996_mcu_set_txpower_sku(phy);
> >   
> >   mutex_unlock(&dev->mt76.mutex);
> >   
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> > index 8097924d460b..8141c24ade50 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> > @@ -4353,3 +4353,61 @@ int mt7996_mcu_wed_rro_reset_sessions(struct
> mt7996_dev *dev, u16 id)
> >   return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req,
> >    sizeof(req), true);
> >   }
> > +
> > +int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
> > +{
> > +#define TX_POWER_LIMIT_TABLE_RATE0
> > +struct mt7996_dev *dev = phy->dev;
> > +struct mt76_phy *mphy = phy->mt76;
> > +struct ieee80211_hw *hw = mphy->hw;
> > +struct tx_power_limit_table_ctrl {
> > +u8 __rsv1[4];
> > +
> > +__le16 tag;
> > +__le16 len;
> > +u8 power_ctrl_id;
> > +u8 power_limit_type;
> > +u8 band_idx;
> > +} __packed req = {
> > +.tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL),
> > +.len = cpu_to_le16(sizeof(req) + MT7996_SKU_RATE_NUM - 4),
> > +.power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL,
> > +.power_limit_type = TX_POWER_LIMIT_TABLE_RATE,
> > +.band_idx = phy->mt76->band_idx,
> > +};
> > +struct mt76_power_limits la = {};
> > +struct sk_buff *skb;
> > +int i, tx_power;
> > +
> > +tx_power = mt7996_get_power_bound(phy, hw->conf.power_level);
> > +tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
> > +      &la, tx_power);
> > +mphy->txpower_cur = tx_power;
> > +
> > +skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
> > + sizeof(req) + MT7996_SKU_RATE_NUM);
> > +if (!skb)
> > +return -ENOMEM;
> > +
> > +skb_put_data(skb, &req, sizeof(req));
> > +/* cck and ofdm */
> > +skb_put_data(skb, &la.cck, sizeof(la.cck) + sizeof(la.ofdm));
> > +/* ht20 */
> > +skb_put_data(skb, &la.mcs[0], 8);
> > +/* ht40 */
> > +skb_put_data(skb, &la.mcs[1], 9);
> > +
> > +/* vht */
> > +for (i = 0; i < 4; i++) {
> > +skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i]));
> > +skb_put_zero(skb, 2);  /* padding */
> > +}
> > +
> > +/* he */
> > +skb_put_data(skb, &la.ru[0], sizeof(la.ru));
> > +/* eht */
> > +skb_put_data(skb, &la.eht[0], sizeof(la.eht));
> > +
> > +return mt76_mcu_skb_send_msg(&dev->mt76, skb,
> > +     MCU_WM_UNI_CMD(TXPOWER), true);
> > +}
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> > index a3eae32c8f10..1562c8a6a821 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> > @@ -762,6 +762,18 @@ enum {
> >   #define MT7996_MAX_BSS_OFFLOAD_SIZE(MT7996_MAX_BEACON_SIZE +\
> >    MT7996_BEACON_UPDATE_SIZE)
> >   
> > +static inline s8
> > +mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower)
> > +{
> > +struct mt76_phy *mphy = phy->mt76;
> > +int n_chains = hweight16(mphy->chainmask);
> > +
> > +txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower *
> 2);
> > +txpower -= mt76_tx_power_nss_delta(n_chains);
> > +
> > +return txpower;
> > +}
> > +
> >   enum {
> >   UNI_BAND_CONFIG_RADIO_ENABLE,
> >   UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
> > @@ -830,6 +842,10 @@ enum {
> >   UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
> >   };
> >   
> > +enum {
> > +UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
> > +};
> > +
> >   enum {
> >   UNI_CMD_ACCESS_REG_BASIC = 0x0,
> >   UNI_CMD_ACCESS_RF_REG_BASIC,
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> > index d3eb564623ae..c62a42512bd6 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> > @@ -42,6 +42,8 @@
> >   #define MT7996_CFEND_RATE_DEFAULT0x49/* OFDM 24M */
> >   #define MT7996_CFEND_RATE_11B0x03/* 11B LP, 11M */
> >   
> > +#define MT7996_SKU_RATE_NUM417
> > +
> >   #define MT7996_MAX_TWT_AGRT16
> >   #define MT7996_MAX_STA_TWT_AGRT8
> >   #define MT7996_MAX_QUEUE(__MT_RXQ_MAX +__MT_MCUQ_MAX + 3)
> > @@ -471,6 +473,7 @@ int mt7996_mcu_get_chan_mib_info(struct
> mt7996_phy *phy, bool chan_switch);
> >   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_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
> >          u8 rx_sel, u8 val);
> >   int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
>
Ben Greear Dec. 7, 2023, 9:01 p.m. UTC | #3
On 12/7/23 09:15, shayne.chen@mediatek.com wrote:
> On Fri, 2023-12-01 at 15:40 -0800, Ben Greear wrote:
>>   	
>> External email : Please do not click links or open attachments until
>> you have verified the sender or the content.
>>   On 11/2/23 03:02, Shayne Chen wrote:
>>> Add support for setting txpower from upper layer and configuring
>> per-rate
>>> txpower limit table.
>>
>> Hello Shayne,
> 
> Hi Ben,
>>
>>   From what I can tell, this patch causes STA vdevs to no longer send
>> probe
>> requests when trying to associate.  I bisected to this in Felix's
>> tree that holds
>> this patch.
>>
>> Tested on x86-64, mtk7996 radio.  Specifically
>> debugged on 2.4Ghz radio, but I think it affects 5Ghz too.
>>
> I have done some tests but didn't face this issue. Could you also use
> the newer firmware to test if it still happens?

The problem remains with this firmware:

[root@ct523c-a0af ~]# ethtool -i wlan2
driver: mt7996e
version: 6.7.0-rc3+
firmware-version: ____000000-20231012001354
expansion-rom-version:
bus-info: 0000:0d:00.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no

Do you have a kernel tree that you are using successfully (not an owrt feed of patches)
that you can share?

Thanks,
Ben
Ben Greear March 1, 2024, 8:12 p.m. UTC | #4
On 12/7/23 13:01, Ben Greear wrote:
> On 12/7/23 09:15, shayne.chen@mediatek.com wrote:
>> On Fri, 2023-12-01 at 15:40 -0800, Ben Greear wrote:
>>>
>>> External email : Please do not click links or open attachments until
>>> you have verified the sender or the content.
>>>   On 11/2/23 03:02, Shayne Chen wrote:
>>>> Add support for setting txpower from upper layer and configuring
>>> per-rate
>>>> txpower limit table.
>>>
>>> Hello Shayne,
>>
>> Hi Ben,
>>>
>>>   From what I can tell, this patch causes STA vdevs to no longer send
>>> probe
>>> requests when trying to associate.  I bisected to this in Felix's
>>> tree that holds
>>> this patch.
>>>
>>> Tested on x86-64, mtk7996 radio.  Specifically
>>> debugged on 2.4Ghz radio, but I think it affects 5Ghz too.
>>>
>> I have done some tests but didn't face this issue. Could you also use
>> the newer firmware to test if it still happens?

Hello Shayne,

I rebased on 6.8, and started adding some debugging around this issue.

I am using the MTK 7996 developer radio board on this system, in an x86-64 pc.  It is not able
to find the 'node', so the per mode power tables are not populated and left at
0x0.  Then, when this 0x0 data is sent to the firmware, the firmware gives
back a failure response 0xc00000bb

[ 8658.340984] mt7996e 0000:03:00.0: get-rate-power-limits:  Could not find node.
[ 8658.340988] mt7996e 0000:03:00.0: set-txpower-sku, tx_power: 36
[ 8658.341127] mt7996e 0000:03:00.0: mcu-parse-response, firmware returned failure code: 0xc00000bb.

Do we need to add code to not even send the mcu command if the per-mode txpower tables
cannot be found?

Or can we calculate the values to some useful default in that case?

For reference, here is my debug patch:


diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
index 0c5c664de6b3..cf48073783b8 100644
--- a/drivers/net/wireless/mediatek/mt76/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
@@ -419,12 +422,16 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,

         memset(dest, target_power, sizeof(*dest));

-       if (!IS_ENABLED(CONFIG_OF))
+       if (!IS_ENABLED(CONFIG_OF)) {
+               mtk_dbg(dev, CFG, "get-rate-power-limits:  CONFIG_OF not enabled.\n");
                 return target_power;
+       }

         np = mt76_find_power_limits_node(dev);
-       if (!np)
+       if (!np) {
+               mtk_dbg(dev, CFG, "get-rate-power-limits:  Could not find node.\n");
                 return target_power;
+       }

         switch (chan->band) {
         case NL80211_BAND_2GHZ:
@@ -442,12 +449,17 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,

         snprintf(name, sizeof(name), "txpower-%cg", band);
         np = of_get_child_by_name(np, name);
-       if (!np)
+       if (!np) {
+               mtk_dbg(dev, CFG, "get-rate-power-limits:  Could not find band node: %s\n",
+                       name);
                 return target_power;
+       }

         np = mt76_find_channel_node(np, chan);
-       if (!np)
+       if (!np) {
+               mtk_dbg(dev, CFG, "get-rate-power-limits:  Could not find chan node\n");
                 return target_power;
+       }

         txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask));

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 2c19b537feec..8f4774c4b1d5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1114,6 +1114,7 @@ enum MTK_DEUBG {
         MTK_DEBUG_FATAL         = 0x00000004,
         MTK_DEBUG_WRN           = 0x00000008,
         MTK_DEBUG_MSG           = 0x00000010, /* messages to/from firmware */
+       MTK_DEBUG_CFG           = 0x00000020, /* Configuration related */
         MTK_DEBUG_ANY           = 0xffffffff
  };

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index e89a06464651..c7042c3a905b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -422,8 +422,11 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
         if (changed & (IEEE80211_CONF_CHANGE_POWER |
                        IEEE80211_CONF_CHANGE_CHANNEL)) {
                 ret = mt7996_mcu_set_txpower_sku(phy);
-               if (ret)
-                       return ret;
+               if (ret) {
+                       dev_err(dev->mt76.dev,
+                               "config:  Failed to set txpower: %d\n", ret);
+                       //return ret;
+               }
         }

         mutex_lock(&dev->mt76.mutex);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index d709d26eacd1..9dc896cd04e6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -281,6 +281,10 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd,
                 /* skip invalid event */
                 if (mcu_cmd != event->cid)
                         ret = -EAGAIN;
+               if (ret) {
+                       mtk_dbg(mdev, CFG, "mcu-parse-response, firmware returned failure code: 0x%x.\n",
+                               ret);
+               }
         } else {
                 skb_pull(skb, sizeof(struct mt7996_mcu_rxd));
         }
@@ -4571,6 +4575,7 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
         tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
                                               &la, tx_power);
         mphy->txpower_cur = tx_power;
+       mtk_dbg(&dev->mt76, CFG, "set-txpower-sku, tx_power: %d\n", tx_power);

         skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
                                  sizeof(req) + MT7996_SKU_RATE_NUM);

Thanks,
Ben
Ben Greear March 4, 2024, 6:13 p.m. UTC | #5
On 3/1/24 12:12, Ben Greear wrote:
> On 12/7/23 13:01, Ben Greear wrote:
>> On 12/7/23 09:15, shayne.chen@mediatek.com wrote:
>>> On Fri, 2023-12-01 at 15:40 -0800, Ben Greear wrote:
>>>>
>>>> External email : Please do not click links or open attachments until
>>>> you have verified the sender or the content.
>>>>   On 11/2/23 03:02, Shayne Chen wrote:
>>>>> Add support for setting txpower from upper layer and configuring
>>>> per-rate
>>>>> txpower limit table.
>>>>
>>>> Hello Shayne,
>>>
>>> Hi Ben,
>>>>
>>>>   From what I can tell, this patch causes STA vdevs to no longer send
>>>> probe
>>>> requests when trying to associate.  I bisected to this in Felix's
>>>> tree that holds
>>>> this patch.
>>>>
>>>> Tested on x86-64, mtk7996 radio.  Specifically
>>>> debugged on 2.4Ghz radio, but I think it affects 5Ghz too.
>>>>
>>> I have done some tests but didn't face this issue. Could you also use
>>> the newer firmware to test if it still happens?
> 
> Hello Shayne,
> 
> I rebased on 6.8, and started adding some debugging around this issue.

I received a patch from Chad that fixes this problem, the cmd size was wrong for one
reason or another.

Thanks,
Ben
diff mbox series

Patch

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 9f12b47eb2bf..7336eaa7b9ae 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -396,6 +396,13 @@  static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
 		ieee80211_wake_queues(hw);
 	}
 
+	if (changed & (IEEE80211_CONF_CHANGE_POWER |
+		       IEEE80211_CONF_CHANGE_CHANNEL)) {
+		ret = mt7996_mcu_set_txpower_sku(phy);
+		if (ret)
+			return ret;
+	}
+
 	mutex_lock(&dev->mt76.mutex);
 
 	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
@@ -965,6 +972,7 @@  mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
 	mt76_set_stream_caps(phy->mt76, true);
 	mt7996_set_stream_vht_txbf_caps(phy);
 	mt7996_set_stream_he_eht_caps(phy);
+	mt7996_mcu_set_txpower_sku(phy);
 
 	mutex_unlock(&dev->mt76.mutex);
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 8097924d460b..8141c24ade50 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -4353,3 +4353,61 @@  int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id)
 	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req,
 				 sizeof(req), true);
 }
+
+int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
+{
+#define TX_POWER_LIMIT_TABLE_RATE	0
+	struct mt7996_dev *dev = phy->dev;
+	struct mt76_phy *mphy = phy->mt76;
+	struct ieee80211_hw *hw = mphy->hw;
+	struct tx_power_limit_table_ctrl {
+		u8 __rsv1[4];
+
+		__le16 tag;
+		__le16 len;
+		u8 power_ctrl_id;
+		u8 power_limit_type;
+		u8 band_idx;
+	} __packed req = {
+		.tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL),
+		.len = cpu_to_le16(sizeof(req) + MT7996_SKU_RATE_NUM - 4),
+		.power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL,
+		.power_limit_type = TX_POWER_LIMIT_TABLE_RATE,
+		.band_idx = phy->mt76->band_idx,
+	};
+	struct mt76_power_limits la = {};
+	struct sk_buff *skb;
+	int i, tx_power;
+
+	tx_power = mt7996_get_power_bound(phy, hw->conf.power_level);
+	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
+					      &la, tx_power);
+	mphy->txpower_cur = tx_power;
+
+	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
+				 sizeof(req) + MT7996_SKU_RATE_NUM);
+	if (!skb)
+		return -ENOMEM;
+
+	skb_put_data(skb, &req, sizeof(req));
+	/* cck and ofdm */
+	skb_put_data(skb, &la.cck, sizeof(la.cck) + sizeof(la.ofdm));
+	/* ht20 */
+	skb_put_data(skb, &la.mcs[0], 8);
+	/* ht40 */
+	skb_put_data(skb, &la.mcs[1], 9);
+
+	/* vht */
+	for (i = 0; i < 4; i++) {
+		skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i]));
+		skb_put_zero(skb, 2);  /* padding */
+	}
+
+	/* he */
+	skb_put_data(skb, &la.ru[0], sizeof(la.ru));
+	/* eht */
+	skb_put_data(skb, &la.eht[0], sizeof(la.eht));
+
+	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+				     MCU_WM_UNI_CMD(TXPOWER), true);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
index a3eae32c8f10..1562c8a6a821 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
@@ -762,6 +762,18 @@  enum {
 #define MT7996_MAX_BSS_OFFLOAD_SIZE	(MT7996_MAX_BEACON_SIZE +		\
 					 MT7996_BEACON_UPDATE_SIZE)
 
+static inline s8
+mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower)
+{
+	struct mt76_phy *mphy = phy->mt76;
+	int n_chains = hweight16(mphy->chainmask);
+
+	txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2);
+	txpower -= mt76_tx_power_nss_delta(n_chains);
+
+	return txpower;
+}
+
 enum {
 	UNI_BAND_CONFIG_RADIO_ENABLE,
 	UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
@@ -830,6 +842,10 @@  enum {
 	UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
 };
 
+enum {
+	UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
+};
+
 enum {
 	UNI_CMD_ACCESS_REG_BASIC = 0x0,
 	UNI_CMD_ACCESS_RF_REG_BASIC,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index d3eb564623ae..c62a42512bd6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -42,6 +42,8 @@ 
 #define MT7996_CFEND_RATE_DEFAULT	0x49	/* OFDM 24M */
 #define MT7996_CFEND_RATE_11B		0x03	/* 11B LP, 11M */
 
+#define MT7996_SKU_RATE_NUM		417
+
 #define MT7996_MAX_TWT_AGRT		16
 #define MT7996_MAX_STA_TWT_AGRT		8
 #define MT7996_MAX_QUEUE		(__MT_RXQ_MAX +	__MT_MCUQ_MAX + 3)
@@ -471,6 +473,7 @@  int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
 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_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
 		       u8 rx_sel, u8 val);
 int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,