mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
rtw89_usb_ops_check_and_reclaim_tx_resource() returns a hardcoded
placeholder value (42) instead of actual TX resource availability.
This violates mac80211's flow control contract, preventing backpressure
and causing uncontrolled URB accumulation under sustained TX load.
Fix by adding per-channel atomic counters (tx_inflight[]) that track
in-flight URBs. Increment before usb_submit_urb() with rollback on
failure, decrement in the completion callback, and return the
remaining capacity to mac80211. The firmware command channel (CH12)
always returns 1 since it has its own flow control.
The pre-increment pattern prevents a race where USB core completes the
URB on another CPU before the submitting code increments the counter.
128 URBs per channel provides headroom for RTL8832CU at 160 MHz
bandwidth. Tested on RTL8852AU (USB3 80 MHz) where 64 and 128 showed
equivalent throughput, and on RTL8832AU where 128 sustained full
throughput under 8-stream parallel load.
Tested on D-Link DWA-X1850 (RTL8832AU), kernel 6.19.8, Fedora 43:
Unpatched -> Patched (128 URBs)
USB3 5GHz UL: 844 -> 837 Mbps (no regression)
USB3 5GHz retx: 3 -> 0
USB3 2.4GHz UL: 162 -> 164 Mbps (no regression)
4-stream UL: 858 -> 826 Mbps (within variance)
8-stream UL: 872 -> 826 Mbps (within variance)
UDP flood: 0% loss (690K datagrams)
60-second soak: 855 Mbps, 0 retransmits
Reported-by: morrownr <morrownr@gmail.com>
Signed-off-by: Lucid Duck <lucid_duck@justthetip.ca>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20260402052216.207858-1-lucid_duck@justthetip.ca
93 lines
2.1 KiB
C
93 lines
2.1 KiB
C
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
|
/* Copyright(c) 2025 Realtek Corporation
|
|
*/
|
|
|
|
#ifndef __RTW89_USB_H__
|
|
#define __RTW89_USB_H__
|
|
|
|
#include "txrx.h"
|
|
|
|
#define RTW89_USB_VENQT 0x05
|
|
#define RTW89_USB_VENQT_READ 0xc0
|
|
#define RTW89_USB_VENQT_WRITE 0x40
|
|
|
|
#define RTW89_USB_RECVBUF_SZ 20480
|
|
#define RTW89_USB_RXCB_NUM 8
|
|
#define RTW89_USB_RX_SKB_NUM 16
|
|
#define RTW89_USB_MAX_RXQ_LEN 512
|
|
#define RTW89_USB_MOD512_PADDING 4
|
|
|
|
#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_1K 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)
|
|
|
|
#define RTW89_USB_MAX_TX_URBS_PER_CH 128
|
|
|
|
struct rtw89_usb_info {
|
|
u32 usb_host_request_2;
|
|
u32 usb_wlan0_1;
|
|
u32 hci_func_en;
|
|
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];
|
|
};
|
|
|
|
struct rtw89_usb_rx_ctrl_block {
|
|
struct rtw89_dev *rtwdev;
|
|
struct urb *rx_urb;
|
|
struct sk_buff *rx_skb;
|
|
};
|
|
|
|
struct rtw89_usb_tx_ctrl_block {
|
|
struct rtw89_dev *rtwdev;
|
|
u8 txch;
|
|
struct sk_buff_head tx_ack_queue;
|
|
};
|
|
|
|
struct rtw89_usb {
|
|
struct rtw89_dev *rtwdev;
|
|
struct usb_device *udev;
|
|
const struct rtw89_usb_info *info;
|
|
|
|
__le32 *vendor_req_buf;
|
|
|
|
atomic_t continual_io_error;
|
|
|
|
u8 in_pipe;
|
|
u8 out_pipe[RTW89_MAX_BULKOUT_NUM];
|
|
|
|
struct workqueue_struct *rxwq;
|
|
struct rtw89_usb_rx_ctrl_block rx_cb[RTW89_USB_RXCB_NUM];
|
|
struct sk_buff_head rx_queue;
|
|
struct sk_buff_head rx_free_queue;
|
|
struct work_struct rx_work;
|
|
struct work_struct rx_urb_work;
|
|
struct usb_anchor tx_submitted;
|
|
|
|
struct sk_buff_head tx_queue[RTW89_TXCH_NUM];
|
|
atomic_t tx_inflight[RTW89_TXCH_NUM];
|
|
};
|
|
|
|
static inline struct rtw89_usb *rtw89_usb_priv(struct rtw89_dev *rtwdev)
|
|
{
|
|
return (struct rtw89_usb *)rtwdev->priv;
|
|
}
|
|
|
|
int rtw89_usb_probe(struct usb_interface *intf,
|
|
const struct usb_device_id *id);
|
|
void rtw89_usb_disconnect(struct usb_interface *intf);
|
|
|
|
#endif
|