diff mbox series

mac80211: limit MT7620 TX power based on eeprom calibration

Message ID TYAP286MB031542007DE86EA4911D4C65BC3CA@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
State Superseded
Delegated to: Daniel Golle
Headers show
Series mac80211: limit MT7620 TX power based on eeprom calibration | expand

Commit Message

Shiji Yang July 22, 2023, 2:52 p.m. UTC
From: Shiji Yang <yangshiji66@qq.com>

This patch adds basic TX power control to the MT7620 and limits its
maximum TX power. This can avoid the link speed decrease caused by
chip overheating.

Signed-off-by: Shiji Yang <yangshiji66@qq.com>
---
 ...t-MT7620-TX-power-based-on-eeprom-ca.patch | 83 +++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 package/kernel/mac80211/patches/rt2x00/997-wifi-rt2x00-limit-MT7620-TX-power-based-on-eeprom-ca.patch

Comments

Daniel Golle July 22, 2023, 4:36 p.m. UTC | #1
On Sat, Jul 22, 2023 at 10:52:02PM +0800, Shiji Yang wrote:
> From: Shiji Yang <yangshiji66@qq.com>
> 
> This patch adds basic TX power control to the MT7620 and limits its
> maximum TX power. This can avoid the link speed decrease caused by
> chip overheating.

