* [PATCH rtw-next v2 1/7] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions
[not found] <20261031070950.425176-1-hjf3108@gmail.com>
@ 2026-10-31 7:09 ` Ho Jie Feng
2026-11-06 17:21 ` Luka Gejak
2026-10-31 7:09 ` [PATCH rtw-next v2 2/7] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions Ho Jie Feng
` (5 subsequent siblings)
6 siblings, 1 reply; 15+ messages in thread
From: Ho Jie Feng @ 2026-10-31 7:09 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
8812a and 8814a support STBC, enable it.
Signed-off-by: Ho Jie Feng <hjf3108@gmail.com>
---
drivers/net/wireless/realtek/rtw88/main.c | 2 +-
drivers/net/wireless/realtek/rtw88/rtw8812a.c | 1 +
drivers/net/wireless/realtek/rtw88/rtw8814a.c | 1 +
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 0f23498b5c96e406581c06a524e9f270873866ae..f7d7b66844862ff01533b8b640ed35738169673d 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1585,7 +1585,7 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev,
if (rtw_chip_has_rx_ldpc(rtwdev))
ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING;
- if (rtw_chip_has_tx_stbc(rtwdev))
+ if (rtw_chip_has_tx_stbc(rtwdev) && rtwdev->hal.rf_path_num > 1)
ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
if (efuse->hw_cap.bw & BIT(RTW_CHANNEL_WIDTH_40))
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
index 781b66ccde675a96c41f69cfb80484ba67c20c16..55f1d3d3240be24580bdc4a7b3456b8ff8340e70 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
@@ -1077,6 +1077,7 @@ const struct rtw_chip_info rtw8812a_hw_spec = {
.rfe_defs = rtw8812a_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8812a_rfe_defs),
.rx_ldpc = false,
+ .tx_stbc = true,
.amsdu_in_ampdu = true,
.hw_feature_report = false,
.c2h_ra_report_size = 4,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
index fa02aa299b5e9925428f591a609db2d9f8627ca8..5bb55606f14a126806acb354658c150150ae0cce 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
@@ -2200,6 +2200,7 @@ const struct rtw_chip_info rtw8814a_hw_spec = {
.txgi_factor = 1,
.is_pwr_by_rate_dec = true,
.rx_ldpc = true,
+ .tx_stbc = true,
.max_power_index = 0x3f,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_2,
.amsdu_in_ampdu = false, /* RX speed is better without AMSDU */
--
2.55.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH rtw-next v2 1/7] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions
2026-10-31 7:09 ` [PATCH rtw-next v2 1/7] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions Ho Jie Feng
@ 2026-11-06 17:21 ` Luka Gejak
0 siblings, 0 replies; 15+ messages in thread
From: Luka Gejak @ 2026-11-06 17:21 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
Hi Jie Feng,
One comment below.
October 31, 2026 at 8:09 AM, "Ho Jie Feng" <hjf3108@gmail.com> wrote:
> diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
> index 0f23498b5c96e406581c06a524e9f270873866ae..f7d7b66844862ff01533b8b640ed35738169673d 100644
> --- a/drivers/net/wireless/realtek/rtw88/main.c
> +++ b/drivers/net/wireless/realtek/rtw88/main.c
> @@ -1585,7 +1585,7 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev,
>
> if (rtw_chip_has_rx_ldpc(rtwdev))
> ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING;
> - if (rtw_chip_has_tx_stbc(rtwdev))
> + if (rtw_chip_has_tx_stbc(rtwdev) && rtwdev->hal.rf_path_num > 1)
> ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
This also changes 8822c, which already had tx_stbc set. When its hw
feature report says one antenna, rtw_hw_config_rf_ant_num() sets
rf_path_num to 1 and it stops advertising HT TX STBC. That looks right
to me, the VHT side already checks rf_path_num the same way, but it
would be good to mention it in the commit message.
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH rtw-next v2 2/7] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
[not found] <20261031070950.425176-1-hjf3108@gmail.com>
2026-10-31 7:09 ` [PATCH rtw-next v2 1/7] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions Ho Jie Feng
@ 2026-10-31 7:09 ` Ho Jie Feng
2026-11-06 17:23 ` Luka Gejak
2026-10-31 7:09 ` [PATCH rtw-next v2 3/7] wifi: rtw88: correctly expose beamformee capabilities Ho Jie Feng
` (4 subsequent siblings)
6 siblings, 1 reply; 15+ messages in thread
From: Ho Jie Feng @ 2026-10-31 7:09 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
Implement beamformee support for 88xxa since they have
support for it.
Signed-off-by: Ho Jie Feng <hjf3108@gmail.com>
---
drivers/net/wireless/realtek/rtw88/bf.h | 2 +
drivers/net/wireless/realtek/rtw88/reg.h | 1 +
drivers/net/wireless/realtek/rtw88/rtw8812a.c | 3 +-
drivers/net/wireless/realtek/rtw88/rtw8814a.c | 36 ++++++++++-
drivers/net/wireless/realtek/rtw88/rtw8821a.c | 3 +-
drivers/net/wireless/realtek/rtw88/rtw88xxa.c | 62 +++++++++++++++++++
drivers/net/wireless/realtek/rtw88/rtw88xxa.h | 2 +
7 files changed, 104 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/bf.h b/drivers/net/wireless/realtek/rtw88/bf.h
index a5d3010e6be6ef776b1c604207f68d6331721feb..0aa78fb6a7e64435e4d5fc18f3e9c70a01d73135 100644
--- a/drivers/net/wireless/realtek/rtw88/bf.h
+++ b/drivers/net/wireless/realtek/rtw88/bf.h
@@ -12,6 +12,8 @@
#define REG_ASSOCIATED_BFMER0_INFO 0x06E4
#define REG_ASSOCIATED_BFMER1_INFO 0x06EC
#define REG_TX_CSI_RPT_PARAM_BW20 0x06F4
+#define REG_TX_CSI_RPT_PARAM_BW40 0x06F8
+#define REG_TX_CSI_RPT_PARAM_BW80 0x06FC
#define REG_SND_PTCL_CTRL 0x0718
#define BIT_DIS_CHK_VHTSIGB_CRC BIT(6)
#define BIT_DIS_CHK_VHTSIGA_CRC BIT(5)
diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
index afcdb66fdb9a11a44bf52c790aea2cc69aeb851c..f8ec1e2931f63a06a72626bf3168256728ed933b 100644
--- a/drivers/net/wireless/realtek/rtw88/reg.h
+++ b/drivers/net/wireless/realtek/rtw88/reg.h
@@ -671,6 +671,7 @@
#define REG_IQK_COM96 0x0984
#define REG_FAS 0x09a4
+#define REG_CSI_CONTENT_VALUE 0x09b4
#define REG_RXSB 0x0a00
#define BIT_RXSB_ANA_DIV BIT(15)
#define REG_CCK_RX 0x0a04
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
index 55f1d3d3240be24580bdc4a7b3456b8ff8340e70..5d58dff4fcee7c4b3194794266cb48cd472014f9 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
@@ -931,7 +931,7 @@ static const struct rtw_chip_ops rtw8812a_ops = {
.phy_calibration = rtw8812a_phy_calibration,
.cck_pd_set = rtw_phy_cck_pd_set,
.pwr_track = rtw8812a_pwr_track,
- .config_bfee = NULL,
+ .config_bfee = rtw88xxa_bf_config_bfee,
.set_gid_table = NULL,
.cfg_csi_rate = NULL,
.led_set = rtw8812a_led_set,
@@ -1084,6 +1084,7 @@ const struct rtw_chip_info rtw8812a_hw_spec = {
.old_datarate_fb_limit = true,
.usb_tx_agg_desc_num = 1,
.iqk_threshold = 8,
+ .bfer_su_max_num = 2,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
index 5bb55606f14a126806acb354658c150150ae0cce..2db05a83766d65123edc95f50a40d3f93bfb1dba 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
@@ -4,6 +4,7 @@
#include <linux/usb.h>
#include "main.h"
+#include "bf.h"
#include "coex.h"
#include "tx.h"
#include "phy.h"
@@ -115,10 +116,13 @@ static void rtw8814a_init_hwcap(struct rtw_dev *rtwdev)
BIT(RTW_CHANNEL_WIDTH_80);
efuse->hw_cap.ptcl = EFUSE_HW_CAP_PTCL_VHT;
- if (hal->rf_type == RF_3T3R)
+ if (hal->rf_type == RF_3T3R) {
efuse->hw_cap.nss = 3;
- else
+ hal->bfee_sts_cap = 2;
+ } else {
efuse->hw_cap.nss = 2;
+ hal->bfee_sts_cap = 1;
+ }
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"hw cap: hci=0x%02x, bw=0x%02x, ptcl=0x%02x, ant_num=%d, nss=%d\n",
@@ -2039,6 +2043,31 @@ static void rtw8814a_led_set(struct led_classdev *led,
rtw_write32(rtwdev, REG_GPIO_PIN_CTRL_2, led_gpio_cfg);
}
+#define RTW_NDP_RX_STANDBY_TIME_8814A 0x40
+#define RTW_SND_CTRL_SOUNDING_8814A 0xDB
+
+static void rtw8814a_bf_enable_bfee_su(struct rtw_dev *rtwdev,
+ struct rtw_vif *vif,
+ struct rtw_bfee *bfee)
+{
+ rtw_bf_enable_bfee_su(rtwdev, vif, bfee);
+
+ rtw_write16(rtwdev, REG_SND_PTCL_CTRL + 1, 0x0202);
+ rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_SOUNDING_8814A);
+ rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3,
+ RTW_NDP_RX_STANDBY_TIME_8814A);
+}
+
+static void rtw8814a_bf_config_bfee(struct rtw_dev *rtwdev,
+ struct rtw_vif *vif,
+ struct rtw_bfee *bfee, bool enable)
+{
+ if (enable)
+ rtw8814a_bf_enable_bfee_su(rtwdev, vif, bfee);
+ else
+ rtw_bf_remove_bfee_su(rtwdev, bfee);
+}
+
static void rtw8814a_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
@@ -2068,7 +2097,7 @@ static const struct rtw_chip_ops rtw8814a_ops = {
.phy_calibration = rtw8814a_phy_calibration,
.cck_pd_set = rtw8814a_phy_cck_pd_set,
.pwr_track = rtw8814a_pwr_track,
- .config_bfee = NULL,
+ .config_bfee = rtw8814a_bf_config_bfee,
.set_gid_table = NULL,
.cfg_csi_rate = NULL,
.led_set = rtw8814a_led_set,
@@ -2231,6 +2260,7 @@ const struct rtw_chip_info rtw8814a_hw_spec = {
.rfe_defs = rtw8814a_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8814a_rfe_defs),
.iqk_threshold = 8,
+ .bfer_su_max_num = 2,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
.coex_para_ver = 0,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
index 6096d3b8e41bee6cdc2d05500d2fbeb9e097430e..6d106ae70d9142b45337057311dc423158e7dabc 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
@@ -877,7 +877,7 @@ static const struct rtw_chip_ops rtw8821a_ops = {
.phy_calibration = rtw8821a_phy_calibration,
.cck_pd_set = rtw_phy_cck_pd_set,
.pwr_track = rtw8821a_pwr_track,
- .config_bfee = NULL,
+ .config_bfee = rtw88xxa_bf_config_bfee,
.set_gid_table = NULL,
.cfg_csi_rate = NULL,
.led_set = rtw8821a_led_set,
@@ -1188,6 +1188,7 @@ const struct rtw_chip_info rtw8821a_hw_spec = {
.old_datarate_fb_limit = true,
.usb_tx_agg_desc_num = 6,
.iqk_threshold = 8,
+ .bfer_su_max_num = 2,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
index c298fa0fb2a6b94118527a297affa5e6e8ab633d..87253fffe78cd6f5b58a325eef42b58b968e2d46 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
@@ -138,6 +138,7 @@ static void rtw88xxa_read_usb_type(struct rtw_dev *rtwdev)
efuse->hw_cap.nss = 1;
else
efuse->hw_cap.nss = 2;
+ rtwdev->hal.bfee_sts_cap = 1;
if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A)
goto print_hw_cap;
@@ -197,6 +198,67 @@ static void rtw88xxa_read_usb_type(struct rtw_dev *rtwdev)
efuse->hw_cap.ant_num, efuse->hw_cap.nss);
}
+#define RTW_NDP_RX_STANDBY_TIME_88XXA 0x50
+#define RTW_SND_CTRL_REMOVE_88XXA 0xC8
+#define RTW_SND_CTRL_SOUNDING_88XXA 0xCB
+
+void rtw88xxa_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif,
+ struct rtw_bfee *bfee, bool enable)
+{
+ static const u32 csi_rpt_regs[] = {
+ REG_TX_CSI_RPT_PARAM_BW20,
+ REG_TX_CSI_RPT_PARAM_BW40,
+ REG_TX_CSI_RPT_PARAM_BW80,
+ };
+ struct rtw_bf_info *bf_info = &rtwdev->bf_info;
+ u8 slot = bfee->su_reg_index;
+ u32 addr_bfer_info;
+ u32 csi_param;
+ int i;
+
+ if (bfee->role != RTW_BFEE_SU || slot >= 2)
+ return;
+
+ addr_bfer_info = slot ? REG_ASSOCIATED_BFMER1_INFO :
+ REG_ASSOCIATED_BFMER0_INFO;
+
+ rtw_dbg(rtwdev, RTW_DBG_BF, "chip %d SU beamformee %s slot %u\n",
+ rtwdev->chip->id, enable ? "enable" : "disable", slot);
+
+ if (!enable) {
+ rtw_write32(rtwdev, addr_bfer_info, 0);
+ rtw_write16(rtwdev, addr_bfer_info + 4, 0);
+
+ clear_bit(slot, bf_info->bfer_su_reg_maping);
+ bfee->su_reg_index = 0xff;
+
+ if (!bf_info->bfer_su_cnt)
+ rtw_write8(rtwdev, REG_SND_PTCL_CTRL,
+ RTW_SND_CTRL_REMOVE_88XXA);
+ return;
+ }
+
+ if (hweight8(rtwdev->hal.antenna_rx) == 2) {
+ rtw_write32(rtwdev, REG_CSI_CONTENT_VALUE, 0);
+ csi_param = 0x01090109;
+ } else {
+ rtw_write32(rtwdev, REG_CSI_CONTENT_VALUE, 0x01081008);
+ csi_param = 0x01080108;
+ }
+
+ rtw_write8(rtwdev, REG_SND_PTCL_CTRL,
+ RTW_SND_CTRL_SOUNDING_88XXA);
+ for (i = 0; i < ETH_ALEN; i++)
+ rtw_write8(rtwdev, addr_bfer_info + i, bfee->mac_addr[i]);
+
+ for (i = 0; i < ARRAY_SIZE(csi_rpt_regs); i++)
+ rtw_write32(rtwdev, csi_rpt_regs[i], csi_param);
+
+ rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3,
+ RTW_NDP_RX_STANDBY_TIME_88XXA);
+}
+EXPORT_SYMBOL(rtw88xxa_bf_config_bfee);
+
int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{
const struct rtw_chip_info *chip = rtwdev->chip;
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
index d9c8db58909cad07b06ab993a08b246b1a9bf74d..0aaf7aa4aafdd396bff25a8fcd880a5514e589ba 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
@@ -170,5 +170,7 @@ bool rtw88xxa_iqk_finish(int average, int threshold,
void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev,
void (*do_lck)(struct rtw_dev *rtwdev),
void (*do_iqk)(struct rtw_dev *rtwdev));
+void rtw88xxa_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif,
+ struct rtw_bfee *bfee, bool enable);
#endif
--
2.55.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH rtw-next v2 2/7] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
2026-10-31 7:09 ` [PATCH rtw-next v2 2/7] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions Ho Jie Feng
@ 2026-11-06 17:23 ` Luka Gejak
0 siblings, 0 replies; 15+ messages in thread
From: Luka Gejak @ 2026-11-06 17:23 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
Hi Jie Feng,
Thanks for the new version. A few comments below.
October 31, 2026 at 8:09 AM, "Ho Jie Feng" <hjf3108@gmail.com> wrote:
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
> index 5bb55606f14a126806acb354658c150150ae0cce..2db05a83766d65123edc95f50a40d3f93bfb1dba 100644
> --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
[ ... ]
> +static void rtw8814a_bf_enable_bfee_su(struct rtw_dev *rtwdev,
> + struct rtw_vif *vif,
> + struct rtw_bfee *bfee)
> +{
> + rtw_bf_enable_bfee_su(rtwdev, vif, bfee);
> +
> + rtw_write16(rtwdev, REG_SND_PTCL_CTRL + 1, 0x0202);
This is a 16 bit write to 0x719, which is not 2 byte aligned. On
RTL8814AE it goes through rtw_pci_write16(), a plain writew() on the
mapped BAR. As far as I know an unaligned access to device memory raises
an alignment fault on arm64, so an RTL8814AE there could oops when it
associates to an AP that is an SU beamformer.
The vendor phydm code does a 32 bit read modify write of 0x718 for these
two bytes:
odm_set_mac_reg(p_dm, REG_SND_PTCL_CTRL_8814A,
MASKBYTE1 | MASKBYTE2, 0x0202);
so maybe the same would work here:
rtw_write32_mask(rtwdev, REG_SND_PTCL_CTRL, MASKBYTE1 | MASKBYTE2,
0x0202);
[ ... ]
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> index c298fa0fb2a6b94118527a297affa5e6e8ab633d..87253fffe78cd6f5b58a325eef42b58b968e2d46 100644
> --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> @@ -138,6 +138,7 @@ static void rtw88xxa_read_usb_type(struct rtw_dev *rtwdev)
> efuse->hw_cap.nss = 1;
> else
> efuse->hw_cap.nss = 2;
> + rtwdev->hal.bfee_sts_cap = 1;
The function already has a hal pointer, so hal->bfee_sts_cap would match
the rest of it.
[ ... ]
> + addr_bfer_info = slot ? REG_ASSOCIATED_BFMER1_INFO :
> + REG_ASSOCIATED_BFMER0_INFO;
Nit, the second line isn't aligned with REG_ASSOCIATED_BFMER1_INFO.
[ ... ]
> + rtw_write8(rtwdev, REG_SND_PTCL_CTRL,
> + RTW_SND_CTRL_SOUNDING_88XXA);
This fits on one line.
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH rtw-next v2 3/7] wifi: rtw88: correctly expose beamformee capabilities
[not found] <20261031070950.425176-1-hjf3108@gmail.com>
2026-10-31 7:09 ` [PATCH rtw-next v2 1/7] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions Ho Jie Feng
2026-10-31 7:09 ` [PATCH rtw-next v2 2/7] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions Ho Jie Feng
@ 2026-10-31 7:09 ` Ho Jie Feng
2026-11-06 17:25 ` Luka Gejak
2026-10-31 7:09 ` [PATCH rtw-next v2 4/7] wifi: rtw88: prepare frequency-offset correction for more chips Ho Jie Feng
` (3 subsequent siblings)
6 siblings, 1 reply; 15+ messages in thread
From: Ho Jie Feng @ 2026-10-31 7:09 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, Jie Feng, linux-kernel
From: Jie Feng <hjf3108@gmail.com>
Make MU and SU capability flags each depend on the chip declared
maximum instead of setting both flags together.
Signed-off-by: Ho Jie Feng <hjf3108@gmail.com>
---
drivers/net/wireless/realtek/rtw88/main.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index f7d7b66844862ff01533b8b640ed35738169673d..0a1b5575b729981b34e0fa9c37a4f8380987afa4 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1605,6 +1605,7 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev,
static void rtw_init_vht_cap(struct rtw_dev *rtwdev,
struct ieee80211_sta_vht_cap *vht_cap)
{
+ const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse;
u16 mcs_map = 0;
__le16 highest;
@@ -1623,10 +1624,13 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev,
0;
if (rtwdev->hal.rf_path_num > 1)
vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
- vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
- IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
- vht_cap->cap |= (rtwdev->hal.bfee_sts_cap <<
- IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
+ if (rtw_bf_support && chip->bfer_su_max_num) {
+ vht_cap->cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+ vht_cap->cap |= rtwdev->hal.bfee_sts_cap <<
+ IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+ }
+ if (rtw_bf_support && chip->bfer_mu_max_num)
+ vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
if (rtw_chip_has_rx_ldpc(rtwdev))
vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
--
2.55.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH rtw-next v2 4/7] wifi: rtw88: prepare frequency-offset correction for more chips
[not found] <20261031070950.425176-1-hjf3108@gmail.com>
` (2 preceding siblings ...)
2026-10-31 7:09 ` [PATCH rtw-next v2 3/7] wifi: rtw88: correctly expose beamformee capabilities Ho Jie Feng
@ 2026-10-31 7:09 ` Ho Jie Feng
2026-10-31 7:09 ` [PATCH rtw-next v2 5/7] wifi: rtw88: 88xxa: correct carrier-frequency offset Ho Jie Feng
` (2 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Ho Jie Feng @ 2026-10-31 7:09 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
Promote chip specific functions into the common core for cfo tracking.
These become helpers which can be used by the other drivers.
Signed-off-by: Ho Jie Feng <hjf3108@gmail.com>
---
drivers/net/wireless/realtek/rtw88/phy.c | 106 ++++++++++++++++++
drivers/net/wireless/realtek/rtw88/phy.h | 2 +
drivers/net/wireless/realtek/rtw88/rtw8822c.c | 100 +----------------
drivers/net/wireless/realtek/rtw88/rtw8822c.h | 3 -
4 files changed, 113 insertions(+), 98 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index e2515a662bb30be88920236e8b7d42791b8880c2..d0c1fb65be9563c5fc29a7d18a1c9e8589730b10 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -720,6 +720,112 @@ void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev,
}
EXPORT_SYMBOL(rtw_phy_parsing_cfo);
+#define CFO_TRK_ENABLE_TH 20
+#define CFO_TRK_STOP_TH 10
+#define CFO_TRK_ADJ_TH 10
+
+static u8 rtw_phy_cfo_tracking_reset(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_cfo_track *cfo = &dm_info->cfo_track;
+
+ cfo->is_adjust = true;
+
+ if (cfo->crystal_cap > rtwdev->efuse.crystal_cap)
+ return cfo->crystal_cap - 1;
+ else if (cfo->crystal_cap < rtwdev->efuse.crystal_cap)
+ return cfo->crystal_cap + 1;
+
+ return cfo->crystal_cap;
+}
+
+void rtw_phy_cfo_xcap_init(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_cfo_track *cfo = &dm_info->cfo_track;
+
+ cfo->crystal_cap = rtwdev->efuse.crystal_cap;
+ cfo->is_adjust = true;
+}
+EXPORT_SYMBOL(rtw_phy_cfo_xcap_init);
+
+#define REPORT_TO_KHZ(val) ({typeof(val) _v = (val); (_v << 1) + (_v >> 1); })
+static s32 rtw_phy_cfo_calc_avg(struct rtw_dev *rtwdev, u8 path_num)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_cfo_track *cfo = &dm_info->cfo_track;
+ s32 cfo_avg, cfo_path_sum = 0, cfo_rpt_sum;
+ u8 i;
+
+ for (i = 0; i < path_num; i++) {
+ cfo_rpt_sum = REPORT_TO_KHZ(cfo->cfo_tail[i]);
+
+ if (cfo->cfo_cnt[i])
+ cfo_avg = cfo_rpt_sum / cfo->cfo_cnt[i];
+ else
+ cfo_avg = 0;
+
+ cfo_path_sum += cfo_avg;
+ }
+
+ for (i = 0; i < path_num; i++) {
+ cfo->cfo_tail[i] = 0;
+ cfo->cfo_cnt[i] = 0;
+ }
+
+ return cfo_path_sum / path_num;
+}
+
+static void rtw_phy_cfo_need_adjust(struct rtw_dev *rtwdev, s32 cfo_avg)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_cfo_track *cfo = &dm_info->cfo_track;
+
+ if (!cfo->is_adjust) {
+ if (abs(cfo_avg) > CFO_TRK_ENABLE_TH)
+ cfo->is_adjust = true;
+ } else {
+ if (abs(cfo_avg) <= CFO_TRK_STOP_TH)
+ cfo->is_adjust = false;
+ }
+}
+
+u8 rtw_phy_cfo_xcap_track(struct rtw_dev *rtwdev, u8 xcap_max, bool bt_hold)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_cfo_track *cfo = &dm_info->cfo_track;
+ u8 path_num = rtwdev->hal.rf_path_num;
+ s8 crystal_cap = cfo->crystal_cap;
+ s32 cfo_avg = 0;
+
+ if (rtwdev->sta_cnt != 1)
+ return rtw_phy_cfo_tracking_reset(rtwdev);
+
+ if (cfo->packet_count == cfo->packet_count_pre)
+ return cfo->crystal_cap;
+
+ cfo->packet_count_pre = cfo->packet_count;
+ cfo_avg = rtw_phy_cfo_calc_avg(rtwdev, path_num);
+ rtw_phy_cfo_need_adjust(rtwdev, cfo_avg);
+
+ if (bt_hold) {
+ cfo->is_adjust = false;
+ return rtwdev->efuse.crystal_cap;
+ }
+
+ if (cfo->is_adjust) {
+ if (cfo_avg > CFO_TRK_ADJ_TH)
+ crystal_cap++;
+ else if (cfo_avg < -CFO_TRK_ADJ_TH)
+ crystal_cap--;
+
+ crystal_cap = clamp_t(s8, crystal_cap, 0, xcap_max);
+ }
+
+ return (u8)crystal_cap;
+}
+EXPORT_SYMBOL(rtw_phy_cfo_xcap_track);
+
static void rtw_phy_cfo_track(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h
index 8a843aac7350ad07aa64388ee712f2617120289c..b551cb860d6255ff149c76d437a7c5af1ef68b56 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.h
+++ b/drivers/net/wireless/realtek/rtw88/phy.h
@@ -68,6 +68,8 @@ void rtw_phy_adaptivity_set_mode(struct rtw_dev *rtwdev);
void rtw_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl);
void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev,
struct rtw_rx_pkt_stat *pkt_stat);
+void rtw_phy_cfo_xcap_init(struct rtw_dev *rtwdev);
+u8 rtw_phy_cfo_xcap_track(struct rtw_dev *rtwdev, u8 xcap_max, bool bt_hold);
void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev);
struct rtw_txpwr_lmt_cfg_pair {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 32d9709f2c2431a2df2f363e548f2c510fe41c34..54f012a2383912142a45cce88c3a11101f7d6464 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -4243,103 +4243,13 @@ static void rtw8822c_set_crystal_cap(struct rtw_dev *rtwdev, u8 crystal_cap)
rtw8822c_set_crystal_cap_reg(rtwdev, crystal_cap);
}
-static void rtw8822c_cfo_tracking_reset(struct rtw_dev *rtwdev)
-{
- struct rtw_dm_info *dm_info = &rtwdev->dm_info;
- struct rtw_cfo_track *cfo = &dm_info->cfo_track;
-
- cfo->is_adjust = true;
-
- if (cfo->crystal_cap > rtwdev->efuse.crystal_cap)
- rtw8822c_set_crystal_cap(rtwdev, cfo->crystal_cap - 1);
- else if (cfo->crystal_cap < rtwdev->efuse.crystal_cap)
- rtw8822c_set_crystal_cap(rtwdev, cfo->crystal_cap + 1);
-}
-
-static void rtw8822c_cfo_init(struct rtw_dev *rtwdev)
-{
- struct rtw_dm_info *dm_info = &rtwdev->dm_info;
- struct rtw_cfo_track *cfo = &dm_info->cfo_track;
-
- cfo->crystal_cap = rtwdev->efuse.crystal_cap;
- cfo->is_adjust = true;
-}
-
-#define REPORT_TO_KHZ(val) ({typeof(val) _v = (val); (_v << 1) + (_v >> 1); })
-static s32 rtw8822c_cfo_calc_avg(struct rtw_dev *rtwdev, u8 path_num)
-{
- struct rtw_dm_info *dm_info = &rtwdev->dm_info;
- struct rtw_cfo_track *cfo = &dm_info->cfo_track;
- s32 cfo_avg, cfo_path_sum = 0, cfo_rpt_sum;
- u8 i;
-
- for (i = 0; i < path_num; i++) {
- cfo_rpt_sum = REPORT_TO_KHZ(cfo->cfo_tail[i]);
-
- if (cfo->cfo_cnt[i])
- cfo_avg = cfo_rpt_sum / cfo->cfo_cnt[i];
- else
- cfo_avg = 0;
-
- cfo_path_sum += cfo_avg;
- }
-
- for (i = 0; i < path_num; i++) {
- cfo->cfo_tail[i] = 0;
- cfo->cfo_cnt[i] = 0;
- }
-
- return cfo_path_sum / path_num;
-}
-
-static void rtw8822c_cfo_need_adjust(struct rtw_dev *rtwdev, s32 cfo_avg)
-{
- struct rtw_dm_info *dm_info = &rtwdev->dm_info;
- struct rtw_cfo_track *cfo = &dm_info->cfo_track;
-
- if (!cfo->is_adjust) {
- if (abs(cfo_avg) > CFO_TRK_ENABLE_TH)
- cfo->is_adjust = true;
- } else {
- if (abs(cfo_avg) <= CFO_TRK_STOP_TH)
- cfo->is_adjust = false;
- }
-
- if (!rtw_coex_disabled(rtwdev)) {
- cfo->is_adjust = false;
- rtw8822c_set_crystal_cap(rtwdev, rtwdev->efuse.crystal_cap);
- }
-}
-
static void rtw8822c_cfo_track(struct rtw_dev *rtwdev)
{
- struct rtw_dm_info *dm_info = &rtwdev->dm_info;
- struct rtw_cfo_track *cfo = &dm_info->cfo_track;
- u8 path_num = rtwdev->hal.rf_path_num;
- s8 crystal_cap = cfo->crystal_cap;
- s32 cfo_avg = 0;
-
- if (rtwdev->sta_cnt != 1) {
- rtw8822c_cfo_tracking_reset(rtwdev);
- return;
- }
-
- if (cfo->packet_count == cfo->packet_count_pre)
- return;
-
- cfo->packet_count_pre = cfo->packet_count;
- cfo_avg = rtw8822c_cfo_calc_avg(rtwdev, path_num);
- rtw8822c_cfo_need_adjust(rtwdev, cfo_avg);
-
- if (cfo->is_adjust) {
- if (cfo_avg > CFO_TRK_ADJ_TH)
- crystal_cap++;
- else if (cfo_avg < -CFO_TRK_ADJ_TH)
- crystal_cap--;
+ u8 crystal_cap;
- crystal_cap = clamp_t(s8, crystal_cap, 0, XCAP_MASK);
- rtw8822c_set_crystal_cap(rtwdev, (u8)crystal_cap);
- }
+ crystal_cap = rtw_phy_cfo_xcap_track(rtwdev, XCAP_MASK,
+ !rtw_coex_disabled(rtwdev));
+ rtw8822c_set_crystal_cap(rtwdev, crystal_cap);
}
static const struct rtw_phy_cck_pd_reg
@@ -4985,7 +4895,7 @@ static const struct rtw_chip_ops rtw8822c_ops = {
.cfg_csi_rate = rtw_bf_cfg_csi_rate,
.adaptivity_init = rtw8822c_adaptivity_init,
.adaptivity = rtw8822c_adaptivity,
- .cfo_init = rtw8822c_cfo_init,
+ .cfo_init = rtw_phy_cfo_xcap_init,
.cfo_track = rtw8822c_cfo_track,
.config_tx_path = rtw8822c_config_tx_path,
.config_txrx_mode = rtw8822c_config_trx_mode,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
index fc62b67a15f216496bfb572a55366f900a2d6734..c27e4c394a435cb11fc755bb8806ee1b51a30e47 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
@@ -181,9 +181,6 @@ const struct rtw_table name ## _tbl = { \
#define REG_ANAPARLDO_POW_MAC 0x0029
#define BIT_LDOE25_PON BIT(0)
#define XCAP_MASK GENMASK(6, 0)
-#define CFO_TRK_ENABLE_TH 20
-#define CFO_TRK_STOP_TH 10
-#define CFO_TRK_ADJ_TH 10
#define REG_TXDFIR0 0x808
#define REG_DFIRBW 0x810
--
2.55.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH rtw-next v2 5/7] wifi: rtw88: 88xxa: correct carrier-frequency offset
[not found] <20261031070950.425176-1-hjf3108@gmail.com>
` (3 preceding siblings ...)
2026-10-31 7:09 ` [PATCH rtw-next v2 4/7] wifi: rtw88: prepare frequency-offset correction for more chips Ho Jie Feng
@ 2026-10-31 7:09 ` Ho Jie Feng
2026-11-06 17:27 ` Luka Gejak
2026-10-31 7:09 ` [PATCH rtw-next v2 6/7] wifi: rtw88: 88xxa: adapt channel sensing to receiver gain Ho Jie Feng
2026-10-31 7:09 ` [PATCH rtw-next v2 7/7] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits Ho Jie Feng
6 siblings, 1 reply; 15+ messages in thread
From: Ho Jie Feng @ 2026-10-31 7:09 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
Use the newly promoted helpers to implement support for 88xxa
Signed-off-by: Ho Jie Feng <hjf3108@gmail.com>
---
drivers/net/wireless/realtek/rtw88/phy.c | 5 +-
drivers/net/wireless/realtek/rtw88/rtw8812a.c | 2 +
drivers/net/wireless/realtek/rtw88/rtw8814a.c | 31 ++++++++++--
drivers/net/wireless/realtek/rtw88/rtw8821a.c | 2 +
drivers/net/wireless/realtek/rtw88/rtw88xxa.c | 47 +++++++++++++++----
drivers/net/wireless/realtek/rtw88/rtw88xxa.h | 1 +
6 files changed, 73 insertions(+), 15 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index d0c1fb65be9563c5fc29a7d18a1c9e8589730b10..69998c0d7c1f851bb30d2702233d62e14b305bf0 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -687,13 +687,14 @@ static void rtw_phy_parsing_cfo_iter(void *data, u8 *mac,
struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat;
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
+ u8 path_num = min_t(u8, rtwdev->hal.rf_path_num, 2);
u8 *bssid = iter_data->bssid;
u8 i;
if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
return;
- for (i = 0; i < rtwdev->hal.rf_path_num; i++) {
+ for (i = 0; i < path_num; i++) {
cfo->cfo_tail[i] += pkt_stat->cfo_tail[i];
cfo->cfo_cnt[i]++;
}
@@ -794,7 +795,7 @@ u8 rtw_phy_cfo_xcap_track(struct rtw_dev *rtwdev, u8 xcap_max, bool bt_hold)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
- u8 path_num = rtwdev->hal.rf_path_num;
+ u8 path_num = min_t(u8, rtwdev->hal.rf_path_num, 2);
s8 crystal_cap = cfo->crystal_cap;
s32 cfo_avg = 0;
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
index 5d58dff4fcee7c4b3194794266cb48cd472014f9..c8008cf43da9df68a8c1dfb277d529a1191bda01 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
@@ -943,6 +943,8 @@ static const struct rtw_chip_ops rtw8812a_ops = {
.coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type,
.coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power,
.coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain,
+ .cfo_init = rtw_phy_cfo_xcap_init,
+ .cfo_track = rtw88xxa_cfo_track,
};
static const struct rtw_page_table page_table_8812a[] = {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
index 2db05a83766d65123edc95f50a40d3f93bfb1dba..3c65cd838ce15f0149852cd488e88f78e709efe1 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
@@ -145,7 +145,7 @@ static int rtw8814a_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
efuse->usb_mode_switch = u8_get_bits(map->usb_mode, BIT(4));
efuse->rfe_option = map->rfe_option;
efuse->rf_board_option = map->rf_board_option;
- efuse->crystal_cap = map->xtal_k;
+ efuse->crystal_cap = map->xtal_k & 0x3f;
efuse->channel_plan = map->channel_plan;
efuse->country_code[0] = map->country_code[0];
efuse->country_code[1] = map->country_code[1];
@@ -284,9 +284,15 @@ static void rtw8814a_config_cck_rx_antenna_init(struct rtw_dev *rtwdev)
rtw_write32_mask(rtwdev, REG_CCKTX, BIT_CMB_CCA_2R, 1);
}
+static void rtw8814a_set_crystal_cap(struct rtw_dev *rtwdev, u8 crystal_cap)
+{
+ rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x07ff8000,
+ crystal_cap | (crystal_cap << 6));
+}
+
static void rtw8814a_phy_set_param(struct rtw_dev *rtwdev)
{
- u32 crystal_cap, val32;
+ u32 val32;
u8 val8, rf_path;
/* power on BB/RF domain */
@@ -308,9 +314,7 @@ static void rtw8814a_phy_set_param(struct rtw_dev *rtwdev)
rtw_load_table(rtwdev, rtwdev->chip->bb_tbl);
rtw_load_table(rtwdev, rtwdev->chip->agc_tbl);
- crystal_cap = rtwdev->efuse.crystal_cap & 0x3F;
- crystal_cap |= crystal_cap << 6;
- rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x07ff8000, crystal_cap);
+ rtw8814a_set_crystal_cap(rtwdev, rtwdev->efuse.crystal_cap);
rtw8814a_config_trx_path(rtwdev);
@@ -1269,6 +1273,8 @@ static void rtw8814a_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
pkt_stat->cfo_tail[i] = cfo[i];
dm_info->cfo_tail[i] = (cfo[i] * 5) >> 1;
}
+
+ rtw_phy_parsing_cfo(rtwdev, pkt_stat);
}
}
@@ -2068,6 +2074,19 @@ static void rtw8814a_bf_config_bfee(struct rtw_dev *rtwdev,
rtw_bf_remove_bfee_su(rtwdev, bfee);
}
+static void rtw8814a_cfo_track(struct rtw_dev *rtwdev)
+{
+ struct rtw_cfo_track *cfo = &rtwdev->dm_info.cfo_track;
+ u8 crystal_cap;
+
+ crystal_cap = rtw_phy_cfo_xcap_track(rtwdev, 0x3f, false);
+ if (crystal_cap == cfo->crystal_cap)
+ return;
+
+ cfo->crystal_cap = crystal_cap;
+ rtw8814a_set_crystal_cap(rtwdev, crystal_cap);
+}
+
static void rtw8814a_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
@@ -2102,6 +2121,8 @@ static const struct rtw_chip_ops rtw8814a_ops = {
.cfg_csi_rate = NULL,
.led_set = rtw8814a_led_set,
.fill_txdesc_checksum = rtw8814a_fill_txdesc_checksum,
+ .cfo_init = rtw_phy_cfo_xcap_init,
+ .cfo_track = rtw8814a_cfo_track,
.coex_set_init = rtw8814a_coex_cfg_init,
.coex_set_ant_switch = rtw8814a_coex_cfg_ant_switch,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
index 6d106ae70d9142b45337057311dc423158e7dabc..17d3677ca463cf633d8c138612deaa676bc02986 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
@@ -889,6 +889,8 @@ static const struct rtw_chip_ops rtw8821a_ops = {
.coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type,
.coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power,
.coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain,
+ .cfo_init = rtw_phy_cfo_xcap_init,
+ .cfo_track = rtw88xxa_cfo_track,
};
static const struct rtw_page_table page_table_8821a[] = {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
index 87253fffe78cd6f5b58a325eef42b58b968e2d46..851d198f76f3b10d5ba77c7e07e4be9d7fd54e4b 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
@@ -279,6 +279,7 @@ int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
efuse->crystal_cap = map->xtal_k;
if (efuse->crystal_cap == 0xff)
efuse->crystal_cap = 0x20;
+ efuse->crystal_cap &= 0x3F;
efuse->pa_type_2g = map->pa_type;
efuse->pa_type_5g = map->pa_type;
efuse->lna_type_2g = map->lna_type_2g;
@@ -632,9 +633,19 @@ static void rtw88xxa_init_beacon_parameters(struct rtw_dev *rtwdev)
rtw_write16(rtwdev, REG_BCNTCFG, 0x4413);
}
+static void rtw88xxa_set_crystal_cap(struct rtw_dev *rtwdev, u8 crystal_cap)
+{
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
+ rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x7FF80000,
+ crystal_cap | (crystal_cap << 6));
+ else
+ rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x00FFF000,
+ crystal_cap | (crystal_cap << 6));
+}
+
static void rtw88xxa_phy_bb_config(struct rtw_dev *rtwdev)
{
- u8 val8, crystal_cap;
+ u8 val8;
/* power on BB/RF domain */
val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
@@ -653,13 +664,7 @@ static void rtw88xxa_phy_bb_config(struct rtw_dev *rtwdev)
rtw_load_table(rtwdev, rtwdev->chip->bb_tbl);
rtw_load_table(rtwdev, rtwdev->chip->agc_tbl);
- crystal_cap = rtwdev->efuse.crystal_cap & 0x3F;
- if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
- rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x7FF80000,
- crystal_cap | (crystal_cap << 6));
- else
- rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x00FFF000,
- crystal_cap | (crystal_cap << 6));
+ rtw88xxa_set_crystal_cap(rtwdev, rtwdev->efuse.crystal_cap & 0x3F);
}
static void rtw88xxa_phy_rf_config(struct rtw_dev *rtwdev)
@@ -1621,6 +1626,17 @@ void rtw88xxa_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
power_b = power_a;
pkt_stat->signal_power = max3(power_a, power_b, min_rx_power);
+
+ pkt_stat->cfo_tail[RF_PATH_A] =
+ (s8)le32_get_bits(rpt->w2, RTW_JGRPHY_W2_CFO_TAIL_A);
+ pkt_stat->cfo_tail[RF_PATH_B] =
+ (s8)le32_get_bits(rpt->w2, RTW_JGRPHY_W2_CFO_TAIL_B);
+
+ /* convert to kHz (used only for debugfs) */
+ for (i = RF_PATH_A; i < rtwdev->hal.rf_path_num; i++)
+ dm_info->cfo_tail[i] = (pkt_stat->cfo_tail[i] * 5) >> 1;
+
+ rtw_phy_parsing_cfo(rtwdev, pkt_stat);
}
}
EXPORT_SYMBOL(rtw88xxa_query_phy_status);
@@ -2009,6 +2025,21 @@ void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev,
}
EXPORT_SYMBOL(rtw88xxa_phy_pwrtrack);
+void rtw88xxa_cfo_track(struct rtw_dev *rtwdev)
+{
+ struct rtw_cfo_track *cfo = &rtwdev->dm_info.cfo_track;
+ bool bt_hold = rtwdev->efuse.btcoex && !rtw_coex_disabled(rtwdev);
+ u8 crystal_cap;
+
+ crystal_cap = rtw_phy_cfo_xcap_track(rtwdev, 0x3F, bt_hold);
+ if (crystal_cap == cfo->crystal_cap)
+ return;
+
+ cfo->crystal_cap = crystal_cap;
+ rtw88xxa_set_crystal_cap(rtwdev, crystal_cap);
+}
+EXPORT_SYMBOL(rtw88xxa_cfo_track);
+
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a/8812a common code");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
index 0aaf7aa4aafdd396bff25a8fcd880a5514e589ba..09b72d33f62e1e99a2ac5af23ac1630dabb38ef9 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
@@ -172,5 +172,6 @@ void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev,
void (*do_iqk)(struct rtw_dev *rtwdev));
void rtw88xxa_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif,
struct rtw_bfee *bfee, bool enable);
+void rtw88xxa_cfo_track(struct rtw_dev *rtwdev);
#endif
--
2.55.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH rtw-next v2 5/7] wifi: rtw88: 88xxa: correct carrier-frequency offset
2026-10-31 7:09 ` [PATCH rtw-next v2 5/7] wifi: rtw88: 88xxa: correct carrier-frequency offset Ho Jie Feng
@ 2026-11-06 17:27 ` Luka Gejak
0 siblings, 0 replies; 15+ messages in thread
From: Luka Gejak @ 2026-11-06 17:27 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
Hi Jie Feng,
A few small comments below.
October 31, 2026 at 8:09 AM, "Ho Jie Feng" <hjf3108@gmail.com> wrote:
> diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
> index d0c1fb65be9563c5fc29a7d18a1c9e8589730b10..69998c0d7c1f851bb30d2702233d62e14b305bf0 100644
> --- a/drivers/net/wireless/realtek/rtw88/phy.c
> +++ b/drivers/net/wireless/realtek/rtw88/phy.c
> @@ -687,13 +687,14 @@ static void rtw_phy_parsing_cfo_iter(void *data, u8 *mac,
> struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat;
> struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> struct rtw_cfo_track *cfo = &dm_info->cfo_track;
> + u8 path_num = min_t(u8, rtwdev->hal.rf_path_num, 2);
This and the same line in rtw_phy_cfo_xcap_track() are in core code that
every chip uses. As far as I can see the limit is only there for 8814a,
which has four paths but reports a CFO tail only for A and B. A short
comment saying so would help, otherwise the 2 looks arbitrary.
The commit message could mention this core change too, together with
the CFO tracking for 8814a that this patch adds.
[ ... ]
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> index 87253fffe78cd6f5b58a325eef42b58b968e2d46..851d198f76f3b10d5ba77c7e07e4be9d7fd54e4b 100644
> --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> @@ -279,6 +279,7 @@ int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
> efuse->crystal_cap = map->xtal_k;
> if (efuse->crystal_cap == 0xff)
> efuse->crystal_cap = 0x20;
> + efuse->crystal_cap &= 0x3F;
[ ... ]
> + rtw88xxa_set_crystal_cap(rtwdev, rtwdev->efuse.crystal_cap & 0x3F);
With the mask in rtw88xxa_read_efuse() the & 0x3F here isn't needed
anymore.
The 6 bit limit now shows up as 0x3F or 0x3f in five places across
rtw88xxa.c and rtw8814a.c. Maybe a define in rtw88xxa.h, which
rtw8814a.c includes too, similar to XCAP_MASK in rtw8822c.h.
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH rtw-next v2 6/7] wifi: rtw88: 88xxa: adapt channel sensing to receiver gain
[not found] <20261031070950.425176-1-hjf3108@gmail.com>
` (4 preceding siblings ...)
2026-10-31 7:09 ` [PATCH rtw-next v2 5/7] wifi: rtw88: 88xxa: correct carrier-frequency offset Ho Jie Feng
@ 2026-10-31 7:09 ` Ho Jie Feng
2026-11-06 17:34 ` Luka Gejak
2026-10-31 7:09 ` [PATCH rtw-next v2 7/7] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits Ho Jie Feng
6 siblings, 1 reply; 15+ messages in thread
From: Ho Jie Feng @ 2026-10-31 7:09 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
Implement adaptivity for 88xxa, since they support it in
the hardware.
Signed-off-by: Ho Jie Feng <hjf3108@gmail.com>
---
drivers/net/wireless/realtek/rtw88/main.h | 1 +
drivers/net/wireless/realtek/rtw88/phy.c | 7 +
drivers/net/wireless/realtek/rtw88/rtw8812a.c | 10 ++
drivers/net/wireless/realtek/rtw88/rtw8821a.c | 10 ++
drivers/net/wireless/realtek/rtw88/rtw88xxa.c | 125 ++++++++++++++++++
drivers/net/wireless/realtek/rtw88/rtw88xxa.h | 5 +
6 files changed, 158 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index d59f6e323adf0c9bf9aeab7a62adb77e3e5f9d74..796fea308fdf7bf2b46f42c703b1b518327e1e0a 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -1787,6 +1787,7 @@ struct rtw_dm_info {
bool is_bt_iqk_timeout;
s8 l2h_th_ini;
+ s8 l2h_th_lb;
enum rtw_edcca_mode edcca_mode;
u8 scan_density;
};
diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index 69998c0d7c1f851bb30d2702233d62e14b305bf0..7a04aec9a045f1e308a4c5d331c900e013996bd5 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -377,6 +377,10 @@ void rtw_phy_dig_set_max_coverage(struct rtw_dev *rtwdev)
DIG_CVRG_MIN);
rtw_phy_dig_write(rtwdev, DIG_CVRG_MIN);
+
+ /* EDCCA thresholds can be relative to the IGI */
+ if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_ADAPTIVITY))
+ rtw_phy_adaptivity(rtwdev);
}
void rtw_phy_dig_reset(struct rtw_dev *rtwdev)
@@ -388,6 +392,9 @@ void rtw_phy_dig_reset(struct rtw_dev *rtwdev)
rtw_dbg(rtwdev, RTW_DBG_PHY, "Resetting IGI=%#x\n", last_igi);
rtw_phy_dig_write(rtwdev, last_igi);
+
+ if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_ADAPTIVITY))
+ rtw_phy_adaptivity(rtwdev);
}
static bool
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
index c8008cf43da9df68a8c1dfb277d529a1191bda01..d93c4776e0303f52273d92eaa75341ebbcfcb066 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
@@ -945,6 +945,8 @@ static const struct rtw_chip_ops rtw8812a_ops = {
.coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain,
.cfo_init = rtw_phy_cfo_xcap_init,
.cfo_track = rtw88xxa_cfo_track,
+ .adaptivity_init = rtw88xxa_adaptivity_init,
+ .adaptivity = rtw88xxa_adaptivity,
};
static const struct rtw_page_table page_table_8812a[] = {
@@ -999,6 +1001,11 @@ static const struct rtw_hw_reg rtw8812a_dig[] = {
[1] = { .addr = REG_RXIGI_B, .mask = 0x7f },
};
+static const struct rtw_hw_reg_offset rtw8812a_edcca_th[] = {
+ [EDCCA_TH_L2H_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE0}, .offset = 0},
+ [EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0},
+};
+
static const struct rtw_rfe_def rtw8812a_rfe_defs[] = {
[0] = { .phy_pg_tbl = &rtw8812a_bb_pg_tbl,
.txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl,
@@ -1089,6 +1096,9 @@ const struct rtw_chip_info rtw8812a_hw_spec = {
.bfer_su_max_num = 2,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
+ .edcca_th = rtw8812a_edcca_th,
+ .l2h_th_ini_cs = 10,
+ .l2h_th_ini_ad = -17,
.coex_para_ver = 0, /* no coex code in 8812au driver */
.bt_desired_ver = 0,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
index 17d3677ca463cf633d8c138612deaa676bc02986..f7391f6aa3039c7ba4d88249d968a5f1763ea866 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
@@ -891,6 +891,8 @@ static const struct rtw_chip_ops rtw8821a_ops = {
.coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain,
.cfo_init = rtw_phy_cfo_xcap_init,
.cfo_track = rtw88xxa_cfo_track,
+ .adaptivity_init = rtw88xxa_adaptivity_init,
+ .adaptivity = rtw88xxa_adaptivity,
};
static const struct rtw_page_table page_table_8821a[] = {
@@ -944,6 +946,11 @@ static const struct rtw_hw_reg rtw8821a_dig[] = {
[0] = { .addr = REG_RXIGI_A, .mask = 0x7f },
};
+static const struct rtw_hw_reg_offset rtw8821a_edcca_th[] = {
+ [EDCCA_TH_L2H_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE0}, .offset = 0},
+ [EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0},
+};
+
static const struct rtw_rfe_def rtw8821a_rfe_defs[] = {
[0] = { .phy_pg_tbl = &rtw8821a_bb_pg_tbl,
.txpwr_lmt_tbl = &rtw8821a_txpwr_lmt_tbl,
@@ -1193,6 +1200,9 @@ const struct rtw_chip_info rtw8821a_hw_spec = {
.bfer_su_max_num = 2,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
+ .edcca_th = rtw8821a_edcca_th,
+ .l2h_th_ini_cs = 10,
+ .l2h_th_ini_ad = -17,
.coex_para_ver = 20190509, /* glcoex_ver_date_8821a_1ant */
.bt_desired_ver = 0x62, /* But for 2 ant it's 0x5c */
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
index 851d198f76f3b10d5ba77c7e07e4be9d7fd54e4b..ee72380757721dab7dc409aabc24b2b825969465 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
@@ -2040,6 +2040,131 @@ void rtw88xxa_cfo_track(struct rtw_dev *rtwdev)
}
EXPORT_SYMBOL(rtw88xxa_cfo_track);
+#define EDCCA_TH_MAX_88XXA 0x7f
+#define EDCCA_L2H_CAP_88XXA 10
+#define EDCCA_L2H_INI_NORMAL_88XXA 20
+#define EDCCA_DBG_PORT_88XXA 0x209
+#define EDCCA_DC_BACKOFF_88XXA 2
+#define EDCCA_LB_START_88XXA (EDCCA_L2H_H2L_DIFF - 30)
+#define EDCCA_LB_RETRY_88XXA (EDCCA_LB_START_88XXA + 18)
+
+static void rtw88xxa_set_rf_mode_rx(struct rtw_dev *rtwdev, u32 data0,
+ u32 data1)
+{
+ u8 path;
+
+ for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) {
+ rtw_write_rf(rtwdev, path, RF_LUTWE, BIT(19), 1);
+ rtw_write_rf(rtwdev, path, RF_MODE_TABLE_ADDR, RFREG_MASK,
+ 0x18000);
+ rtw_write_rf(rtwdev, path, RF_MODE_TABLE_DATA0, RFREG_MASK,
+ data0);
+ rtw_write_rf(rtwdev, path, RF_MODE_TABLE_DATA1, RFREG_MASK,
+ data1);
+ rtw_write_rf(rtwdev, path, RF_LUTWE, BIT(19), 0);
+ }
+}
+
+static void rtw88xxa_set_lna(struct rtw_dev *rtwdev, bool enable)
+{
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
+ rtw88xxa_set_rf_mode_rx(rtwdev, 0x3f7ff,
+ enable ? 0xc26bf : 0xc22bf);
+ else
+ rtw88xxa_set_rf_mode_rx(rtwdev, 0x0002f,
+ enable ? 0xfb0bb : 0xfb09b);
+}
+
+static u8 rtw88xxa_edcca_count(struct rtw_dev *rtwdev)
+{
+ u8 cnt = 0;
+ int i;
+
+ rtw_write32(rtwdev, REG_DBGSEL, 0);
+ for (i = 0; i < 3 &&
+ rtw_read32(rtwdev, REG_DBGRPT) & BIT_DBG_CCA_BUSY; i++)
+ usleep_range(3000, 3500);
+
+ rtw_write32(rtwdev, REG_DBGSEL, EDCCA_DBG_PORT_88XXA);
+ for (i = 0; i < 20; i++)
+ if (rtw_read32(rtwdev, REG_DBGRPT) & BIT_DBG_EDCCA_BUSY)
+ cnt++;
+
+ return cnt;
+}
+
+static s8 rtw88xxa_edcca_search_floor(struct rtw_dev *rtwdev)
+{
+ s8 l2h = EDCCA_LB_START_88XXA;
+
+ rtw_phy_set_edcca_th(rtwdev, l2h, l2h - EDCCA_L2H_H2L_DIFF);
+ msleep(30);
+
+ while (l2h < EDCCA_L2H_CAP_88XXA && rtw88xxa_edcca_count(rtwdev) > 1) {
+ l2h++;
+ rtw_phy_set_edcca_th(rtwdev, l2h, l2h - EDCCA_L2H_H2L_DIFF);
+ }
+
+ return l2h;
+}
+
+void rtw88xxa_adaptivity_init(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u32 dbgsel = rtw_read32(rtwdev, REG_DBGSEL);
+ s8 l2h;
+
+ rtw_write32_clr(rtwdev, REG_TX_PTCL_CTRL, BIT_DIS_EDCCA);
+
+ rtw88xxa_set_lna(rtwdev, false);
+ l2h = rtw88xxa_edcca_search_floor(rtwdev);
+ if (l2h >= EDCCA_LB_RETRY_88XXA)
+ l2h = rtw88xxa_edcca_search_floor(rtwdev);
+ rtw88xxa_set_lna(rtwdev, true);
+ rtw_write32(rtwdev, REG_DBGSEL, dbgsel);
+
+ dm_info->l2h_th_lb = l2h + EDCCA_DC_BACKOFF_88XXA;
+ rtw_phy_set_edcca_th(rtwdev, EDCCA_TH_MAX_88XXA, EDCCA_TH_MAX_88XXA);
+
+ rtw_dbg(rtwdev, RTW_DBG_ADAPTIVITY, "EDCCA L2H floor %d\n",
+ dm_info->l2h_th_lb);
+}
+EXPORT_SYMBOL(rtw88xxa_adaptivity_init);
+
+void rtw88xxa_adaptivity(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ /* igi_history[0] keeps the pre-scan IGI while scanning */
+ u8 igi = rtw_read32_mask(rtwdev, REG_RXIGI_A, 0x7f);
+ int igi_diff = EDCCA_IGI_BASE - igi;
+ s8 l2h_lb = dm_info->l2h_th_lb;
+ s8 l2h, h2l;
+
+ /* toggle the ADC mask to work around an EDCCA hang */
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) {
+ rtw_write32_set(rtwdev, REG_FPGA0_RFMOD, BIT(10));
+ rtw_write32_clr(rtwdev, REG_FPGA0_RFMOD, BIT(10));
+ }
+
+ if (dm_info->edcca_mode == RTW_EDCCA_ADAPTIVITY) {
+ l2h = min(dm_info->l2h_th_ini + igi_diff, EDCCA_L2H_CAP_88XXA);
+ h2l = l2h - EDCCA_L2H_H2L_DIFF;
+ } else {
+ l2h = EDCCA_L2H_INI_NORMAL_88XXA + igi_diff;
+ h2l = l2h - EDCCA_L2H_H2L_DIFF_NORMAL;
+ }
+
+ l2h = max(l2h, l2h_lb);
+ h2l = max_t(s8, h2l, l2h_lb - EDCCA_L2H_H2L_DIFF);
+
+ rtw_phy_set_edcca_th(rtwdev, l2h, h2l);
+
+ rtw_dbg(rtwdev, RTW_DBG_ADAPTIVITY,
+ "EDCCA mode %d, IGI 0x%x, L2H %d, H2L %d\n",
+ dm_info->edcca_mode, igi, l2h, h2l);
+}
+EXPORT_SYMBOL(rtw88xxa_adaptivity);
+
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a/8812a common code");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
index 09b72d33f62e1e99a2ac5af23ac1630dabb38ef9..b8719c278df7326842e09509fc52d12f226fd417 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
@@ -139,6 +139,9 @@ struct rtw_jaguar_phy_status_rpt {
#define RF18_BW_MASK (BIT(11) | BIT(10))
+#define BIT_DBG_CCA_BUSY BIT(3)
+#define BIT_DBG_EDCCA_BUSY BIT(29)
+
void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on);
int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map);
void rtw88xxa_power_off(struct rtw_dev *rtwdev,
@@ -173,5 +176,7 @@ void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev,
void rtw88xxa_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif,
struct rtw_bfee *bfee, bool enable);
void rtw88xxa_cfo_track(struct rtw_dev *rtwdev);
+void rtw88xxa_adaptivity_init(struct rtw_dev *rtwdev);
+void rtw88xxa_adaptivity(struct rtw_dev *rtwdev);
#endif
--
2.55.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH rtw-next v2 6/7] wifi: rtw88: 88xxa: adapt channel sensing to receiver gain
2026-10-31 7:09 ` [PATCH rtw-next v2 6/7] wifi: rtw88: 88xxa: adapt channel sensing to receiver gain Ho Jie Feng
@ 2026-11-06 17:34 ` Luka Gejak
2026-11-06 19:46 ` Bitterblue Smith
0 siblings, 1 reply; 15+ messages in thread
From: Luka Gejak @ 2026-11-06 17:34 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih
Cc: linux-wireless, Ho Jie Feng, linux-kernel, Bitterblue Smith
Hi Jie Feng and Bitterblue,
Thanks for fixing the scan latency. A few comments below.
> diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
> index 69998c0d7c1f851bb30d2702233d62e14b305bf0..7a04aec9a045f1e308a4c5d331c900e013996bd5 100644
> --- a/drivers/net/wireless/realtek/rtw88/phy.c
> +++ b/drivers/net/wireless/realtek/rtw88/phy.c
> @@ -377,6 +377,10 @@ void rtw_phy_dig_set_max_coverage(struct rtw_dev *rtwdev)
> DIG_CVRG_MIN);
>
> rtw_phy_dig_write(rtwdev, DIG_CVRG_MIN);
> +
> + /* EDCCA thresholds can be relative to the IGI */
> + if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_ADAPTIVITY))
> + rtw_phy_adaptivity(rtwdev);
> }
This and the call in rtw_phy_dig_reset() also reach
rtw8822b_adaptivity() and rtw8822c_adaptivity() when the firmware
doesn't handle adaptivity. They use igi_history[0], so as far as I can
see they just write the same thresholds again, but since this is core
code it would be good to mention it in the commit message.
[ ... ]
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> index 851d198f76f3b10d5ba77c7e07e4be9d7fd54e4b..ee72380757721dab7dc409aabc24b2b825969465 100644
> --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
[ ... ]
> +#define EDCCA_LB_START_88XXA (EDCCA_L2H_H2L_DIFF - 30)
> +#define EDCCA_LB_RETRY_88XXA (EDCCA_LB_START_88XXA + 18)
Maybe a short comment on where the 18 comes from. As far as I can see it
is the vendor condition for searching a second time (IGI upper bound of
0x26 or lower), worked out for an initial L2H of -17.
[ ... ]
> + rtw_write32(rtwdev, REG_DBGSEL, 0);
> + for (i = 0; i < 3 &&
> + rtw_read32(rtwdev, REG_DBGRPT) & BIT_DBG_CCA_BUSY; i++)
> + usleep_range(3000, 3500);
The register read in the loop condition is a bit hard to follow. Maybe
read_poll_timeout() would read easier, like efuse.c uses it:
read_poll_timeout(rtw_read32, val, !(val & BIT_DBG_CCA_BUSY),
3000, 9000, false, rtwdev, REG_DBGRPT);
[ ... ]
> +void rtw88xxa_adaptivity_init(struct rtw_dev *rtwdev)
> +{
> + struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> + u32 dbgsel = rtw_read32(rtwdev, REG_DBGSEL);
> + s8 l2h;
> +
> + rtw_write32_clr(rtwdev, REG_TX_PTCL_CTRL, BIT_DIS_EDCCA);
Bitterblue reported on that "firmware failed to leave lps state" shows
up a lot more often with this patch and stops when EDCCA is disabled,
and you replied that it only prints a line in dmesg. On rtw-next it is
more than a message now. Since dc16902cad9c ("wifi: rtw88: ps: Trigger
firmware recovery when failing to leave LPS state"), rtw_fw_leave_lps_check()
goes on to a firmware recovery after the warning:
rtw_warn(rtwdev, "firmware failed to leave lps state\n");
rtw_fw_dump_dbg_info(rtwdev);
rtw_fw_recovery(rtwdev);
So a failed leave now ends in a firmware recovery, with a "firmware
crash, start reset and recover" WARN and ieee80211_restart_hw(). With
power saving on, rtw_watch_dog_work() calls rtw_leave_lps() every 2
seconds before the dynamic mechanisms, so I think this needs to be
solved before the patch can go in.
About a longer timeout, according to the comment in
__rtw_fw_leave_lps_check_reg() the firmware restores REG_TCR once the AP
has acked its null frame, so I think it would mostly hide the problem.
Leaving this patch out of v3 and sending it again once the cause is
known sounds fine to me, then the rest of the series doesn't have to
wait.
Bitterblue, did you turn EDCCA off through the edcca_enable debugfs file?
With this patch that only switches to RTW_EDCCA_NORMAL, and
rtw88xxa_adaptivity() then keeps EDCCA on with the higher normal
thresholds. If that is what made it stop, it would point at the
thresholds used in adaptivity mode (ETSI and JP regions) rather than at
EDCCA itself.
Jie Feng, maybe comparing the IGI in the hardware when the leave fails
with the IGI the thresholds were computed from would show more.
[ ... ]
> + /* igi_history[0] keeps the pre-scan IGI while scanning */
> + u8 igi = rtw_read32_mask(rtwdev, REG_RXIGI_A, 0x7f);
The comment sits on a line that doesn't use igi_history[0], so it reads
a bit confusing. Maybe something like "read the IGI in use,
igi_history[0] still holds the old value while scanning".
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH rtw-next v2 6/7] wifi: rtw88: 88xxa: adapt channel sensing to receiver gain
2026-11-06 17:34 ` Luka Gejak
@ 2026-11-06 19:46 ` Bitterblue Smith
2026-11-06 20:27 ` Luka Gejak
0 siblings, 1 reply; 15+ messages in thread
From: Bitterblue Smith @ 2026-11-06 19:46 UTC (permalink / raw)
To: Luka Gejak, Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, linux-kernel
On 06/11/2026 19:34, Luka Gejak wrote:
> Hi Jie Feng and Bitterblue,
>
> Thanks for fixing the scan latency. A few comments below.
>
>> diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
>> index 69998c0d7c1f851bb30d2702233d62e14b305bf0..7a04aec9a045f1e308a4c5d331c900e013996bd5 100644
>> --- a/drivers/net/wireless/realtek/rtw88/phy.c
>> +++ b/drivers/net/wireless/realtek/rtw88/phy.c
>> @@ -377,6 +377,10 @@ void rtw_phy_dig_set_max_coverage(struct rtw_dev *rtwdev)
>> DIG_CVRG_MIN);
>>
>> rtw_phy_dig_write(rtwdev, DIG_CVRG_MIN);
>> +
>> + /* EDCCA thresholds can be relative to the IGI */
>> + if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_ADAPTIVITY))
>> + rtw_phy_adaptivity(rtwdev);
>> }
>
> This and the call in rtw_phy_dig_reset() also reach
> rtw8822b_adaptivity() and rtw8822c_adaptivity() when the firmware
> doesn't handle adaptivity. They use igi_history[0], so as far as I can
> see they just write the same thresholds again, but since this is core
> code it would be good to mention it in the commit message.
>
> [ ... ]
>
>> diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
>> index 851d198f76f3b10d5ba77c7e07e4be9d7fd54e4b..ee72380757721dab7dc409aabc24b2b825969465 100644
>> --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
>> +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
>
> [ ... ]
>
>> +#define EDCCA_LB_START_88XXA (EDCCA_L2H_H2L_DIFF - 30)
>> +#define EDCCA_LB_RETRY_88XXA (EDCCA_LB_START_88XXA + 18)
>
> Maybe a short comment on where the 18 comes from. As far as I can see it
> is the vendor condition for searching a second time (IGI upper bound of
> 0x26 or lower), worked out for an initial L2H of -17.
>
> [ ... ]
>
>> + rtw_write32(rtwdev, REG_DBGSEL, 0);
>> + for (i = 0; i < 3 &&
>> + rtw_read32(rtwdev, REG_DBGRPT) & BIT_DBG_CCA_BUSY; i++)
>> + usleep_range(3000, 3500);
>
> The register read in the loop condition is a bit hard to follow. Maybe
> read_poll_timeout() would read easier, like efuse.c uses it:
>
> read_poll_timeout(rtw_read32, val, !(val & BIT_DBG_CCA_BUSY),
> 3000, 9000, false, rtwdev, REG_DBGRPT);
>
> [ ... ]
>
>> +void rtw88xxa_adaptivity_init(struct rtw_dev *rtwdev)
>> +{
>> + struct rtw_dm_info *dm_info = &rtwdev->dm_info;
>> + u32 dbgsel = rtw_read32(rtwdev, REG_DBGSEL);
>> + s8 l2h;
>> +
>> + rtw_write32_clr(rtwdev, REG_TX_PTCL_CTRL, BIT_DIS_EDCCA);
>
> Bitterblue reported on that "firmware failed to leave lps state" shows
> up a lot more often with this patch and stops when EDCCA is disabled,
> and you replied that it only prints a line in dmesg. On rtw-next it is
> more than a message now. Since dc16902cad9c ("wifi: rtw88: ps: Trigger
> firmware recovery when failing to leave LPS state"), rtw_fw_leave_lps_check()
> goes on to a firmware recovery after the warning:
>
> rtw_warn(rtwdev, "firmware failed to leave lps state\n");
> rtw_fw_dump_dbg_info(rtwdev);
> rtw_fw_recovery(rtwdev);
>
> So a failed leave now ends in a firmware recovery, with a "firmware
> crash, start reset and recover" WARN and ieee80211_restart_hw(). With
> power saving on, rtw_watch_dog_work() calls rtw_leave_lps() every 2
> seconds before the dynamic mechanisms, so I think this needs to be
> solved before the patch can go in.
>
> About a longer timeout, according to the comment in
> __rtw_fw_leave_lps_check_reg() the firmware restores REG_TCR once the AP
> has acked its null frame, so I think it would mostly hide the problem.
> Leaving this patch out of v3 and sending it again once the cause is
> known sounds fine to me, then the rest of the series doesn't have to
> wait.
>
> Bitterblue, did you turn EDCCA off through the edcca_enable debugfs file?
Yes, that's what I did.
> With this patch that only switches to RTW_EDCCA_NORMAL, and
> rtw88xxa_adaptivity() then keeps EDCCA on with the higher normal
> thresholds. If that is what made it stop, it would point at the
> thresholds used in adaptivity mode (ETSI and JP regions) rather than at
> EDCCA itself.
>
> Jie Feng, maybe comparing the IGI in the hardware when the leave fails
> with the IGI the thresholds were computed from would show more.
>
> [ ... ]
>
>> + /* igi_history[0] keeps the pre-scan IGI while scanning */
>> + u8 igi = rtw_read32_mask(rtwdev, REG_RXIGI_A, 0x7f);
>
> The comment sits on a line that doesn't use igi_history[0], so it reads
> a bit confusing. Maybe something like "read the IGI in use,
> igi_history[0] still holds the old value while scanning".
>
> Best regards,
> Luka Gejak
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH rtw-next v2 6/7] wifi: rtw88: 88xxa: adapt channel sensing to receiver gain
2026-11-06 19:46 ` Bitterblue Smith
@ 2026-11-06 20:27 ` Luka Gejak
0 siblings, 0 replies; 15+ messages in thread
From: Luka Gejak @ 2026-11-06 20:27 UTC (permalink / raw)
To: Bitterblue Smith, Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, linux-kernel
November 6, 2026 at 8:46 PM, "Bitterblue Smith" <rtl8821cerfe2@gmail.com> wrote:
>
> On 06/11/2026 19:34, Luka Gejak wrote:
>
>>
[ ... ]
>>
>> Bitterblue, did you turn EDCCA off through the edcca_enable debugfs file?
>>
> Yes, that's what I did.
>
Thanks for the answer. So I think EDCCA itself is fine with this patch,
and it is the lower thresholds of the adaptivity mode that keep the
firmware from leaving LPS.
To me this looks a lot like b0435910e47d ("wifi: rtw88: 8822b: Relax
ETSI EDCCA threshold on 2.4 GHz"). There an RTL8812BU running as a 2.4
GHz AP wasn't seen in scans and failed to get TX reports under the
ETSI threshold, mostly because of energy from the adapter's own USB 3
link. The fix was to use the normal threshold on 2.4 GHz under ETSI,
capped for EN 300 328. Your network is on channel 13, so that would fit.
The 8812au vendor drivers don't use the adaptivity thresholds by default
either. Both v5.6.4.2 and 8812au-20210820 build with
CONFIG_RTW_ADAPTIVITY_EN = disable
and as far as I can see phydm_adaptivity() then stays on the normal
(mode2) thresholds.
Jie Feng, maybe doing the same as 8822b would work for v3, the normal
thresholds on 2.4 GHz under ETSI and the adaptivity ones for 5 GHz and
JP. Bitterblue, is the adapter on a USB 3 port, and do you see the LPS
failures on 5 GHz as well?
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH rtw-next v2 7/7] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits
[not found] <20261031070950.425176-1-hjf3108@gmail.com>
` (5 preceding siblings ...)
2026-10-31 7:09 ` [PATCH rtw-next v2 6/7] wifi: rtw88: 88xxa: adapt channel sensing to receiver gain Ho Jie Feng
@ 2026-10-31 7:09 ` Ho Jie Feng
2026-11-06 17:35 ` Luka Gejak
6 siblings, 1 reply; 15+ messages in thread
From: Ho Jie Feng @ 2026-10-31 7:09 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
Honor the peer-advertised receive limit for transmitted A-MPDUs.
Signed-off-by: Ho Jie Feng <hjf3108@gmail.com>
---
drivers/net/wireless/realtek/rtw88/rtw8812a.c | 9 ++++++++-
drivers/net/wireless/realtek/rtw88/rtw8821a.c | 9 ++++++++-
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
index d93c4776e0303f52273d92eaa75341ebbcfcb066..a3b5fae5608e0637b1badb7aff7986160c9668a1 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
@@ -78,6 +78,13 @@ static void rtw8812a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
{
}
+static void rtw8812a_set_ampdu_factor(struct rtw_dev *rtwdev, u8 factor)
+{
+ factor = min_t(u8, factor, IEEE80211_VHT_MAX_AMPDU_128K);
+
+ rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, (8192 << factor) - 1);
+}
+
static void rtw8812a_do_lck(struct rtw_dev *rtwdev)
{
u32 cont_tx, lc_cal, i;
@@ -926,7 +933,7 @@ static const struct rtw_chip_ops rtw8812a_ops = {
.set_tx_power_index = rtw88xxa_set_tx_power_index,
.cfg_ldo25 = rtw8812a_cfg_ldo25,
.efuse_grant = rtw88xxa_efuse_grant,
- .set_ampdu_factor = NULL,
+ .set_ampdu_factor = rtw8812a_set_ampdu_factor,
.false_alarm_statistics = rtw88xxa_false_alarm_statistics,
.phy_calibration = rtw8812a_phy_calibration,
.cck_pd_set = rtw_phy_cck_pd_set,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
index f7391f6aa3039c7ba4d88249d968a5f1763ea866..f597edec290f64fda1c457812b240515360dc387 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
@@ -49,6 +49,13 @@ static void rtw8821a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
{
}
+static void rtw8821a_set_ampdu_factor(struct rtw_dev *rtwdev, u8 factor)
+{
+ factor = min_t(u8, factor, IEEE80211_HT_MAX_AMPDU_64K);
+
+ rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, (8192 << factor) - 1);
+}
+
#define CAL_NUM_8821A 3
#define MACBB_REG_NUM_8821A 8
#define AFE_REG_NUM_8821A 4
@@ -872,7 +879,7 @@ static const struct rtw_chip_ops rtw8821a_ops = {
.set_tx_power_index = rtw88xxa_set_tx_power_index,
.cfg_ldo25 = rtw8821a_cfg_ldo25,
.efuse_grant = rtw88xxa_efuse_grant,
- .set_ampdu_factor = NULL,
+ .set_ampdu_factor = rtw8821a_set_ampdu_factor,
.false_alarm_statistics = rtw88xxa_false_alarm_statistics,
.phy_calibration = rtw8821a_phy_calibration,
.cck_pd_set = rtw_phy_cck_pd_set,
--
2.55.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH rtw-next v2 7/7] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits
2026-10-31 7:09 ` [PATCH rtw-next v2 7/7] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits Ho Jie Feng
@ 2026-11-06 17:35 ` Luka Gejak
0 siblings, 0 replies; 15+ messages in thread
From: Luka Gejak @ 2026-11-06 17:35 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, Ho Jie Feng, linux-kernel
Hi Jie Feng,
Two small comments below.
October 31, 2026 at 8:09 AM, "Ho Jie Feng" <hjf3108@gmail.com> wrote:
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
> index f7391f6aa3039c7ba4d88249d968a5f1763ea866..f597edec290f64fda1c457812b240515360dc387 100644
> --- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
> @@ -49,6 +49,13 @@ static void rtw8821a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
> {
> }
>
> +static void rtw8821a_set_ampdu_factor(struct rtw_dev *rtwdev, u8 factor)
> +{
> + factor = min_t(u8, factor, IEEE80211_HT_MAX_AMPDU_64K);
For a VHT peer rtw_set_ampdu_factor() passes the VHT exponent here, so
IEEE80211_VHT_MAX_AMPDU_64K would match the 8812a version. It is the
same value, so this is only about readability.
> +
> + rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, (8192 << factor) - 1);
> +}
This is the same as rtw8812a_set_ampdu_factor() apart from the limit.
Maybe a single rtw88xxa_set_ampdu_factor() that picks the limit by chip
id, like rtw88xxa_set_crystal_cap() in patch 5 does for the mask?
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 15+ messages in thread