* [PATCH rtw-next v3 0/5] wifi: rtw88: extend 88xxA support
@ 2026-11-12 17:32 Ho Jie Feng
2026-11-12 17:32 ` [PATCH rtw-next v3 1/5] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions Ho Jie Feng
` (4 more replies)
0 siblings, 5 replies; 17+ messages in thread
From: Ho Jie Feng @ 2026-11-12 17:32 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: linux-wireless, linux-kernel, Bitterblue Smith, Luka Gejak, Ho Jie Feng
This series enables HT STBC transmission, VHT SU beamformed reception
and carrier-frequency-offset correction on supported 88xxA devices.
Tested on RTL8812AU:
TX went from 136.0 to 144.2.
RX went from 215.5 to 249.2.
Changelog v3:
- Remove EDCCA commits since it causes problems in some situations
- Beamformee: gate on spatial streams instead of the RX antennas,
in case an antenna is disabled
- Beamformee: writes RTL8814A use rtw_write32_mask() instead of
an unaligned 16-bit write
- Beamformee: drop the chip ID from the debug message, style fixes
- CFO: add RTW_XCAP_MASK to phy.h
- CFO: use 0x20 as the RTL8814A crystal cap when the efuse is empty,
following the vendor driver
- CFO: add comment on why min(...,2) is needed for rtl8814
- A-MPDU: set BIT(31) of REG_AMPDU_MAX_LENGTH, like the vendor driver
- A-MPDU: limit RTL8821A with IEEE80211_VHT_MAX_AMPDU_64K
Changelog v2:
- Split correcting beamform caps into its own commit
- Adjust EDCCA threshold on scan to avoid high latency
Ho Jie Feng (5):
wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions
wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
wifi: rtw88: prepare frequency-offset correction for more chips
wifi: rtw88: 88xxa: correct carrier-frequency offset
wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits
drivers/net/wireless/realtek/rtw88/bf.h | 2 +
drivers/net/wireless/realtek/rtw88/main.c | 14 ++-
drivers/net/wireless/realtek/rtw88/phy.c | 110 +++++++++++++++++-
drivers/net/wireless/realtek/rtw88/phy.h | 5 +
drivers/net/wireless/realtek/rtw88/reg.h | 1 +
drivers/net/wireless/realtek/rtw88/rtw8812a.c | 16 ++-
drivers/net/wireless/realtek/rtw88/rtw8814a.c | 70 +++++++++--
drivers/net/wireless/realtek/rtw88/rtw8821a.c | 15 ++-
drivers/net/wireless/realtek/rtw88/rtw8822c.c | 100 +---------------
drivers/net/wireless/realtek/rtw88/rtw8822c.h | 3 -
drivers/net/wireless/realtek/rtw88/rtw88xxa.c | 108 +++++++++++++++--
drivers/net/wireless/realtek/rtw88/rtw88xxa.h | 3 +
12 files changed, 324 insertions(+), 123 deletions(-)
base-commit: 61a5eb87b2d9b4d5e353780b781cf691f39ba9e1
--
2.53.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH rtw-next v3 1/5] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions
2026-11-12 17:32 [PATCH rtw-next v3 0/5] wifi: rtw88: extend 88xxA support Ho Jie Feng
@ 2026-11-12 17:32 ` Ho Jie Feng
2026-11-13 8:08 ` Luka Gejak
2026-11-12 17:32 ` [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions Ho Jie Feng
` (3 subsequent siblings)
4 siblings, 1 reply; 17+ messages in thread
From: Ho Jie Feng @ 2026-11-12 17:32 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: linux-wireless, linux-kernel, Bitterblue Smith, Luka Gejak, Ho Jie Feng
8812a and 8814a support STBC, enable it.
8822c will lose reporting TX STBC capability if efuse reports
only 1 path, but this is correct, since it in that case it doesn't
actually support STBC.
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 f7708ad17b..e243738809 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1583,7 +1583,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 781b66ccde..55f1d3d324 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 b6916d3dc6..e35c57c9d1 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.53.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
2026-11-12 17:32 [PATCH rtw-next v3 0/5] wifi: rtw88: extend 88xxA support Ho Jie Feng
2026-11-12 17:32 ` [PATCH rtw-next v3 1/5] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions Ho Jie Feng
@ 2026-11-12 17:32 ` Ho Jie Feng
2026-11-13 7:46 ` Luka Gejak
2026-11-13 8:09 ` Luka Gejak
2026-11-12 17:32 ` [PATCH rtw-next v3 3/5] wifi: rtw88: prepare frequency-offset correction for more chips Ho Jie Feng
` (2 subsequent siblings)
4 siblings, 2 replies; 17+ messages in thread
From: Ho Jie Feng @ 2026-11-12 17:32 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: linux-wireless, linux-kernel, Bitterblue Smith, Luka Gejak, Ho Jie Feng
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/main.c | 12 ++--
drivers/net/wireless/realtek/rtw88/reg.h | 1 +
drivers/net/wireless/realtek/rtw88/rtw8812a.c | 3 +-
drivers/net/wireless/realtek/rtw88/rtw8814a.c | 37 ++++++++++-
drivers/net/wireless/realtek/rtw88/rtw8821a.c | 3 +-
drivers/net/wireless/realtek/rtw88/rtw88xxa.c | 61 +++++++++++++++++++
drivers/net/wireless/realtek/rtw88/rtw88xxa.h | 2 +
8 files changed, 112 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/bf.h b/drivers/net/wireless/realtek/rtw88/bf.h
index a5d3010e6b..0aa78fb6a7 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/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index e243738809..fe93c93b1a 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1603,6 +1603,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;
@@ -1621,10 +1622,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;
diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
index afcdb66fdb..f8ec1e2931 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 55f1d3d324..5d58dff4fc 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 e35c57c9d1..c2a18f6be8 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,32 @@ 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_write32_mask(rtwdev, REG_SND_PTCL_CTRL, MASKBYTE1 | MASKBYTE2,
+ 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 +2098,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 +2261,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 6096d3b8e4..6d106ae70d 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 5ffa29d181..128a18ee33 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;
+ hal->bfee_sts_cap = 1;
if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A)
goto print_hw_cap;
@@ -197,6 +198,66 @@ 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, "SU beamformee %s slot %u\n",
+ 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 (rtwdev->efuse.hw_cap.nss == 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, u8 *phy_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 6597ca0dfc..150e86ea74 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.53.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH rtw-next v3 3/5] wifi: rtw88: prepare frequency-offset correction for more chips
2026-11-12 17:32 [PATCH rtw-next v3 0/5] wifi: rtw88: extend 88xxA support Ho Jie Feng
2026-11-12 17:32 ` [PATCH rtw-next v3 1/5] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions Ho Jie Feng
2026-11-12 17:32 ` [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions Ho Jie Feng
@ 2026-11-12 17:32 ` Ho Jie Feng
2026-11-12 17:32 ` [PATCH rtw-next v3 4/5] wifi: rtw88: 88xxa: correct carrier-frequency offset Ho Jie Feng
2026-11-12 17:32 ` [PATCH rtw-next v3 5/5] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits Ho Jie Feng
4 siblings, 0 replies; 17+ messages in thread
From: Ho Jie Feng @ 2026-11-12 17:32 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: linux-wireless, linux-kernel, Bitterblue Smith, Luka Gejak, Ho Jie Feng
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 e2515a662b..d0c1fb65be 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 8a843aac73..b551cb860d 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 09315d23e2..d7b0204e6d 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 fc62b67a15..c27e4c394a 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.53.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH rtw-next v3 4/5] wifi: rtw88: 88xxa: correct carrier-frequency offset
2026-11-12 17:32 [PATCH rtw-next v3 0/5] wifi: rtw88: extend 88xxA support Ho Jie Feng
` (2 preceding siblings ...)
2026-11-12 17:32 ` [PATCH rtw-next v3 3/5] wifi: rtw88: prepare frequency-offset correction for more chips Ho Jie Feng
@ 2026-11-12 17:32 ` Ho Jie Feng
2026-11-13 7:52 ` Luka Gejak
2026-11-12 17:32 ` [PATCH rtw-next v3 5/5] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits Ho Jie Feng
4 siblings, 1 reply; 17+ messages in thread
From: Ho Jie Feng @ 2026-11-12 17:32 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: linux-wireless, linux-kernel, Bitterblue Smith, Luka Gejak, Ho Jie Feng
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 | 6 ++-
drivers/net/wireless/realtek/rtw88/phy.h | 3 ++
drivers/net/wireless/realtek/rtw88/rtw8812a.c | 2 +
drivers/net/wireless/realtek/rtw88/rtw8814a.c | 32 +++++++++++--
drivers/net/wireless/realtek/rtw88/rtw8821a.c | 2 +
drivers/net/wireless/realtek/rtw88/rtw88xxa.c | 47 +++++++++++++++----
drivers/net/wireless/realtek/rtw88/rtw88xxa.h | 1 +
7 files changed, 79 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index d0c1fb65be..eed3e2cb60 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -687,13 +687,15 @@ 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;
+ /* rtl8814a has 4 paths, but only 2 of them report cfo */
+ 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 +796,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/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h
index b551cb860d..3a74035219 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.h
+++ b/drivers/net/wireless/realtek/rtw88/phy.h
@@ -204,4 +204,7 @@ enum rtw_phy_cck_pd_lv {
#define RRSR_RATE_ORDER_MAX 0xfffff
#define RRSR_RATE_ORDER_CCK_LEN 4
+/* crystal cap width of all chips except RTL8822C */
+#define RTW_XCAP_MASK GENMASK(5, 0)
+
#endif
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
index 5d58dff4fc..c8008cf43d 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 c2a18f6be8..a66bd7c7e0 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
@@ -146,6 +146,9 @@ static int rtw8814a_read_efuse(struct rtw_dev *rtwdev, u8 *log_map, u8 *phy_map)
efuse->rfe_option = map->rfe_option;
efuse->rf_board_option = map->rf_board_option;
efuse->crystal_cap = map->xtal_k;
+ if (efuse->crystal_cap == 0xff)
+ efuse->crystal_cap = 0x20;
+ efuse->crystal_cap &= RTW_XCAP_MASK;
efuse->channel_plan = map->channel_plan;
efuse->country_code[0] = map->country_code[0];
efuse->country_code[1] = map->country_code[1];
@@ -284,9 +287,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 +317,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 +1276,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);
}
}
@@ -2069,6 +2078,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, RTW_XCAP_MASK, 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)
@@ -2103,6 +2125,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 6d106ae70d..17d3677ca4 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 128a18ee33..a6c964e6c3 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
@@ -278,6 +278,7 @@ int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map, u8 *phy_map)
efuse->crystal_cap = map->xtal_k;
if (efuse->crystal_cap == 0xff)
efuse->crystal_cap = 0x20;
+ efuse->crystal_cap &= RTW_XCAP_MASK;
efuse->pa_type_2g = map->pa_type;
efuse->pa_type_5g = map->pa_type;
efuse->lna_type_2g = map->lna_type_2g;
@@ -631,9 +632,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);
@@ -652,13 +663,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);
}
static void rtw88xxa_phy_rf_config(struct rtw_dev *rtwdev)
@@ -1620,6 +1625,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);
@@ -2008,6 +2024,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, RTW_XCAP_MASK, 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 150e86ea74..188b8f3a4b 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.53.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH rtw-next v3 5/5] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits
2026-11-12 17:32 [PATCH rtw-next v3 0/5] wifi: rtw88: extend 88xxA support Ho Jie Feng
` (3 preceding siblings ...)
2026-11-12 17:32 ` [PATCH rtw-next v3 4/5] wifi: rtw88: 88xxa: correct carrier-frequency offset Ho Jie Feng
@ 2026-11-12 17:32 ` Ho Jie Feng
2026-11-13 8:10 ` Luka Gejak
4 siblings, 1 reply; 17+ messages in thread
From: Ho Jie Feng @ 2026-11-12 17:32 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: linux-wireless, linux-kernel, Bitterblue Smith, Luka Gejak, Ho Jie Feng
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 | 10 +++++++++-
drivers/net/wireless/realtek/rtw88/rtw8821a.c | 10 +++++++++-
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
index c8008cf43d..c8f5cdf31c 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
@@ -78,6 +78,14 @@ 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) | BIT(31));
+}
+
static void rtw8812a_do_lck(struct rtw_dev *rtwdev)
{
u32 cont_tx, lc_cal, i;
@@ -926,7 +934,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 17d3677ca4..796c100165 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
@@ -49,6 +49,14 @@ 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_VHT_MAX_AMPDU_64K);
+
+ rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH,
+ ((8192 << factor) - 1) | BIT(31));
+}
+
#define CAL_NUM_8821A 3
#define MACBB_REG_NUM_8821A 8
#define AFE_REG_NUM_8821A 4
@@ -872,7 +880,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.53.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
2026-11-12 17:32 ` [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions Ho Jie Feng
@ 2026-11-13 7:46 ` Luka Gejak
2026-11-13 8:01 ` Jie Feng
2026-11-13 8:09 ` Luka Gejak
1 sibling, 1 reply; 17+ messages in thread
From: Luka Gejak @ 2026-11-13 7:46 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, linux-kernel, Bitterblue Smith
Hi Jie Feng,
Thanks for the new version. A question and a comment below.
On November 12, 2026 6:32:41 PM GMT+01:00, 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 e243738809..fe93c93b1a 100644
> --- a/drivers/net/wireless/realtek/rtw88/main.c
> +++ b/drivers/net/wireless/realtek/rtw88/main.c
[ ... ]
> @@ -1621,10 +1622,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;
In v2 this was its own patch, 3/7 "correctly expose beamformee
capabilities", after Bitterblue asked on v1 for it to be split out. Was
folding it back in here intended? I couldn't find it in the v3 changelog.
I can see a reason for it. Without this part, an AP that is also a MU
beamformer makes rtw_bf_assoc() take the MU branch and return at
bfer_mu_max_num, so the new config_bfee code would never run for it. If
that is why, maybe mention it in the changelog, and in the commit message
too, since this is core code and the support_bf check now hides the
beamformee caps on every chip when beamforming is turned off.
[ ... ]
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
> index 55f1d3d324..5d58dff4fc 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,
As far as I can see, 8812a, 8821a and 8814a are now the first chips that
can become a SU beamformee without a cfg_csi_rate op. Once rtw_bf_assoc()
has set bfee.role, the watchdog goes through
rtw_vif_watch_dog_iter()
rtw_dynamic_csi_rate()
and there new_csi_rate_idx is only written by that op:
u8 new_csi_rate_idx;
...
rtw_chip_cfg_csi_rate(rtwdev, rtwdev->dm_info.min_rssi,
bf_info->cur_csi_rpt_rate,
fix_rate_enable, &new_csi_rate_idx);
if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate)
bf_info->cur_csi_rpt_rate = new_csi_rate_idx;
So if I read it right, it compares and stores an uninitialized value
there. cur_csi_rpt_rate has no other user on these chips, so it seems
harmless for now, but I think KMSAN would report it. Maybe
rtw_dynamic_csi_rate() could return early when the chip has no
cfg_csi_rate op?
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 4/5] wifi: rtw88: 88xxa: correct carrier-frequency offset
2026-11-12 17:32 ` [PATCH rtw-next v3 4/5] wifi: rtw88: 88xxa: correct carrier-frequency offset Ho Jie Feng
@ 2026-11-13 7:52 ` Luka Gejak
0 siblings, 0 replies; 17+ messages in thread
From: Luka Gejak @ 2026-11-13 7:52 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, linux-kernel, Bitterblue Smith
Hi Jie Feng,
Thanks for adding the comment. One small comment below.
On November 12, 2026 6:32:43 PM GMT+01:00, 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 d0c1fb65be..eed3e2cb60 100644
> --- a/drivers/net/wireless/realtek/rtw88/phy.c
> +++ b/drivers/net/wireless/realtek/rtw88/phy.c
> @@ -687,13 +687,15 @@ 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;
> + /* rtl8814a has 4 paths, but only 2 of them report cfo */
> + u8 path_num = min_t(u8, rtwdev->hal.rf_path_num, 2);
[ ... ]
> @@ -794,7 +796,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);
The new comment explains the 2 in rtw_phy_parsing_cfo_iter(), but
rtw_phy_cfo_xcap_track() has the same min_t() without it, so someone
reading that function still sees an unexplained 2.
Maybe add a define in phy.h and use it in both places, something like:
/* RTL8814A has 4 paths, but only paths A and B report CFO */
#define RTW_CFO_PATH_NUM_MAX 2
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
2026-11-13 7:46 ` Luka Gejak
@ 2026-11-13 8:01 ` Jie Feng
2026-11-13 8:07 ` Luka Gejak
0 siblings, 1 reply; 17+ messages in thread
From: Jie Feng @ 2026-11-13 8:01 UTC (permalink / raw)
To: Luka Gejak; +Cc: Ping-Ke Shih, linux-wireless, linux-kernel, Bitterblue Smith
On Fri, 13 Nov 2026 at 15:46, Luka Gejak <luka.gejak@linux.dev> wrote:
>
> Hi Jie Feng,
>
> Thanks for the new version. A question and a comment below.
>
> On November 12, 2026 6:32:41 PM GMT+01:00, 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 e243738809..fe93c93b1a 100644
> > --- a/drivers/net/wireless/realtek/rtw88/main.c
> > +++ b/drivers/net/wireless/realtek/rtw88/main.c
>
> [ ... ]
>
> > @@ -1621,10 +1622,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;
>
> In v2 this was its own patch, 3/7 "correctly expose beamformee
> capabilities", after Bitterblue asked on v1 for it to be split out. Was
> folding it back in here intended? I couldn't find it in the v3 changelog.
Sorry, looks like I used the wrong commit on my local tree, will resend as a v4.
Please ignore this v3.
> I can see a reason for it. Without this part, an AP that is also a MU
> beamformer makes rtw_bf_assoc() take the MU branch and return at
> bfer_mu_max_num, so the new config_bfee code would never run for it. If
> that is why, maybe mention it in the changelog, and in the commit message
> too, since this is core code and the support_bf check now hides the
> beamformee caps on every chip when beamforming is turned off.
>
> [ ... ]
>
> > diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
> > index 55f1d3d324..5d58dff4fc 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,
>
> As far as I can see, 8812a, 8821a and 8814a are now the first chips that
> can become a SU beamformee without a cfg_csi_rate op. Once rtw_bf_assoc()
> has set bfee.role, the watchdog goes through
>
> rtw_vif_watch_dog_iter()
> rtw_dynamic_csi_rate()
>
> and there new_csi_rate_idx is only written by that op:
>
> u8 new_csi_rate_idx;
> ...
> rtw_chip_cfg_csi_rate(rtwdev, rtwdev->dm_info.min_rssi,
> bf_info->cur_csi_rpt_rate,
> fix_rate_enable, &new_csi_rate_idx);
>
> if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate)
> bf_info->cur_csi_rpt_rate = new_csi_rate_idx;
>
> So if I read it right, it compares and stores an uninitialized value
> there. cur_csi_rpt_rate has no other user on these chips, so it seems
> harmless for now, but I think KMSAN would report it. Maybe
> rtw_dynamic_csi_rate() could return early when the chip has no
> cfg_csi_rate op?
>
> Best regards,
> Luka Gejak
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
2026-11-13 8:01 ` Jie Feng
@ 2026-11-13 8:07 ` Luka Gejak
2026-11-13 8:12 ` Jie Feng
0 siblings, 1 reply; 17+ messages in thread
From: Luka Gejak @ 2026-11-13 8:07 UTC (permalink / raw)
To: Jie Feng; +Cc: Ping-Ke Shih, linux-wireless, linux-kernel, Bitterblue Smith
On November 13, 2026 9:01:47 AM GMT+01:00, Jie Feng <hjf3108@gmail.com>
wrote:
>On Fri, 13 Nov 2026 at 15:46, Luka Gejak <luka.gejak@linux.dev> wrote:
>>
>> Hi Jie Feng,
>>
>> Thanks for the new version. A question and a comment below.
>>
>> On November 12, 2026 6:32:41 PM GMT+01:00, 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 e243738809..fe93c93b1a 100644
>> > --- a/drivers/net/wireless/realtek/rtw88/main.c
>> > +++ b/drivers/net/wireless/realtek/rtw88/main.c
>>
>> [ ... ]
>>
>> > @@ -1621,10 +1622,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;
>>
>> In v2 this was its own patch, 3/7 "correctly expose beamformee
>> capabilities", after Bitterblue asked on v1 for it to be split out. Was
>> folding it back in here intended? I couldn't find it in the v3
>changelog.
>Sorry, looks like I used the wrong commit on my local tree, will resend as
>a v4.
>Please ignore this v3.
>
Can you address all comments I have send, as they will most likely apply
to v4 as well?
>> I can see a reason for it. Without this part, an AP that is also a MU
>> beamformer makes rtw_bf_assoc() take the MU branch and return at
>> bfer_mu_max_num, so the new config_bfee code would never run for it. If
>> that is why, maybe mention it in the changelog, and in the commit
>message
>> too, since this is core code and the support_bf check now hides the
>> beamformee caps on every chip when beamforming is turned off.
>>
>> [ ... ]
>>
>> > diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
>b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
>> > index 55f1d3d324..5d58dff4fc 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,
>>
>> As far as I can see, 8812a, 8821a and 8814a are now the first chips that
>> can become a SU beamformee without a cfg_csi_rate op. Once
>rtw_bf_assoc()
>> has set bfee.role, the watchdog goes through
>>
>> rtw_vif_watch_dog_iter()
>> rtw_dynamic_csi_rate()
>>
>> and there new_csi_rate_idx is only written by that op:
>>
>> u8 new_csi_rate_idx;
>> ...
>> rtw_chip_cfg_csi_rate(rtwdev, rtwdev->dm_info.min_rssi,
>> bf_info->cur_csi_rpt_rate,
>> fix_rate_enable, &new_csi_rate_idx);
>>
>> if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate)
>> bf_info->cur_csi_rpt_rate = new_csi_rate_idx;
>>
>> So if I read it right, it compares and stores an uninitialized value
>> there. cur_csi_rpt_rate has no other user on these chips, so it seems
>> harmless for now, but I think KMSAN would report it. Maybe
>> rtw_dynamic_csi_rate() could return early when the chip has no
>> cfg_csi_rate op?
>>
>> Best regards,
>> Luka Gejak
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 1/5] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions
2026-11-12 17:32 ` [PATCH rtw-next v3 1/5] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions Ho Jie Feng
@ 2026-11-13 8:08 ` Luka Gejak
0 siblings, 0 replies; 17+ messages in thread
From: Luka Gejak @ 2026-11-13 8:08 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, linux-kernel, Bitterblue Smith
Hi Jie Feng,
Thanks for adding the 8822c note. One question below.
On November 12, 2026 6:32:40 PM GMT+01:00, Ho Jie Feng <hjf3108@gmail.com>
wrote:
> 8812a and 8814a support STBC, enable it.
The hardware seems to support it. The vendor driver reports TX STBC for
both chips unless they are 1T1R or 1T2R. But it keeps HT STBC TX off by
default, os_dep/linux/os_intfs.c in the 8812au driver has
int rtw_stbc_cap = 0x13;
and rtw_ht_use_default_setting() only enables HT STBC TX for BIT5, which
is not set there. VHT STBC TX (BIT1) is on. In rtw88 only 8822c has it,
from 81a68a1424ba ("rtw88: 8822c: add tx stbc support under HT mode"),
while 8822b stays off although it is 2T2R as well.
As far as I can see, a VHT peer already gets STBC through the VHT TX
STBC capability we advertise for rf_path_num > 1, so this patch only
changes HT peers, for example any AP on 2.4 GHz, where we don't
advertise VHT. Did you test it there or with an HT only AP? The numbers
in the cover letter would only show this patch if the test was done
that way.
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
2026-11-12 17:32 ` [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions Ho Jie Feng
2026-11-13 7:46 ` Luka Gejak
@ 2026-11-13 8:09 ` Luka Gejak
2026-11-13 8:20 ` Jie Feng
1 sibling, 1 reply; 17+ messages in thread
From: Luka Gejak @ 2026-11-13 8:09 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, linux-kernel, Bitterblue Smith
Hi Jie Feng,
Two more small comments that I missed in my first reply.
On November 12, 2026 6:32:41 PM GMT+01:00, 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 e35c57c9d1..c2a18f6be8 100644
> --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
[ ... ]
> + rtw_bf_enable_bfee_su(rtwdev, vif, bfee);
> +
> + rtw_write32_mask(rtwdev, REG_SND_PTCL_CTRL, MASKBYTE1 | MASKBYTE2,
> + 0x0202);
The other values in this function have defines, but 0x0202 is bare. The
vendor code doesn't name it either, so maybe just a short comment on
what these two bytes do, if you know it.
[ ... ]
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> index 5ffa29d181..128a18ee33 100644
> --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
[ ... ]
> + if (rtwdev->efuse.hw_cap.nss == 2) {
> + rtw_write32(rtwdev, REG_CSI_CONTENT_VALUE, 0);
> + csi_param = 0x01090109;
> + } else {
> + rtw_write32(rtwdev, REG_CSI_CONTENT_VALUE, 0x01081008);
> + csi_param = 0x01080108;
> + }
[ ... ]
> + for (i = 0; i < ARRAY_SIZE(csi_rpt_regs); i++)
> + rtw_write32(rtwdev, csi_rpt_regs[i], csi_param);
These numbers are hard to follow. As far as I can see csi_param is the
same 16 bit value twice, BFMER0 in the low half and BFMER1 in the high
half, with the layout rtw_bf_enable_bfee_su() builds from named fields:
csi_param = (u16)((coefficientsize << 10) |
(codebookinfo << 8) |
(grouping << 6) |
(nr_index << 3) |
nc_index);
So here codebookinfo and nr_index are 1, and nc_index is nss minus 1.
Maybe build it the same way, or add a comment. For REG_CSI_CONTENT_VALUE
the vendor code has "nc = 2" and "nc = 1" comments next to the two
values, which would already help.
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 5/5] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits
2026-11-12 17:32 ` [PATCH rtw-next v3 5/5] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits Ho Jie Feng
@ 2026-11-13 8:10 ` Luka Gejak
2026-11-13 8:16 ` Jie Feng
0 siblings, 1 reply; 17+ messages in thread
From: Luka Gejak @ 2026-11-13 8:10 UTC (permalink / raw)
To: Ho Jie Feng, Ping-Ke Shih; +Cc: linux-wireless, linux-kernel, Bitterblue Smith
Hi Jie Feng,
Thanks for the patch. One small question below.
On November 12, 2026 6:32:44 PM GMT+01:00, Ho Jie Feng <hjf3108@gmail.com>
wrote:
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
> index c8008cf43d..c8f5cdf31c 100644
> --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
[ ... ]
> +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) | BIT(31));
> +}
What does BIT(31) do here? I see the vendor driver sets it too, so I
think it is right, but a define in reg.h or a short comment would make
it easier to follow. The same goes for rtw8821a_set_ampdu_factor().
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
2026-11-13 8:07 ` Luka Gejak
@ 2026-11-13 8:12 ` Jie Feng
0 siblings, 0 replies; 17+ messages in thread
From: Jie Feng @ 2026-11-13 8:12 UTC (permalink / raw)
To: Luka Gejak; +Cc: Ping-Ke Shih, linux-wireless, linux-kernel, Bitterblue Smith
On Fri, 13 Nov 2026 at 16:07, Luka Gejak <luka.gejak@linux.dev> wrote:
>
> On November 13, 2026 9:01:47 AM GMT+01:00, Jie Feng <hjf3108@gmail.com>
> wrote:
> >On Fri, 13 Nov 2026 at 15:46, Luka Gejak <luka.gejak@linux.dev> wrote:
> >>
> >> Hi Jie Feng,
> >>
> >> Thanks for the new version. A question and a comment below.
> >>
> >> On November 12, 2026 6:32:41 PM GMT+01:00, 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 e243738809..fe93c93b1a 100644
> >> > --- a/drivers/net/wireless/realtek/rtw88/main.c
> >> > +++ b/drivers/net/wireless/realtek/rtw88/main.c
> >>
> >> [ ... ]
> >>
> >> > @@ -1621,10 +1622,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;
> >>
> >> In v2 this was its own patch, 3/7 "correctly expose beamformee
> >> capabilities", after Bitterblue asked on v1 for it to be split out. Was
> >> folding it back in here intended? I couldn't find it in the v3
> >changelog.
> >Sorry, looks like I used the wrong commit on my local tree, will resend as
> >a v4.
> >Please ignore this v3.
> >
>
> Can you address all comments I have send, as they will most likely apply
> to v4 as well?
Yes v4 will address both the csi and cfo comments. I will send it out
after figuring
out the correct fix.
> >> I can see a reason for it. Without this part, an AP that is also a MU
> >> beamformer makes rtw_bf_assoc() take the MU branch and return at
> >> bfer_mu_max_num, so the new config_bfee code would never run for it. If
> >> that is why, maybe mention it in the changelog, and in the commit
> >message
> >> too, since this is core code and the support_bf check now hides the
> >> beamformee caps on every chip when beamforming is turned off.
> >>
> >> [ ... ]
> >>
> >> > diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
> >b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
> >> > index 55f1d3d324..5d58dff4fc 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,
> >>
> >> As far as I can see, 8812a, 8821a and 8814a are now the first chips that
> >> can become a SU beamformee without a cfg_csi_rate op. Once
> >rtw_bf_assoc()
> >> has set bfee.role, the watchdog goes through
> >>
> >> rtw_vif_watch_dog_iter()
> >> rtw_dynamic_csi_rate()
> >>
> >> and there new_csi_rate_idx is only written by that op:
> >>
> >> u8 new_csi_rate_idx;
> >> ...
> >> rtw_chip_cfg_csi_rate(rtwdev, rtwdev->dm_info.min_rssi,
> >> bf_info->cur_csi_rpt_rate,
> >> fix_rate_enable, &new_csi_rate_idx);
> >>
> >> if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate)
> >> bf_info->cur_csi_rpt_rate = new_csi_rate_idx;
> >>
> >> So if I read it right, it compares and stores an uninitialized value
> >> there. cur_csi_rpt_rate has no other user on these chips, so it seems
> >> harmless for now, but I think KMSAN would report it. Maybe
> >> rtw_dynamic_csi_rate() could return early when the chip has no
> >> cfg_csi_rate op?
This looks correct, will put in v4.
Another alternative would be to do:
u8 new_csi_rate_idx = bf_info->cur_csi_rpt_rate
and the != will never pass.
> >> Best regards,
> >> Luka Gejak
> >
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 5/5] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits
2026-11-13 8:10 ` Luka Gejak
@ 2026-11-13 8:16 ` Jie Feng
2026-11-13 8:39 ` Luka Gejak
0 siblings, 1 reply; 17+ messages in thread
From: Jie Feng @ 2026-11-13 8:16 UTC (permalink / raw)
To: Luka Gejak; +Cc: Ping-Ke Shih, linux-wireless, linux-kernel, Bitterblue Smith
On Fri, 13 Nov 2026 at 16:10, Luka Gejak <luka.gejak@linux.dev> wrote:
>
> Hi Jie Feng,
>
> Thanks for the patch. One small question below.
>
> On November 12, 2026 6:32:44 PM GMT+01:00, Ho Jie Feng <hjf3108@gmail.com>
> wrote:
>
> > diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
> > index c8008cf43d..c8f5cdf31c 100644
> > --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
> > +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
>
> [ ... ]
>
> > +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) | BIT(31));
> > +}
>
> What does BIT(31) do here? I see the vendor driver sets it too, so I
> think it is right, but a define in reg.h or a short comment would make
> it easier to follow. The same goes for rtw8821a_set_ampdu_factor().
I reviewed it again and saw it, so I added it to be at parity with the
vendor code.
> Best regards,
> Luka Gejak
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions
2026-11-13 8:09 ` Luka Gejak
@ 2026-11-13 8:20 ` Jie Feng
0 siblings, 0 replies; 17+ messages in thread
From: Jie Feng @ 2026-11-13 8:20 UTC (permalink / raw)
To: Luka Gejak; +Cc: Ping-Ke Shih, linux-wireless, linux-kernel, Bitterblue Smith
On Fri, 13 Nov 2026 at 16:09, Luka Gejak <luka.gejak@linux.dev> wrote:
>
> Hi Jie Feng,
>
> Two more small comments that I missed in my first reply.
>
> On November 12, 2026 6:32:41 PM GMT+01:00, 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 e35c57c9d1..c2a18f6be8 100644
> > --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c
> > +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c
>
> [ ... ]
>
> > + rtw_bf_enable_bfee_su(rtwdev, vif, bfee);
> > +
> > + rtw_write32_mask(rtwdev, REG_SND_PTCL_CTRL, MASKBYTE1 | MASKBYTE2,
> > + 0x0202);
>
> The other values in this function have defines, but 0x0202 is bare. The
> vendor code doesn't name it either, so maybe just a short comment on
> what these two bytes do, if you know it.
Yeah, indeed the vendor code is full of magic numbers, I don't really
know what they mean beyond guessing.
> [ ... ]
>
> > diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> > index 5ffa29d181..128a18ee33 100644
> > --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
> > +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
>
> [ ... ]
>
> > + if (rtwdev->efuse.hw_cap.nss == 2) {
> > + rtw_write32(rtwdev, REG_CSI_CONTENT_VALUE, 0);
> > + csi_param = 0x01090109;
> > + } else {
> > + rtw_write32(rtwdev, REG_CSI_CONTENT_VALUE, 0x01081008);
> > + csi_param = 0x01080108;
> > + }
>
> [ ... ]
>
> > + for (i = 0; i < ARRAY_SIZE(csi_rpt_regs); i++)
> > + rtw_write32(rtwdev, csi_rpt_regs[i], csi_param);
>
> These numbers are hard to follow. As far as I can see csi_param is the
> same 16 bit value twice, BFMER0 in the low half and BFMER1 in the high
> half, with the layout rtw_bf_enable_bfee_su() builds from named fields:
>
> csi_param = (u16)((coefficientsize << 10) |
> (codebookinfo << 8) |
> (grouping << 6) |
> (nr_index << 3) |
> nc_index);
>
> So here codebookinfo and nr_index are 1, and nc_index is nss minus 1.
> Maybe build it the same way, or add a comment. For REG_CSI_CONTENT_VALUE
> the vendor code has "nc = 2" and "nc = 1" comments next to the two
> values, which would already help.
I opted to avoid trying to add more meaning to the vendor code, because
I couldn't be sure if they were correct. Rather than risk incorrect
documentation,
I just put the magic numbers in, since they are used as is without modification.
I can dig the vendor code for some confirmation that the csi param format
is the same for the later chips as 88xxa.
> Best regards,
> Luka Gejak
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH rtw-next v3 5/5] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits
2026-11-13 8:16 ` Jie Feng
@ 2026-11-13 8:39 ` Luka Gejak
0 siblings, 0 replies; 17+ messages in thread
From: Luka Gejak @ 2026-11-13 8:39 UTC (permalink / raw)
To: Jie Feng; +Cc: Ping-Ke Shih, linux-wireless, linux-kernel, Bitterblue Smith
On November 13, 2026 9:16:33 AM GMT+01:00, Jie Feng <hjf3108@gmail.com>
wrote:
>On Fri, 13 Nov 2026 at 16:10, Luka Gejak <luka.gejak@linux.dev> wrote:
>>
>> Hi Jie Feng,
>>
>> Thanks for the patch. One small question below.
>>
>> On November 12, 2026 6:32:44 PM GMT+01:00, Ho Jie Feng
><hjf3108@gmail.com>
>> wrote:
>>
>> > diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
>b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
>> > index c8008cf43d..c8f5cdf31c 100644
>> > --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
>> > +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
>>
>> [ ... ]
>>
>> > +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) | BIT(31));
>> > +}
>>
>> What does BIT(31) do here? I see the vendor driver sets it too, so I
>> think it is right, but a define in reg.h or a short comment would make
>> it easier to follow. The same goes for rtw8821a_set_ampdu_factor().
>I reviewed it again and saw it, so I added it to be at parity with the
>vendor code.
>
Can you add a define in reg.h or a short comment, as that would make it
more readable?
Best regards,
Luka Gejak
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-11-13 8:39 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-12 17:32 [PATCH rtw-next v3 0/5] wifi: rtw88: extend 88xxA support Ho Jie Feng
2026-11-12 17:32 ` [PATCH rtw-next v3 1/5] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions Ho Jie Feng
2026-11-13 8:08 ` Luka Gejak
2026-11-12 17:32 ` [PATCH rtw-next v3 2/5] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions Ho Jie Feng
2026-11-13 7:46 ` Luka Gejak
2026-11-13 8:01 ` Jie Feng
2026-11-13 8:07 ` Luka Gejak
2026-11-13 8:12 ` Jie Feng
2026-11-13 8:09 ` Luka Gejak
2026-11-13 8:20 ` Jie Feng
2026-11-12 17:32 ` [PATCH rtw-next v3 3/5] wifi: rtw88: prepare frequency-offset correction for more chips Ho Jie Feng
2026-11-12 17:32 ` [PATCH rtw-next v3 4/5] wifi: rtw88: 88xxa: correct carrier-frequency offset Ho Jie Feng
2026-11-13 7:52 ` Luka Gejak
2026-11-12 17:32 ` [PATCH rtw-next v3 5/5] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits Ho Jie Feng
2026-11-13 8:10 ` Luka Gejak
2026-11-13 8:16 ` Jie Feng
2026-11-13 8:39 ` Luka Gejak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®