Thanks a lot for your patch and analysis of the situation.
As you add code reading values from the EEPROM, we need to make sure
that it doesn't break other chips (Rt5xxx most likely, Rt3xxx could
also be affected). The easiest would be to create a new function
rt2800_config_alc_mt7620 which is called only for MT7620 while keeping
the original codepath for all other rt2800 radios (unless we are 100%
sure that we won't break things).

> 
> Signed-off-by: Shiji Yang <yangshiji66@qq.com>
> ---
>  ...t-MT7620-TX-power-based-on-eeprom-ca.patch | 83 +++++++++++++++++++
>  1 file changed, 83 insertions(+)
>  create mode 100644 package/kernel/mac80211/patches/rt2x00/997-wifi-rt2x00-limit-MT7620-TX-power-based-on-eeprom-ca.patch
> 
> diff --git a/package/kernel/mac80211/patches/rt2x00/997-wifi-rt2x00-limit-MT7620-TX-power-based-on-eeprom-ca.patch b/package/kernel/mac80211/patches/rt2x00/997-wifi-rt2x00-limit-MT7620-TX-power-based-on-eeprom-ca.patch
> new file mode 100644
> index 0000000000..ecb8577752
> --- /dev/null
> +++ b/package/kernel/mac80211/patches/rt2x00/997-wifi-rt2x00-limit-MT7620-TX-power-based-on-eeprom-ca.patch
> @@ -0,0 +1,83 @@
> +From: Shiji Yang <yangshiji66@outlook.com>
> +Date: Sat, 22 Jul 2023 21:56:30 +0800
> +Subject: [PATCH] wifi: rt2x00: limit MT7620 TX power based on eeprom
> + calibration
> +
> +In the vendor driver, the current channel power is queried from
> +EEPROM_TXPOWER_BG1 and EEPROM_TXPOWER_BG2. And then the mixed value
> +will be written into the low half-word of the TX_ALC_CFG_0 register.
> +The high half-word of the TX_ALC_CFG_0 is a fixed value 0x2f2f.
> +
> +We can't get the accurate TX power. Based on my tests and the new
> +MediaTek mt76 driver source code, the real TX power is approximately
> +equal to channel_power + (max) rate_power. Usually max rate_power is
> +the gain of the OFDM 6M rate, which can be readed from the offset
> +EEPROM_TXPOWER_BYRATE +1.
> +
> +Based on these eeprom values, this patch adds basic TX power control
> +to the MT7620 and limits its maximum TX power. This can avoid the
> +link speed decrease caused by chip overheating.
> +
> +Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
> +---
> + .../net/wireless/ralink/rt2x00/rt2800lib.c    | 43 +++++++++++++------
> + 1 file changed, 30 insertions(+), 13 deletions(-)
> +
> +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
> ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
> +@@ -3894,25 +3894,42 @@ static void rt2800_config_channel_rf7620
> + static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev,
> + 			      struct ieee80211_channel *chan,
> + 			      int power_level) {
> +-	u16 eeprom, target_power, max_power;
> ++	u16 eeprom, chan_power, rate_power, target_power;
> ++	u16 tx_power[2];
> ++	s8 *power_group[2];
> + 	u32 mac_sys_ctrl;
> +-	u32 reg;
> ++	u32 cnt, reg;
> + 	u8 bbp;
> + 
> +-	/* hardware unit is 0.5dBm, limited to 23.5dBm */
> +-	power_level *= 2;
> +-	if (power_level > 0x2f)
> +-		power_level = 0x2f;
> ++	/* get per channel power, 2 channels in total, unit is 0.5dBm */
> ++	power_level = (power_level - 3) * 2;
> ++	/*
> ++	 * We can't set the accurate TX power. Based on some tests, the real
> ++	 * TX power is approximately equal to channel_power + (max)rate_power.
> ++	 * Usually max rate_power is the gain of the OFDM 6M rate.
> ++	 */
> ++	rate_power = rt2800_eeprom_read_from_array(rt2x00dev,
> ++				EEPROM_TXPOWER_BYRATE, 1) & 0x3f;
> ++	power_level -= rate_power;
> ++	if (power_level < 1)
> ++		power_level = 1;
> ++	if (power_level > chan->max_power * 2)
> ++		power_level = chan->max_power * 2;
> + 
> +-	max_power = chan->max_power * 2;
> +-	if (max_power > 0x2f)
> +-		max_power = 0x2f;
> ++	power_group[0] = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
> ++	power_group[1] = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
> ++	for (cnt = 0; cnt < 2; cnt++) {
> ++		chan_power = power_group[cnt][rt2x00dev->rf_channel - 1];
> ++		if (chan_power >= 0x20 || chan_power == 0)
> ++			chan_power = 0x10;
> ++		tx_power[cnt] = power_level < chan_power ? power_level : chan_power;
> ++	}
> + 
> + 	reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_0);
> +-	rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_0, power_level);
> +-	rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_1, power_level);
> +-	rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_0, max_power);
> +-	rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_1, max_power);
> ++	rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_0, tx_power[0]);
> ++	rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_1, tx_power[1]);
> ++	rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_0, 0x2f);
> ++	rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_1, 0x2f);
> + 
> + 	eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1);
> + 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_INTERNAL_TX_ALC)) {
> -- 
> 2.39.2
>
Shiji Yang July 23, 2023, 2:13 a.m. UTC | #2
Hi, 
Thank you for your quick review.

On July 22, 2023, 4:36 p.m. UTC, Daniel Golle wrote:

>On Sat, Jul 22, 2023 at 10:52:02PM +0800, Shiji Yang wrote:
>> From: Shiji Yang <yangshiji66@qq.com>
>>
>> This patch adds basic TX power control to the MT7620 and limits its
>> maximum TX power. This can avoid the link speed decrease caused by
>> chip overheating.
>
>Thanks a lot for your patch and analysis of the situation.
>As you add code reading values from the EEPROM, we need to make sure
>that it doesn't break other chips (Rt5xxx most likely, Rt3xxx could
>also be affected). The easiest would be to create a new function
>rt2800_config_alc_mt7620 which is called only for MT7620 while keeping
>the original codepath for all other rt2800 radios (unless we are 100%
>sure that we won't break things).
>
>>
>> Signed-off-by: Shiji Yang <yangshiji66@qq.com>

This rt2800_config_alc() function is only used by RT6352(AKA MT7620),
so these changes are safe. I'll rename it to rt2800_config_alc_rt6352()
on the V2 patch.

ref:
https://elixir.bootlin.com/linux/v6.4.3/A/ident/rt2800_config_alc
diff mbox series

Patch

diff --git a/package/kernel/mac80211/patches/rt2x00/997-wifi-rt2x00-limit-MT7620-TX-power-based-on-eeprom-ca.patch b/package/kernel/mac80211/patches/rt2x00/997-wifi-rt2x00-limit-MT7620-TX-power-based-on-eeprom-ca.patch
new file mode 100644
index 0000000000..ecb8577752
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/997-wifi-rt2x00-limit-MT7620-TX-power-based-on-eeprom-ca.patch
@@ -0,0 +1,83 @@ 
+From: Shiji Yang <yangshiji66@outlook.com>
+Date: Sat, 22 Jul 2023 21:56:30 +0800
+Subject: [PATCH] wifi: rt2x00: limit MT7620 TX power based on eeprom
+ calibration
+
+In the vendor driver, the current channel power is queried from
+EEPROM_TXPOWER_BG1 and EEPROM_TXPOWER_BG2. And then the mixed value
+will be written into the low half-word of the TX_ALC_CFG_0 register.
+The high half-word of the TX_ALC_CFG_0 is a fixed value 0x2f2f.
+
+We can't get the accurate TX power. Based on my tests and the new
+MediaTek mt76 driver source code, the real TX power is approximately
+equal to channel_power + (max) rate_power. Usually max rate_power is
+the gain of the OFDM 6M rate, which can be readed from the offset
+EEPROM_TXPOWER_BYRATE +1.
+
+Based on these eeprom values, this patch adds basic TX power control
+to the MT7620 and limits its maximum TX power. This can avoid the
+link speed decrease caused by chip overheating.
+
+Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
+---
+ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 43 +++++++++++++------
+ 1 file changed, 30 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -3894,25 +3894,42 @@ static void rt2800_config_channel_rf7620
+ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev,
+ 			      struct ieee80211_channel *chan,
+ 			      int power_level) {
+-	u16 eeprom, target_power, max_power;
++	u16 eeprom, chan_power, rate_power, target_power;
++	u16 tx_power[2];
++	s8 *power_group[2];
+ 	u32 mac_sys_ctrl;
+-	u32 reg;
++	u32 cnt, reg;
+ 	u8 bbp;
+ 
+-	/* hardware unit is 0.5dBm, limited to 23.5dBm */
+-	power_level *= 2;
+-	if (power_level > 0x2f)
+-		power_level = 0x2f;
++	/* get per channel power, 2 channels in total, unit is 0.5dBm */
++	power_level = (power_level - 3) * 2;
++	/*
++	 * We can't set the accurate TX power. Based on some tests, the real
++	 * TX power is approximately equal to channel_power + (max)rate_power.
++	 * Usually max rate_power is the gain of the OFDM 6M rate.
++	 */
++	rate_power = rt2800_eeprom_read_from_array(rt2x00dev,
++				EEPROM_TXPOWER_BYRATE, 1) & 0x3f;
++	power_level -= rate_power;
++	if (power_level < 1)
++		power_level = 1;
++	if (power_level > chan->max_power * 2)
++		power_level = chan->max_power * 2;
+ 
+-	max_power = chan->max_power * 2;
+-	if (max_power > 0x2f)
+-		max_power = 0x2f;
++	power_group[0] = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
++	power_group[1] = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
++	for (cnt = 0; cnt < 2; cnt++) {
++		chan_power = power_group[cnt][rt2x00dev->rf_channel - 1];
++		if (chan_power >= 0x20 || chan_power == 0)
++			chan_power = 0x10;
++		tx_power[cnt] = power_level < chan_power ? power_level : chan_power;
++	}
+ 
+ 	reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_0);
+-	rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_0, power_level);
+-	rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_1, power_level);
+-	rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_0, max_power);
+-	rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_1, max_power);
++	rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_0, tx_power[0]);
++	rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_1, tx_power[1]);
++	rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_0, 0x2f);
++	rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_1, 0x2f);
+ 
+ 	eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1);
+ 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_INTERNAL_TX_ALC)) {