public inbox for linux-wireless@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH rtw-next] wifi: rtw89: usb: Rx aggregation for RTL8832CU/RTL8851BU
@ 2026-03-09  8:58 Ping-Ke Shih
  2026-03-10 22:16 ` Bitterblue Smith
  0 siblings, 1 reply; 3+ messages in thread
From: Ping-Ke Shih @ 2026-03-09  8:58 UTC (permalink / raw)
  To: linux-wireless; +Cc: rtl8821cerfe2, mh_chen, isaiah

From: Shin-Yi Lin <isaiah@realtek.com>

USB RX Aggregation is a performance optimization technique used
in USB network devices to increase throughput.

Instead of sending every received network packet to the host computer
individually, the device hardware groups multiple smaller packets
into a single, large USB Bulk Transfer.

 * toAP/toNB use iperf3 respectively.

With BE6000 - iperf3 tcp 10 pair (to another NB)

RTL8832CU-USB3.0
      before   after
TX    941      941
RX    847      919

RTL8832CU-USB2.0
      before   after
TX    864      877
RX    864      902

RTL8851BU
      before   after
TX    115      114
RX    295      306

Signed-off-by: Shin-Yi Lin <isaiah@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
This one is to add USB RX aggregation to improve performance. The other
one is TX aggregation, which we are working on.
---
 .../net/wireless/realtek/rtw89/rtw8851bu.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852au.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852bu.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852cu.c    |  1 +
 drivers/net/wireless/realtek/rtw89/usb.c      | 84 ++++++++++++++++---
 drivers/net/wireless/realtek/rtw89/usb.h      | 12 +++
 6 files changed, 87 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
index 959d62aefdd8..6a8d31544314 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
@@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8851b_usb_info = {
 	.usb3_mac_npi_config_intf_0	= R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
 	.usb_endpoint_0			= R_AX_USB_ENDPOINT_0,
 	.usb_endpoint_2			= R_AX_USB_ENDPOINT_2,
+	.rx_agg_alignment		= 8,
 	.bulkout_id = {
 		[RTW89_DMA_ACH0] = 3,
 		[RTW89_DMA_ACH1] = 4,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
index ccdbcc178c2a..4cced4619b7d 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
@@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852a_usb_info = {
 	.usb3_mac_npi_config_intf_0	= R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
 	.usb_endpoint_0			= R_AX_USB_ENDPOINT_0,
 	.usb_endpoint_2			= R_AX_USB_ENDPOINT_2,
+	.rx_agg_alignment		= 8,
 	.bulkout_id = {
 		[RTW89_DMA_ACH0] = 3,
 		[RTW89_DMA_ACH2] = 5,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
index 84cd3ec971f9..37111fed276f 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
@@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852b_usb_info = {
 	.usb3_mac_npi_config_intf_0	= R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
 	.usb_endpoint_0			= R_AX_USB_ENDPOINT_0,
 	.usb_endpoint_2			= R_AX_USB_ENDPOINT_2,
+	.rx_agg_alignment		= 8,
 	.bulkout_id = {
 		[RTW89_DMA_ACH0] = 3,
 		[RTW89_DMA_ACH1] = 4,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
index 3b9825c92a0d..0c5aebaed873 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
@@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852c_usb_info = {
 	.usb3_mac_npi_config_intf_0	= R_AX_USB3_MAC_NPI_CONFIG_INTF_0_V1,
 	.usb_endpoint_0			= R_AX_USB_ENDPOINT_0_V1,
 	.usb_endpoint_2			= R_AX_USB_ENDPOINT_2_V1,
+	.rx_agg_alignment		= 8,
 	.bulkout_id = {
 		[RTW89_DMA_ACH0] = 3,
 		[RTW89_DMA_ACH2] = 5,
diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
index da1b7ce8089e..4482ce61592b 100644
--- a/drivers/net/wireless/realtek/rtw89/usb.c
+++ b/drivers/net/wireless/realtek/rtw89/usb.c
@@ -408,11 +408,14 @@ static int rtw89_usb_ops_tx_write(struct rtw89_dev *rtwdev,
 static void rtw89_usb_rx_handler(struct work_struct *work)
 {
 	struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_work);
+	const struct rtw89_usb_info *info = rtwusb->info;
 	struct rtw89_dev *rtwdev = rtwusb->rtwdev;
 	struct rtw89_rx_desc_info desc_info;
+	s32 aligned_offset, remaining;
 	struct sk_buff *rx_skb;
 	struct sk_buff *skb;
 	u32 pkt_offset;
+	u8 *pkt_ptr;
 	int limit;
 
 	for (limit = 0; limit < 200; limit++) {
@@ -425,23 +428,38 @@ static void rtw89_usb_rx_handler(struct work_struct *work)
 			goto free_or_reuse;
 		}
 
-		memset(&desc_info, 0, sizeof(desc_info));
-		rtw89_chip_query_rxdesc(rtwdev, &desc_info, rx_skb->data, 0);
+		pkt_ptr = rx_skb->data;
+		remaining = rx_skb->len;
 
-		skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
-		if (!skb) {
-			rtw89_debug(rtwdev, RTW89_DBG_HCI,
-				    "failed to allocate RX skb of size %u\n",
-				    desc_info.pkt_size);
-			goto free_or_reuse;
-		}
+		do {
+			memset(&desc_info, 0, sizeof(desc_info));
+			rtw89_chip_query_rxdesc(rtwdev, &desc_info, pkt_ptr, 0);
 
-		pkt_offset = desc_info.offset + desc_info.rxd_len;
+			pkt_offset = desc_info.offset + desc_info.rxd_len;
+			if (remaining < (pkt_offset + desc_info.pkt_size)) {
+				rtw89_debug(rtwdev, RTW89_DBG_HCI,
+					    "Failed to get remaining RX pkt %u > %u\n",
+					    pkt_offset + desc_info.pkt_size, remaining);
+				goto free_or_reuse;
+			}
 
-		skb_put_data(skb, rx_skb->data + pkt_offset,
-			     desc_info.pkt_size);
+			skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
+			if (!skb) {
+				rtw89_debug(rtwdev, RTW89_DBG_HCI,
+					    "failed to allocate RX skb of size %u\n",
+					    desc_info.pkt_size);
+				goto free_or_reuse;
+			}
+
+			skb_put_data(skb, pkt_ptr + pkt_offset, desc_info.pkt_size);
+			rtw89_core_rx(rtwdev, &desc_info, skb);
 
-		rtw89_core_rx(rtwdev, &desc_info, skb);
+			/* next frame */
+			pkt_offset += desc_info.pkt_size;
+			aligned_offset = ALIGN(pkt_offset, info->rx_agg_alignment);
+			pkt_ptr += aligned_offset;
+			remaining -= aligned_offset;
+		} while (remaining > 0);
 
 free_or_reuse:
 		if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW89_USB_RX_SKB_NUM)
@@ -745,6 +763,44 @@ static int rtw89_usb_ops_mac_pre_deinit(struct rtw89_dev *rtwdev)
 	return 0; /* Nothing to do. */
 }
 
+static void usb_rx_agg_cfg_v1(struct rtw89_dev *rtwdev)
+{
+	const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
+			    FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 0) |
+			    FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
+			    FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_4K, 5);
+
+	rtw89_write32(rtwdev, R_AX_RXAGG_0, rxagg_0);
+}
+
+static void usb_rx_agg_cfg_v2(struct rtw89_dev *rtwdev)
+{
+	const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
+			    FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 255) |
+			    FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
+			    FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_K, 20);
+
+	rtw89_write32(rtwdev, R_AX_RXAGG_0_V1, rxagg_0);
+	rtw89_write32(rtwdev, R_AX_RXAGG_1_V1, 0x1F);
+}
+
+static void usb_rx_agg_cfg(struct rtw89_dev *rtwdev)
+{
+	switch (rtwdev->chip->chip_id) {
+	case RTL8851B:
+	case RTL8852A:
+	case RTL8852B:
+		usb_rx_agg_cfg_v1(rtwdev);
+		break;
+	case RTL8852C:
+		usb_rx_agg_cfg_v2(rtwdev);
+		break;
+	default:
+		rtw89_warn(rtwdev, "%s: USB RX agg not support\n", __func__);
+		return;
+	}
+}
+
 static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
@@ -773,6 +829,8 @@ static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
 		rtw89_write8(rtwdev, info->usb_endpoint_2 + 1, NUMP);
 	}
 
+	usb_rx_agg_cfg(rtwdev);
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/realtek/rtw89/usb.h b/drivers/net/wireless/realtek/rtw89/usb.h
index 203ec8e993e9..afc62c1f687f 100644
--- a/drivers/net/wireless/realtek/rtw89/usb.h
+++ b/drivers/net/wireless/realtek/rtw89/usb.h
@@ -20,6 +20,17 @@
 #define RTW89_MAX_ENDPOINT_NUM		9
 #define RTW89_MAX_BULKOUT_NUM		7
 
+#define R_AX_RXAGG_0_V1			0x6000
+#define B_AX_RXAGG_0_EN			BIT(31)
+#define B_AX_RXAGG_0_NUM_TH		GENMASK(23, 16)
+#define B_AX_RXAGG_0_TIME_32US_TH	GENMASK(15, 8)
+#define B_AX_RXAGG_0_BUF_SZ_K		GENMASK(7, 0)
+
+#define R_AX_RXAGG_1_V1			0x6004
+
+#define R_AX_RXAGG_0			0x8900
+#define B_AX_RXAGG_0_BUF_SZ_4K		GENMASK(7, 0)
+
 struct rtw89_usb_info {
 	u32 usb_host_request_2;
 	u32 usb_wlan0_1;
@@ -27,6 +38,7 @@ struct rtw89_usb_info {
 	u32 usb3_mac_npi_config_intf_0;
 	u32 usb_endpoint_0;
 	u32 usb_endpoint_2;
+	u8 rx_agg_alignment;
 	u8 bulkout_id[RTW89_DMA_CH_NUM];
 };
 

base-commit: 039cd522dc70151da13329a5e3ae19b1736f468a
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH rtw-next] wifi: rtw89: usb: Rx aggregation for RTL8832CU/RTL8851BU
  2026-03-09  8:58 [PATCH rtw-next] wifi: rtw89: usb: Rx aggregation for RTL8832CU/RTL8851BU Ping-Ke Shih
@ 2026-03-10 22:16 ` Bitterblue Smith
       [not found]   ` <197660d0061246518129933398072dd5@realtek.com>
  0 siblings, 1 reply; 3+ messages in thread
From: Bitterblue Smith @ 2026-03-10 22:16 UTC (permalink / raw)
  To: Ping-Ke Shih, linux-wireless; +Cc: mh_chen, isaiah

On 09/03/2026 10:58, Ping-Ke Shih wrote:
> From: Shin-Yi Lin <isaiah@realtek.com>
> 
> USB RX Aggregation is a performance optimization technique used
> in USB network devices to increase throughput.
> 
> Instead of sending every received network packet to the host computer
> individually, the device hardware groups multiple smaller packets
> into a single, large USB Bulk Transfer.
> 
>  * toAP/toNB use iperf3 respectively.
> 
> With BE6000 - iperf3 tcp 10 pair (to another NB)
> 
> RTL8832CU-USB3.0
>       before   after
> TX    941      941
> RX    847      919
> 
> RTL8832CU-USB2.0
>       before   after
> TX    864      877
> RX    864      902

I wonder if these numbers are actually from a different scenario?
USB 2.0 can't go that fast.

> 
> RTL8851BU
>       before   after
> TX    115      114
> RX    295      306
> 
> Signed-off-by: Shin-Yi Lin <isaiah@realtek.com>
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
> ---
> This one is to add USB RX aggregation to improve performance. The other
> one is TX aggregation, which we are working on.

That is wonderful news.

> ---
>  .../net/wireless/realtek/rtw89/rtw8851bu.c    |  1 +
>  .../net/wireless/realtek/rtw89/rtw8852au.c    |  1 +
>  .../net/wireless/realtek/rtw89/rtw8852bu.c    |  1 +
>  .../net/wireless/realtek/rtw89/rtw8852cu.c    |  1 +
>  drivers/net/wireless/realtek/rtw89/usb.c      | 84 ++++++++++++++++---
>  drivers/net/wireless/realtek/rtw89/usb.h      | 12 +++
>  6 files changed, 87 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
> index 959d62aefdd8..6a8d31544314 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8851b_usb_info = {
>  	.usb3_mac_npi_config_intf_0	= R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
>  	.usb_endpoint_0			= R_AX_USB_ENDPOINT_0,
>  	.usb_endpoint_2			= R_AX_USB_ENDPOINT_2,
> +	.rx_agg_alignment		= 8,
>  	.bulkout_id = {
>  		[RTW89_DMA_ACH0] = 3,
>  		[RTW89_DMA_ACH1] = 4,
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
> index ccdbcc178c2a..4cced4619b7d 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852a_usb_info = {
>  	.usb3_mac_npi_config_intf_0	= R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
>  	.usb_endpoint_0			= R_AX_USB_ENDPOINT_0,
>  	.usb_endpoint_2			= R_AX_USB_ENDPOINT_2,
> +	.rx_agg_alignment		= 8,
>  	.bulkout_id = {
>  		[RTW89_DMA_ACH0] = 3,
>  		[RTW89_DMA_ACH2] = 5,
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
> index 84cd3ec971f9..37111fed276f 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852b_usb_info = {
>  	.usb3_mac_npi_config_intf_0	= R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
>  	.usb_endpoint_0			= R_AX_USB_ENDPOINT_0,
>  	.usb_endpoint_2			= R_AX_USB_ENDPOINT_2,
> +	.rx_agg_alignment		= 8,
>  	.bulkout_id = {
>  		[RTW89_DMA_ACH0] = 3,
>  		[RTW89_DMA_ACH1] = 4,
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
> index 3b9825c92a0d..0c5aebaed873 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852c_usb_info = {
>  	.usb3_mac_npi_config_intf_0	= R_AX_USB3_MAC_NPI_CONFIG_INTF_0_V1,
>  	.usb_endpoint_0			= R_AX_USB_ENDPOINT_0_V1,
>  	.usb_endpoint_2			= R_AX_USB_ENDPOINT_2_V1,
> +	.rx_agg_alignment		= 8,
>  	.bulkout_id = {
>  		[RTW89_DMA_ACH0] = 3,
>  		[RTW89_DMA_ACH2] = 5,
> diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
> index da1b7ce8089e..4482ce61592b 100644
> --- a/drivers/net/wireless/realtek/rtw89/usb.c
> +++ b/drivers/net/wireless/realtek/rtw89/usb.c
> @@ -408,11 +408,14 @@ static int rtw89_usb_ops_tx_write(struct rtw89_dev *rtwdev,
>  static void rtw89_usb_rx_handler(struct work_struct *work)
>  {
>  	struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_work);
> +	const struct rtw89_usb_info *info = rtwusb->info;
>  	struct rtw89_dev *rtwdev = rtwusb->rtwdev;
>  	struct rtw89_rx_desc_info desc_info;
> +	s32 aligned_offset, remaining;
>  	struct sk_buff *rx_skb;
>  	struct sk_buff *skb;
>  	u32 pkt_offset;
> +	u8 *pkt_ptr;
>  	int limit;
>  
>  	for (limit = 0; limit < 200; limit++) {
> @@ -425,23 +428,38 @@ static void rtw89_usb_rx_handler(struct work_struct *work)
>  			goto free_or_reuse;
>  		}
>  
> -		memset(&desc_info, 0, sizeof(desc_info));
> -		rtw89_chip_query_rxdesc(rtwdev, &desc_info, rx_skb->data, 0);
> +		pkt_ptr = rx_skb->data;
> +		remaining = rx_skb->len;
>  
> -		skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
> -		if (!skb) {
> -			rtw89_debug(rtwdev, RTW89_DBG_HCI,
> -				    "failed to allocate RX skb of size %u\n",
> -				    desc_info.pkt_size);
> -			goto free_or_reuse;
> -		}
> +		do {
> +			memset(&desc_info, 0, sizeof(desc_info));
> +			rtw89_chip_query_rxdesc(rtwdev, &desc_info, pkt_ptr, 0);
>  
> -		pkt_offset = desc_info.offset + desc_info.rxd_len;
> +			pkt_offset = desc_info.offset + desc_info.rxd_len;
> +			if (remaining < (pkt_offset + desc_info.pkt_size)) {
> +				rtw89_debug(rtwdev, RTW89_DBG_HCI,
> +					    "Failed to get remaining RX pkt %u > %u\n",
> +					    pkt_offset + desc_info.pkt_size, remaining);
> +				goto free_or_reuse;
> +			}
>  
> -		skb_put_data(skb, rx_skb->data + pkt_offset,
> -			     desc_info.pkt_size);
> +			skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
> +			if (!skb) {
> +				rtw89_debug(rtwdev, RTW89_DBG_HCI,
> +					    "failed to allocate RX skb of size %u\n",
> +					    desc_info.pkt_size);
> +				goto free_or_reuse;
> +			}
> +
> +			skb_put_data(skb, pkt_ptr + pkt_offset, desc_info.pkt_size);
> +			rtw89_core_rx(rtwdev, &desc_info, skb);
>  
> -		rtw89_core_rx(rtwdev, &desc_info, skb);
> +			/* next frame */
> +			pkt_offset += desc_info.pkt_size;
> +			aligned_offset = ALIGN(pkt_offset, info->rx_agg_alignment);
> +			pkt_ptr += aligned_offset;
> +			remaining -= aligned_offset;
> +		} while (remaining > 0);
>  
>  free_or_reuse:
>  		if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW89_USB_RX_SKB_NUM)
> @@ -745,6 +763,44 @@ static int rtw89_usb_ops_mac_pre_deinit(struct rtw89_dev *rtwdev)
>  	return 0; /* Nothing to do. */
>  }
>  
> +static void usb_rx_agg_cfg_v1(struct rtw89_dev *rtwdev)

Maybe give the new functions the usual "rtw89_" prefix?

> +{
> +	const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
> +			    FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 0) |
> +			    FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
> +			    FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_4K, 5);
> +
> +	rtw89_write32(rtwdev, R_AX_RXAGG_0, rxagg_0);
> +}
> +
> +static void usb_rx_agg_cfg_v2(struct rtw89_dev *rtwdev)
> +{
> +	const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
> +			    FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 255) |
> +			    FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
> +			    FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_K, 20);
> +
> +	rtw89_write32(rtwdev, R_AX_RXAGG_0_V1, rxagg_0);
> +	rtw89_write32(rtwdev, R_AX_RXAGG_1_V1, 0x1F);
> +}
> +
> +static void usb_rx_agg_cfg(struct rtw89_dev *rtwdev)
> +{
> +	switch (rtwdev->chip->chip_id) {
> +	case RTL8851B:
> +	case RTL8852A:
> +	case RTL8852B:
> +		usb_rx_agg_cfg_v1(rtwdev);
> +		break;
> +	case RTL8852C:
> +		usb_rx_agg_cfg_v2(rtwdev);
> +		break;
> +	default:
> +		rtw89_warn(rtwdev, "%s: USB RX agg not support\n", __func__);
> +		return;
> +	}

The subject only mentions RTL8832CU and RTL8851BU, but looks like you
implemented it for every chip currently supported.

> +}
> +
>  static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
>  {
>  	struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
> @@ -773,6 +829,8 @@ static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
>  		rtw89_write8(rtwdev, info->usb_endpoint_2 + 1, NUMP);
>  	}
>  
> +	usb_rx_agg_cfg(rtwdev);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/net/wireless/realtek/rtw89/usb.h b/drivers/net/wireless/realtek/rtw89/usb.h
> index 203ec8e993e9..afc62c1f687f 100644
> --- a/drivers/net/wireless/realtek/rtw89/usb.h
> +++ b/drivers/net/wireless/realtek/rtw89/usb.h
> @@ -20,6 +20,17 @@
>  #define RTW89_MAX_ENDPOINT_NUM		9
>  #define RTW89_MAX_BULKOUT_NUM		7
>  
> +#define R_AX_RXAGG_0_V1			0x6000
> +#define B_AX_RXAGG_0_EN			BIT(31)
> +#define B_AX_RXAGG_0_NUM_TH		GENMASK(23, 16)
> +#define B_AX_RXAGG_0_TIME_32US_TH	GENMASK(15, 8)
> +#define B_AX_RXAGG_0_BUF_SZ_K		GENMASK(7, 0)

Is it missing a number before the letter K ?

> +
> +#define R_AX_RXAGG_1_V1			0x6004
> +
> +#define R_AX_RXAGG_0			0x8900
> +#define B_AX_RXAGG_0_BUF_SZ_4K		GENMASK(7, 0)
> +
>  struct rtw89_usb_info {
>  	u32 usb_host_request_2;
>  	u32 usb_wlan0_1;
> @@ -27,6 +38,7 @@ struct rtw89_usb_info {
>  	u32 usb3_mac_npi_config_intf_0;
>  	u32 usb_endpoint_0;
>  	u32 usb_endpoint_2;
> +	u8 rx_agg_alignment;
>  	u8 bulkout_id[RTW89_DMA_CH_NUM];
>  };
>  
> 
> base-commit: 039cd522dc70151da13329a5e3ae19b1736f468a


^ permalink raw reply	[flat|nested] 3+ messages in thread

* RE: [PATCH rtw-next] wifi: rtw89: usb: Rx aggregation for RTL8832CU/RTL8851BU
       [not found]   ` <197660d0061246518129933398072dd5@realtek.com>
