]> git.ipfire.org Git - thirdparty/openwrt.git/blob
30f13f9d385c3f0dfc97abf41d492f2aff82738c
[thirdparty/openwrt.git] /
1 From e9048e2935f7d797c2ba047c15b705b57c2fa99a Mon Sep 17 00:00:00 2001
2 From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
3 Date: Thu, 19 Dec 2024 00:33:20 +0200
4 Subject: [PATCH] wifi: rtw88: usb: Copy instead of cloning the RX skb
5
6 "iperf3 -c 192.168.0.1 -R --udp -b 0" shows about 40% of datagrams
7 are lost. Many torrents don't download faster than 3 MiB/s, probably
8 because the Bittorrent protocol uses UDP. This is somehow related to
9 the use of skb_clone() in the RX path.
10
11 Don't use skb_clone(). Instead allocate a new skb for each 802.11 frame
12 received and copy the data from the big (32768 byte) skb.
13
14 With this patch, "iperf3 -c 192.168.0.1 -R --udp -b 0" shows only 1-2%
15 of datagrams are lost, and torrents can reach download speeds of 36
16 MiB/s.
17
18 Tested with RTL8812AU and RTL8822CU.
19
20 Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
21 Acked-by: Ping-Ke Shih <pkshih@realtek.com>
22 Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
23 Link: https://patch.msgid.link/8c9d4f9d-ebd8-4dc0-a0c4-9ebe430521dd@gmail.com
24 ---
25 drivers/net/wireless/realtek/rtw88/usb.c | 52 ++++++++++++++----------
26 1 file changed, 31 insertions(+), 21 deletions(-)
27
28 --- a/drivers/net/wireless/realtek/rtw88/usb.c
29 +++ b/drivers/net/wireless/realtek/rtw88/usb.c
30 @@ -7,6 +7,7 @@
31 #include <linux/mutex.h>
32 #include "main.h"
33 #include "debug.h"
34 +#include "mac.h"
35 #include "reg.h"
36 #include "tx.h"
37 #include "rx.h"
38 @@ -547,49 +548,58 @@ static void rtw_usb_rx_handler(struct wo
39 {
40 struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work);
41 struct rtw_dev *rtwdev = rtwusb->rtwdev;
42 - const struct rtw_chip_info *chip = rtwdev->chip;
43 - u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
44 struct ieee80211_rx_status rx_status;
45 - u32 pkt_offset, next_pkt, urb_len;
46 struct rtw_rx_pkt_stat pkt_stat;
47 - struct sk_buff *next_skb;
48 + struct sk_buff *rx_skb;
49 struct sk_buff *skb;
50 + u32 pkt_desc_sz = rtwdev->chip->rx_pkt_desc_sz;
51 + u32 max_skb_len = pkt_desc_sz + PHY_STATUS_SIZE * 8 +
52 + IEEE80211_MAX_MPDU_LEN_VHT_11454;
53 + u32 pkt_offset, next_pkt, skb_len;
54 u8 *rx_desc;
55 int limit;
56
57 for (limit = 0; limit < 200; limit++) {
58 - skb = skb_dequeue(&rtwusb->rx_queue);
59 - if (!skb)
60 + rx_skb = skb_dequeue(&rtwusb->rx_queue);
61 + if (!rx_skb)
62 break;
63
64 if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) {
65 dev_dbg_ratelimited(rtwdev->dev, "failed to get rx_queue, overflow\n");
66 - dev_kfree_skb_any(skb);
67 + dev_kfree_skb_any(rx_skb);
68 continue;
69 }
70
71 - urb_len = skb->len;
72 + rx_desc = rx_skb->data;
73
74 do {
75 - rx_desc = skb->data;
76 rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat,
77 &rx_status);
78 pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
79 pkt_stat.shift;
80
81 - next_pkt = round_up(pkt_stat.pkt_len + pkt_offset, 8);
82 + skb_len = pkt_stat.pkt_len + pkt_offset;
83 + if (skb_len > max_skb_len) {
84 + rtw_dbg(rtwdev, RTW_DBG_USB,
85 + "skipping too big packet: %u\n",
86 + skb_len);
87 + goto skip_packet;
88 + }
89 +
90 + skb = alloc_skb(skb_len, GFP_KERNEL);
91 + if (!skb) {
92 + rtw_dbg(rtwdev, RTW_DBG_USB,
93 + "failed to allocate RX skb of size %u\n",
94 + skb_len);
95 + goto skip_packet;
96 + }
97
98 - if (urb_len >= next_pkt + pkt_desc_sz)
99 - next_skb = skb_clone(skb, GFP_KERNEL);
100 - else
101 - next_skb = NULL;
102 + skb_put_data(skb, rx_desc, skb_len);
103
104 if (pkt_stat.is_c2h) {
105 - skb_trim(skb, pkt_stat.pkt_len + pkt_offset);
106 rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb);
107 } else {
108 skb_pull(skb, pkt_offset);
109 - skb_trim(skb, pkt_stat.pkt_len);
110 rtw_update_rx_freq_for_invalid(rtwdev, skb,
111 &rx_status,
112 &pkt_stat);
113 @@ -598,12 +608,12 @@ static void rtw_usb_rx_handler(struct wo
114 ieee80211_rx_irqsafe(rtwdev->hw, skb);
115 }
116
117 - skb = next_skb;
118 - if (skb)
119 - skb_pull(skb, next_pkt);
120 +skip_packet:
121 + next_pkt = round_up(skb_len, 8);
122 + rx_desc += next_pkt;
123 + } while (rx_desc + pkt_desc_sz < rx_skb->data + rx_skb->len);
124
125 - urb_len -= next_pkt;
126 - } while (skb);
127 + dev_kfree_skb_any(rx_skb);
128 }
129 }
130