@ 2026-03-12  2:30     ` Isaiah
  0 siblings, 0 replies; 3+ messages in thread
From: Isaiah @ 2026-03-12  2:30 UTC (permalink / raw)
  To: Bitterblue Smith, Ping-Ke Shih, linux-wireless@vger.kernel.org; +Cc: Mh_chen

________________________________________
寄件者: Bitterblue Smith <mailto:rtl8821cerfe2@gmail.com>
寄件日期: 2026年3月11日 上午 06:16
收件者: Ping-Ke Shih; mailto:linux-wireless@vger.kernel.org
副本: Mh_chen; Isaiah
主旨: Re: [PATCH rtw-next] wifi: rtw89: usb: Rx aggregation for RTL8832CU/RTL8851BU 
 

External mail : This email originated from outside the organization. Do not reply, click links, or open attachments unless you recognize the sender and know the content is safe.



On 09/03/2026 10:58, Ping-Ke Shih wrote:
> From: Shin-Yi Lin <mailto:isaiah@realtek.com>
>
> USB RX Aggregation is a performance optimization technique used
> in USB network devices to increase throughput.
>
> Instead of sending every received network packet to the host computer
> individually, the device hardware groups multiple smaller packets
> into a single, large USB Bulk Transfer.
>
>  * toAP/toNB use iperf3 respectively.
>
> With BE6000 - iperf3 tcp 10 pair (to another NB)
>
> RTL8832CU-USB3.0
>       before   after
> TX    941      941
> RX    847      919
>
> RTL8832CU-USB2.0
>       before   after
> TX    864      877
> RX    864      902

> I wonder if these numbers are actually from a different scenario?
> USB 2.0 can't go that fast.

Sorry, I made a mistake in the data.
Details as below. The corrected data will be included in next patch.
[6G 160Mhz]:

 RTL8832CU-USB3.0
       before   after
 TX    941      941
 RX    847      919

 RTL8832CU-USB2.0
       before   after
 TX    293      286
 RX    342      356

-------------------------------
[5G 80Mhz]:

 RTL8832CU-USB3.0
       before   after
 TX    864      877
 RX    864      902

 RTL8832CU-USB2.0
       before   after
 TX    279      271
 RX    327      349

 RTL8851BU
       before   after
 TX    115      114
 RX    295      306


>
> RTL8851BU
>       before   after
> TX    115      114
> RX    295      306
>
> Signed-off-by: Shin-Yi Lin <mailto:isaiah@realtek.com>
> Signed-off-by: Ping-Ke Shih <mailto:pkshih@realtek.com>
> ---
> This one is to add USB RX aggregation to improve performance. The other
> one is TX aggregation, which we are working on.

> That is wonderful news.

> ---
>  .../net/wireless/realtek/rtw89/rtw8851bu.c    |  1 +
>  .../net/wireless/realtek/rtw89/rtw8852au.c    |  1 +
>  .../net/wireless/realtek/rtw89/rtw8852bu.c    |  1 +
>  .../net/wireless/realtek/rtw89/rtw8852cu.c    |  1 +
>  drivers/net/wireless/realtek/rtw89/usb.c      | 84 ++++++++++++++++---
>  drivers/net/wireless/realtek/rtw89/usb.h      | 12 +++
>  6 files changed, 87 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
> index 959d62aefdd8..6a8d31544314 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8851b_usb_info = {
>       .usb3_mac_npi_config_intf_0     = R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
>       .usb_endpoint_0                 = R_AX_USB_ENDPOINT_0,
>       .usb_endpoint_2                 = R_AX_USB_ENDPOINT_2,
> +     .rx_agg_alignment               = 8,
>       .bulkout_id = {
>               [RTW89_DMA_ACH0] = 3,
>               [RTW89_DMA_ACH1] = 4,
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
> index ccdbcc178c2a..4cced4619b7d 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852a_usb_info = {
>       .usb3_mac_npi_config_intf_0     = R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
>       .usb_endpoint_0                 = R_AX_USB_ENDPOINT_0,
>       .usb_endpoint_2                 = R_AX_USB_ENDPOINT_2,
> +     .rx_agg_alignment               = 8,
>       .bulkout_id = {
>               [RTW89_DMA_ACH0] = 3,
>               [RTW89_DMA_ACH2] = 5,
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
> index 84cd3ec971f9..37111fed276f 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852b_usb_info = {
>       .usb3_mac_npi_config_intf_0     = R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
>       .usb_endpoint_0                 = R_AX_USB_ENDPOINT_0,
>       .usb_endpoint_2                 = R_AX_USB_ENDPOINT_2,
> +     .rx_agg_alignment               = 8,
>       .bulkout_id = {
>               [RTW89_DMA_ACH0] = 3,
>               [RTW89_DMA_ACH1] = 4,
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
> index 3b9825c92a0d..0c5aebaed873 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852c_usb_info = {
>       .usb3_mac_npi_config_intf_0     = R_AX_USB3_MAC_NPI_CONFIG_INTF_0_V1,
>       .usb_endpoint_0                 = R_AX_USB_ENDPOINT_0_V1,
>       .usb_endpoint_2                 = R_AX_USB_ENDPOINT_2_V1,
> +     .rx_agg_alignment               = 8,
>       .bulkout_id = {
>               [RTW89_DMA_ACH0] = 3,
>               [RTW89_DMA_ACH2] = 5,
> diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
> index da1b7ce8089e..4482ce61592b 100644
> --- a/drivers/net/wireless/realtek/rtw89/usb.c
> +++ b/drivers/net/wireless/realtek/rtw89/usb.c
> @@ -408,11 +408,14 @@ static int rtw89_usb_ops_tx_write(struct rtw89_dev *rtwdev,
>  static void rtw89_usb_rx_handler(struct work_struct *work)
>  {
>       struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_work);
> +     const struct rtw89_usb_info *info = rtwusb->info;
>       struct rtw89_dev *rtwdev = rtwusb->rtwdev;
>       struct rtw89_rx_desc_info desc_info;
> +     s32 aligned_offset, remaining;
>       struct sk_buff *rx_skb;
>       struct sk_buff *skb;
>       u32 pkt_offset;
> +     u8 *pkt_ptr;
>       int limit;
>
>       for (limit = 0; limit < 200; limit++) {
> @@ -425,23 +428,38 @@ static void rtw89_usb_rx_handler(struct work_struct *work)
>                       goto free_or_reuse;
>               }
>
> -             memset(&desc_info, 0, sizeof(desc_info));
> -             rtw89_chip_query_rxdesc(rtwdev, &desc_info, rx_skb->data, 0);
> +             pkt_ptr = rx_skb->data;
> +             remaining = rx_skb->len;
>
> -             skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
> -             if (!skb) {
> -                     rtw89_debug(rtwdev, RTW89_DBG_HCI,
> -                                 "failed to allocate RX skb of size %u\n",
> -                                 desc_info.pkt_size);
> -                     goto free_or_reuse;
> -             }
> +             do {
> +                     memset(&desc_info, 0, sizeof(desc_info));
> +                     rtw89_chip_query_rxdesc(rtwdev, &desc_info, pkt_ptr, 0);
>
> -             pkt_offset = desc_info.offset + desc_info.rxd_len;
> +                     pkt_offset = desc_info.offset + desc_info.rxd_len;
> +                     if (remaining < (pkt_offset + desc_info.pkt_size)) {
> +                             rtw89_debug(rtwdev, RTW89_DBG_HCI,
> +                                         "Failed to get remaining RX pkt %u > %u\n",
> +                                         pkt_offset + desc_info.pkt_size, remaining);
> +                             goto free_or_reuse;
> +                     }
>
> -             skb_put_data(skb, rx_skb->data + pkt_offset,
> -                          desc_info.pkt_size);
> +                     skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
> +                     if (!skb) {
> +                             rtw89_debug(rtwdev, RTW89_DBG_HCI,
> +                                         "failed to allocate RX skb of size %u\n",
> +                                         desc_info.pkt_size);
> +                             goto free_or_reuse;
> +                     }
> +
> +                     skb_put_data(skb, pkt_ptr + pkt_offset, desc_info.pkt_size);
> +                     rtw89_core_rx(rtwdev, &desc_info, skb);
>
> -             rtw89_core_rx(rtwdev, &desc_info, skb);
> +                     /* next frame */
> +                     pkt_offset += desc_info.pkt_size;
> +                     aligned_offset = ALIGN(pkt_offset, info->rx_agg_alignment);
> +                     pkt_ptr += aligned_offset;
> +                     remaining -= aligned_offset;
> +             } while (remaining > 0);
>
>  free_or_reuse:
>               if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW89_USB_RX_SKB_NUM)
> @@ -745,6 +763,44 @@ static int rtw89_usb_ops_mac_pre_deinit(struct rtw89_dev *rtwdev)
>       return 0; /* Nothing to do. */
>  }
>
> +static void usb_rx_agg_cfg_v1(struct rtw89_dev *rtwdev)

> Maybe give the new functions the usual "rtw89_" prefix?

OK, I will refine in next patch

> +{
> +     const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
> +                         FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 0) |
> +                         FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
> +                         FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_4K, 5);
> +
> +     rtw89_write32(rtwdev, R_AX_RXAGG_0, rxagg_0);
> +}
> +
> +static void usb_rx_agg_cfg_v2(struct rtw89_dev *rtwdev)
> +{
> +     const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
> +                         FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 255) |
> +                         FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
> +                         FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_K, 20);
> +
> +     rtw89_write32(rtwdev, R_AX_RXAGG_0_V1, rxagg_0);
> +     rtw89_write32(rtwdev, R_AX_RXAGG_1_V1, 0x1F);
> +}
> +
> +static void usb_rx_agg_cfg(struct rtw89_dev *rtwdev)
> +{
> +     switch (rtwdev->chip->chip_id) {
> +     case RTL8851B:
> +     case RTL8852A:
> +     case RTL8852B:
> +             usb_rx_agg_cfg_v1(rtwdev);
> +             break;
> +     case RTL8852C:
> +             usb_rx_agg_cfg_v2(rtwdev);
> +             break;
> +     default:
> +             rtw89_warn(rtwdev, "%s: USB RX agg not support\n", __func__);
> +             return;
> +     }

> The subject only mentions RTL8832CU and RTL8851BU, but looks like you
> implemented it for every chip currently supported.

Basically all are supported, but I have only verified RTL8832CU and RTL8851BU.

> +}
> +
>  static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
>  {
>       struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
> @@ -773,6 +829,8 @@ static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
>               rtw89_write8(rtwdev, info->usb_endpoint_2 + 1, NUMP);
>       }
>
> +     usb_rx_agg_cfg(rtwdev);
> +
>       return 0;
>  }
>
> diff --git a/drivers/net/wireless/realtek/rtw89/usb.h b/drivers/net/wireless/realtek/rtw89/usb.h
> index 203ec8e993e9..afc62c1f687f 100644
> --- a/drivers/net/wireless/realtek/rtw89/usb.h
> +++ b/drivers/net/wireless/realtek/rtw89/usb.h
> @@ -20,6 +20,17 @@
>  #define RTW89_MAX_ENDPOINT_NUM               9
>  #define RTW89_MAX_BULKOUT_NUM                7
>
> +#define R_AX_RXAGG_0_V1                      0x6000
> +#define B_AX_RXAGG_0_EN                      BIT(31)
> +#define B_AX_RXAGG_0_NUM_TH          GENMASK(23, 16)
> +#define B_AX_RXAGG_0_TIME_32US_TH    GENMASK(15, 8)
> +#define B_AX_RXAGG_0_BUF_SZ_K                GENMASK(7, 0)

> Is it missing a number before the letter K ?

OK, I will refine in next patch

> +
> +#define R_AX_RXAGG_1_V1                      0x6004
> +
> +#define R_AX_RXAGG_0                 0x8900
> +#define B_AX_RXAGG_0_BUF_SZ_4K               GENMASK(7, 0)
> +
>  struct rtw89_usb_info {
>       u32 usb_host_request_2;
>       u32 usb_wlan0_1;
> @@ -27,6 +38,7 @@ struct rtw89_usb_info {
>       u32 usb3_mac_npi_config_intf_0;
>       u32 usb_endpoint_0;
>       u32 usb_endpoint_2;
> +     u8 rx_agg_alignment;
>       u8 bulkout_id[RTW89_DMA_CH_NUM];
>  };
>
>
> base-commit: 039cd522dc70151da13329a5e3ae19b1736f468a

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-03-12  2:30 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-09  8:58 [PATCH rtw-next] wifi: rtw89: usb: Rx aggregation for RTL8832CU/RTL8851BU Ping-Ke Shih
2026-03-10 22:16 ` Bitterblue Smith
     [not found]   ` <197660d0061246518129933398072dd5@realtek.com>
2026-03-12  2:30     ` Isaiah

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox