diff --git a/packages/linux/patches/rtlwifi/after-6.12/0029-wifi-rtw88-add-__packed-attribute-to-efuse-layout-st.patch b/packages/linux/patches/rtlwifi/after-6.12/0029-wifi-rtw88-add-__packed-attribute-to-efuse-layout-st.patch new file mode 100644 index 0000000000..ce1c37e27d --- /dev/null +++ b/packages/linux/patches/rtlwifi/after-6.12/0029-wifi-rtw88-add-__packed-attribute-to-efuse-layout-st.patch @@ -0,0 +1,209 @@ +From 0daa521a1c8c29ffbefe6530f0d276e74e2749d0 Mon Sep 17 00:00:00 2001 +From: Ping-Ke Shih +Date: Thu, 12 Dec 2024 13:42:03 +0800 +Subject: [PATCH 29/35] wifi: rtw88: add __packed attribute to efuse layout + struct + +The layout struct of efuse should not do address alignment by compiler. +Otherwise it leads unexpected layout and size for certain arch suc as arm. +In x86-64, the results are identical before and after this patch. + +Also adjust bit-field to prevent over adjacent byte to avoid warning: + rtw88/rtw8822b.h:66:1: note: offset of packed bit-field `res2` has changed in GCC 4.4 + 66 | } __packed; + | ^ + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202412120131.qk0x6OhE-lkp@intel.com/ +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20241212054203.135046-1-pkshih@realtek.com +--- + drivers/net/wireless/realtek/rtw88/main.h | 4 ++-- + drivers/net/wireless/realtek/rtw88/rtw8723x.h | 8 ++++---- + drivers/net/wireless/realtek/rtw88/rtw8821c.h | 9 +++++---- + drivers/net/wireless/realtek/rtw88/rtw8822b.h | 9 +++++---- + drivers/net/wireless/realtek/rtw88/rtw8822c.h | 9 +++++---- + 5 files changed, 21 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h +index cd09fb6f7b8b..65c7acea41af 100644 +--- a/drivers/net/wireless/realtek/rtw88/main.h ++++ b/drivers/net/wireless/realtek/rtw88/main.h +@@ -510,12 +510,12 @@ struct rtw_5g_txpwr_idx { + struct rtw_5g_vht_ns_pwr_idx_diff vht_2s_diff; + struct rtw_5g_vht_ns_pwr_idx_diff vht_3s_diff; + struct rtw_5g_vht_ns_pwr_idx_diff vht_4s_diff; +-}; ++} __packed; + + struct rtw_txpwr_idx { + struct rtw_2g_txpwr_idx pwr_idx_2g; + struct rtw_5g_txpwr_idx pwr_idx_5g; +-}; ++} __packed; + + struct rtw_channel_params { + u8 center_chan; +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.h b/drivers/net/wireless/realtek/rtw88/rtw8723x.h +index e93bfce994bf..a99af527c92c 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8723x.h ++++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.h +@@ -47,7 +47,7 @@ struct rtw8723xe_efuse { + u8 device_id[2]; + u8 sub_vendor_id[2]; + u8 sub_device_id[2]; +-}; ++} __packed; + + struct rtw8723xu_efuse { + u8 res4[48]; /* 0xd0 */ +@@ -56,12 +56,12 @@ struct rtw8723xu_efuse { + u8 usb_option; /* 0x104 */ + u8 res5[2]; /* 0x105 */ + u8 mac_addr[ETH_ALEN]; /* 0x107 */ +-}; ++} __packed; + + struct rtw8723xs_efuse { + u8 res4[0x4a]; /* 0xd0 */ + u8 mac_addr[ETH_ALEN]; /* 0x11a */ +-}; ++} __packed; + + struct rtw8723x_efuse { + __le16 rtl_id; +@@ -96,7 +96,7 @@ struct rtw8723x_efuse { + struct rtw8723xu_efuse u; + struct rtw8723xs_efuse s; + }; +-}; ++} __packed; + + #define RTW8723X_IQK_ADDA_REG_NUM 16 + #define RTW8723X_IQK_MAC8_REG_NUM 3 +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.h b/drivers/net/wireless/realtek/rtw88/rtw8821c.h +index 7a33ebd612ed..954e93c8020d 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.h ++++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.h +@@ -27,7 +27,7 @@ struct rtw8821cu_efuse { + u8 res11[0xcf]; + u8 package_type; /* 0x1fb */ + u8 res12[0x4]; +-}; ++} __packed; + + struct rtw8821ce_efuse { + u8 mac_addr[ETH_ALEN]; /* 0xd0 */ +@@ -47,7 +47,8 @@ struct rtw8821ce_efuse { + u8 ltr_en:1; + u8 res1:2; + u8 obff:2; +- u8 res2:3; ++ u8 res2_1:1; ++ u8 res2_2:2; + u8 obff_cap:2; + u8 res3:4; + u8 res4[3]; +@@ -63,7 +64,7 @@ struct rtw8821ce_efuse { + u8 res6:1; + u8 port_t_power_on_value:5; + u8 res7; +-}; ++} __packed; + + struct rtw8821cs_efuse { + u8 res4[0x4a]; /* 0xd0 */ +@@ -101,7 +102,7 @@ struct rtw8821c_efuse { + struct rtw8821cu_efuse u; + struct rtw8821cs_efuse s; + }; +-}; ++} __packed; + + static inline void + _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.h b/drivers/net/wireless/realtek/rtw88/rtw8822b.h +index 0514958fb57c..9fca9ba67c90 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.h ++++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.h +@@ -27,7 +27,7 @@ struct rtw8822bu_efuse { + u8 res11[0xcf]; + u8 package_type; /* 0x1fb */ + u8 res12[0x4]; +-}; ++} __packed; + + struct rtw8822be_efuse { + u8 mac_addr[ETH_ALEN]; /* 0xd0 */ +@@ -47,7 +47,8 @@ struct rtw8822be_efuse { + u8 ltr_en:1; + u8 res1:2; + u8 obff:2; +- u8 res2:3; ++ u8 res2_1:1; ++ u8 res2_2:2; + u8 obff_cap:2; + u8 res3:4; + u8 res4[3]; +@@ -63,7 +64,7 @@ struct rtw8822be_efuse { + u8 res6:1; + u8 port_t_power_on_value:5; + u8 res7; +-}; ++} __packed; + + struct rtw8822bs_efuse { + u8 res4[0x4a]; /* 0xd0 */ +@@ -103,7 +104,7 @@ struct rtw8822b_efuse { + struct rtw8822bu_efuse u; + struct rtw8822bs_efuse s; + }; +-}; ++} __packed; + + static inline void + _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h +index e2b383d633cd..fc62b67a15f2 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h ++++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h +@@ -14,7 +14,7 @@ struct rtw8822cu_efuse { + u8 res1[3]; + u8 mac_addr[ETH_ALEN]; /* 0x157 */ + u8 res2[0x3d]; +-}; ++} __packed; + + struct rtw8822cs_efuse { + u8 res0[0x4a]; /* 0x120 */ +@@ -39,7 +39,8 @@ struct rtw8822ce_efuse { + u8 ltr_en:1; + u8 res1:2; + u8 obff:2; +- u8 res2:3; ++ u8 res2_1:1; ++ u8 res2_2:2; + u8 obff_cap:2; + u8 res3:4; + u8 class_code[3]; +@@ -55,7 +56,7 @@ struct rtw8822ce_efuse { + u8 res6:1; + u8 port_t_power_on_value:5; + u8 res7; +-}; ++} __packed; + + struct rtw8822c_efuse { + __le16 rtl_id; +@@ -102,7 +103,7 @@ struct rtw8822c_efuse { + struct rtw8822cu_efuse u; + struct rtw8822cs_efuse s; + }; +-}; ++} __packed; + + enum rtw8822c_dpk_agc_phase { + RTW_DPK_GAIN_CHECK, +-- +2.43.0 + diff --git a/packages/linux/patches/rtlwifi/after-6.12/0030-wifi-rtlwifi-rtl8821ae-Fix-media-status-report.patch b/packages/linux/patches/rtlwifi/after-6.12/0030-wifi-rtlwifi-rtl8821ae-Fix-media-status-report.patch new file mode 100644 index 0000000000..35ced20c49 --- /dev/null +++ b/packages/linux/patches/rtlwifi/after-6.12/0030-wifi-rtlwifi-rtl8821ae-Fix-media-status-report.patch @@ -0,0 +1,59 @@ +From 66ef0289ac99e155d206ddaa0fdfad09ae3cd007 Mon Sep 17 00:00:00 2001 +From: Bitterblue Smith +Date: Wed, 18 Dec 2024 00:53:11 +0200 +Subject: [PATCH 30/35] wifi: rtlwifi: rtl8821ae: Fix media status report + +RTL8821AE is stuck transmitting at the lowest rate allowed by the rate +mask. This is because the firmware doesn't know the device is connected +to a network. + +Fix the macros SET_H2CCMD_MSRRPT_PARM_OPMODE and +SET_H2CCMD_MSRRPT_PARM_MACID_IND to work on the first byte of __cmd, +not the second. Now the firmware is correctly notified when the device +is connected to a network and it activates the rate control. + +Before (MCS3): + +[ 5] 0.00-1.00 sec 12.5 MBytes 105 Mbits/sec 0 339 KBytes +[ 5] 1.00-2.00 sec 10.6 MBytes 89.1 Mbits/sec 0 339 KBytes +[ 5] 2.00-3.00 sec 10.6 MBytes 89.1 Mbits/sec 0 386 KBytes +[ 5] 3.00-4.00 sec 10.6 MBytes 89.1 Mbits/sec 0 386 KBytes +[ 5] 4.00-5.00 sec 10.2 MBytes 86.0 Mbits/sec 0 427 KBytes + +After (MCS9): + +[ 5] 0.00-1.00 sec 33.9 MBytes 284 Mbits/sec 0 771 KBytes +[ 5] 1.00-2.00 sec 31.6 MBytes 265 Mbits/sec 0 865 KBytes +[ 5] 2.00-3.00 sec 29.9 MBytes 251 Mbits/sec 0 963 KBytes +[ 5] 3.00-4.00 sec 28.2 MBytes 237 Mbits/sec 0 963 KBytes +[ 5] 4.00-5.00 sec 26.8 MBytes 224 Mbits/sec 0 963 KBytes + +Fixes: 39f40710d0b5 ("rtlwifi: rtl88821ae: Remove usage of private bit manipulation macros") +Cc: stable@vger.kernel.org +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/754785b3-8a78-4554-b80d-de5f603b410b@gmail.com +--- + drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h +index c269942b3f4a..af8d17b9e012 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h +@@ -197,9 +197,9 @@ enum rtl8821a_h2c_cmd { + + /* _MEDIA_STATUS_RPT_PARM_CMD1 */ + #define SET_H2CCMD_MSRRPT_PARM_OPMODE(__cmd, __value) \ +- u8p_replace_bits(__cmd + 1, __value, BIT(0)) ++ u8p_replace_bits(__cmd, __value, BIT(0)) + #define SET_H2CCMD_MSRRPT_PARM_MACID_IND(__cmd, __value) \ +- u8p_replace_bits(__cmd + 1, __value, BIT(1)) ++ u8p_replace_bits(__cmd, __value, BIT(1)) + + /* AP_OFFLOAD */ + #define SET_H2CCMD_AP_OFFLOAD_ON(__cmd, __value) \ +-- +2.43.0 + diff --git a/packages/linux/patches/rtlwifi/after-6.12/0031-wifi-rtw88-8812a-Support-RFE-type-2.patch b/packages/linux/patches/rtlwifi/after-6.12/0031-wifi-rtw88-8812a-Support-RFE-type-2.patch new file mode 100644 index 0000000000..cff4f7229a --- /dev/null +++ b/packages/linux/patches/rtlwifi/after-6.12/0031-wifi-rtw88-8812a-Support-RFE-type-2.patch @@ -0,0 +1,33 @@ +From 59ab27a9f20f8de6f7989e8a8c3d97c04ed8199c Mon Sep 17 00:00:00 2001 +From: Bitterblue Smith +Date: Wed, 18 Dec 2024 02:13:22 +0200 +Subject: [PATCH 31/35] wifi: rtw88: 8812a: Support RFE type 2 + +RF front end type 2 exists in the wild and can be treated like types +0 and 1. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/2917c7fc-6d88-4007-b6a6-9130bd1991e5@gmail.com +--- + drivers/net/wireless/realtek/rtw88/rtw8812a.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c +index 482edd31823d..d8f0ed70777f 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c +@@ -985,6 +985,9 @@ static const struct rtw_rfe_def rtw8812a_rfe_defs[] = { + [1] = { .phy_pg_tbl = &rtw8812a_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8812a_rtw_pwr_track_tbl, }, ++ [2] = { .phy_pg_tbl = &rtw8812a_bb_pg_tbl, ++ .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl, ++ .pwr_track_tbl = &rtw8812a_rtw_pwr_track_tbl, }, + [3] = { .phy_pg_tbl = &rtw8812a_bb_pg_rfe3_tbl, + .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8812a_rtw_pwr_track_rfe3_tbl, }, +-- +2.43.0 + diff --git a/packages/linux/patches/rtlwifi/after-6.12/0032-wifi-rtw88-8821a-8812a-Set-ptct_efuse_size-to-0.patch b/packages/linux/patches/rtlwifi/after-6.12/0032-wifi-rtw88-8821a-8812a-Set-ptct_efuse_size-to-0.patch new file mode 100644 index 0000000000..8d667f74e1 --- /dev/null +++ b/packages/linux/patches/rtlwifi/after-6.12/0032-wifi-rtw88-8821a-8812a-Set-ptct_efuse_size-to-0.patch @@ -0,0 +1,58 @@ +From 74a72c367573ad521becf6cc4d649e14387b3c64 Mon Sep 17 00:00:00 2001 +From: Bitterblue Smith +Date: Wed, 18 Dec 2024 02:16:11 +0200 +Subject: [PATCH 32/35] wifi: rtw88: 8821a/8812a: Set ptct_efuse_size to 0 + +Some RTL8812AU devices fail to probe: + +[ 12.478774] rtw_8812au 1-1.3:1.0: failed to dump efuse logical map +[ 12.487712] rtw_8812au 1-1.3:1.0: failed to setup chip efuse info +[ 12.487742] rtw_8812au 1-1.3:1.0: failed to setup chip information +[ 12.491077] rtw_8812au: probe of 1-1.3:1.0 failed with error -22 + +It turns out these chips don't need to "protect" any bytes at the end of +the efuse. + +The original value of 96 was copied from rtw8821c.c. + +No one reported any failures with RTL8821AU yet, but the vendor driver +uses the same efuse reading code for both chips. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/1a477adb-60c3-463c-b158-3f86c94cb821@gmail.com +--- + drivers/net/wireless/realtek/rtw88/rtw8812a.c | 2 +- + drivers/net/wireless/realtek/rtw88/rtw8821a.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c +index d8f0ed70777f..21795286a1a0 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c +@@ -1027,7 +1027,7 @@ const struct rtw_chip_info rtw8812a_hw_spec = { + .rx_buf_desc_sz = 8, + .phy_efuse_size = 512, + .log_efuse_size = 512, +- .ptct_efuse_size = 96 + 1, /* TODO or just 18? */ ++ .ptct_efuse_size = 0, + .txff_size = 131072, + .rxff_size = 16128, + .rsvd_drv_pg_num = 9, +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c +index db242c9ad68f..dafab2af33bc 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c +@@ -1118,7 +1118,7 @@ const struct rtw_chip_info rtw8821a_hw_spec = { + .rx_buf_desc_sz = 8, + .phy_efuse_size = 512, + .log_efuse_size = 512, +- .ptct_efuse_size = 96 + 1, /* TODO or just 18? */ ++ .ptct_efuse_size = 0, + .txff_size = 65536, + .rxff_size = 16128, + .rsvd_drv_pg_num = 8, +-- +2.43.0 + diff --git a/packages/linux/patches/rtlwifi/after-6.12/0033-wifi-rtw88-usb-Copy-instead-of-cloning-the-RX-skb.patch b/packages/linux/patches/rtlwifi/after-6.12/0033-wifi-rtw88-usb-Copy-instead-of-cloning-the-RX-skb.patch new file mode 100644 index 0000000000..1d1f7657d2 --- /dev/null +++ b/packages/linux/patches/rtlwifi/after-6.12/0033-wifi-rtw88-usb-Copy-instead-of-cloning-the-RX-skb.patch @@ -0,0 +1,135 @@ +From e9048e2935f7d797c2ba047c15b705b57c2fa99a Mon Sep 17 00:00:00 2001 +From: Bitterblue Smith +Date: Thu, 19 Dec 2024 00:33:20 +0200 +Subject: [PATCH 33/35] wifi: rtw88: usb: Copy instead of cloning the RX skb + +"iperf3 -c 192.168.0.1 -R --udp -b 0" shows about 40% of datagrams +are lost. Many torrents don't download faster than 3 MiB/s, probably +because the Bittorrent protocol uses UDP. This is somehow related to +the use of skb_clone() in the RX path. + +Don't use skb_clone(). Instead allocate a new skb for each 802.11 frame +received and copy the data from the big (32768 byte) skb. + +With this patch, "iperf3 -c 192.168.0.1 -R --udp -b 0" shows only 1-2% +of datagrams are lost, and torrents can reach download speeds of 36 +MiB/s. + +Tested with RTL8812AU and RTL8822CU. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/8c9d4f9d-ebd8-4dc0-a0c4-9ebe430521dd@gmail.com +--- + drivers/net/wireless/realtek/rtw88/usb.c | 52 ++++++++++++++---------- + 1 file changed, 31 insertions(+), 21 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c +index be193c7add77..28679d9cdffc 100644 +--- a/drivers/net/wireless/realtek/rtw88/usb.c ++++ b/drivers/net/wireless/realtek/rtw88/usb.c +@@ -7,6 +7,7 @@ + #include + #include "main.h" + #include "debug.h" ++#include "mac.h" + #include "reg.h" + #include "tx.h" + #include "rx.h" +@@ -547,49 +548,58 @@ static void rtw_usb_rx_handler(struct work_struct *work) + { + struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work); + struct rtw_dev *rtwdev = rtwusb->rtwdev; +- const struct rtw_chip_info *chip = rtwdev->chip; +- u32 pkt_desc_sz = chip->rx_pkt_desc_sz; + struct ieee80211_rx_status rx_status; +- u32 pkt_offset, next_pkt, urb_len; + struct rtw_rx_pkt_stat pkt_stat; +- struct sk_buff *next_skb; ++ struct sk_buff *rx_skb; + struct sk_buff *skb; ++ u32 pkt_desc_sz = rtwdev->chip->rx_pkt_desc_sz; ++ u32 max_skb_len = pkt_desc_sz + PHY_STATUS_SIZE * 8 + ++ IEEE80211_MAX_MPDU_LEN_VHT_11454; ++ u32 pkt_offset, next_pkt, skb_len; + u8 *rx_desc; + int limit; + + for (limit = 0; limit < 200; limit++) { +- skb = skb_dequeue(&rtwusb->rx_queue); +- if (!skb) ++ rx_skb = skb_dequeue(&rtwusb->rx_queue); ++ if (!rx_skb) + break; + + if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) { + dev_dbg_ratelimited(rtwdev->dev, "failed to get rx_queue, overflow\n"); +- dev_kfree_skb_any(skb); ++ dev_kfree_skb_any(rx_skb); + continue; + } + +- urb_len = skb->len; ++ rx_desc = rx_skb->data; + + do { +- rx_desc = skb->data; + rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, + &rx_status); + pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + + pkt_stat.shift; + +- next_pkt = round_up(pkt_stat.pkt_len + pkt_offset, 8); ++ skb_len = pkt_stat.pkt_len + pkt_offset; ++ if (skb_len > max_skb_len) { ++ rtw_dbg(rtwdev, RTW_DBG_USB, ++ "skipping too big packet: %u\n", ++ skb_len); ++ goto skip_packet; ++ } + +- if (urb_len >= next_pkt + pkt_desc_sz) +- next_skb = skb_clone(skb, GFP_KERNEL); +- else +- next_skb = NULL; ++ skb = alloc_skb(skb_len, GFP_KERNEL); ++ if (!skb) { ++ rtw_dbg(rtwdev, RTW_DBG_USB, ++ "failed to allocate RX skb of size %u\n", ++ skb_len); ++ goto skip_packet; ++ } ++ ++ skb_put_data(skb, rx_desc, skb_len); + + if (pkt_stat.is_c2h) { +- skb_trim(skb, pkt_stat.pkt_len + pkt_offset); + rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb); + } else { + skb_pull(skb, pkt_offset); +- skb_trim(skb, pkt_stat.pkt_len); + rtw_update_rx_freq_for_invalid(rtwdev, skb, + &rx_status, + &pkt_stat); +@@ -598,12 +608,12 @@ static void rtw_usb_rx_handler(struct work_struct *work) + ieee80211_rx_irqsafe(rtwdev->hw, skb); + } + +- skb = next_skb; +- if (skb) +- skb_pull(skb, next_pkt); ++skip_packet: ++ next_pkt = round_up(skb_len, 8); ++ rx_desc += next_pkt; ++ } while (rx_desc + pkt_desc_sz < rx_skb->data + rx_skb->len); + +- urb_len -= next_pkt; +- } while (skb); ++ dev_kfree_skb_any(rx_skb); + } + } + +-- +2.43.0 + diff --git a/packages/linux/patches/rtlwifi/after-6.12/0034-wifi-rtw88-Handle-C2H_ADAPTIVITY-in-rtw_fw_c2h_cmd_h.patch b/packages/linux/patches/rtlwifi/after-6.12/0034-wifi-rtw88-Handle-C2H_ADAPTIVITY-in-rtw_fw_c2h_cmd_h.patch new file mode 100644 index 0000000000..64a4ee82e8 --- /dev/null +++ b/packages/linux/patches/rtlwifi/after-6.12/0034-wifi-rtw88-Handle-C2H_ADAPTIVITY-in-rtw_fw_c2h_cmd_h.patch @@ -0,0 +1,51 @@ +From 13221be72034d1c34630ab124c43438aefe7e656 Mon Sep 17 00:00:00 2001 +From: Bitterblue Smith +Date: Thu, 19 Dec 2024 00:34:42 +0200 +Subject: [PATCH 34/35] wifi: rtw88: Handle C2H_ADAPTIVITY in + rtw_fw_c2h_cmd_handle() + +The firmware message C2H_ADAPTIVITY is currently handled in +rtw_fw_c2h_cmd_rx_irqsafe(), which runs in the RX workqueue, but it's +not "irqsafe" with USB because it sleeps (reads hardware registers). +This becomes a problem after the next patch, which will create the RX +workqueue with the flag WQ_BH. + +To avoid sleeping when it's not allowed, handle C2H_ADAPTIVITY in +rtw_fw_c2h_cmd_handle(), which runs in the c2h workqueue. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/96e52b03-be8d-4050-ae71-bfdb478ff42f@gmail.com +--- + drivers/net/wireless/realtek/rtw88/fw.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c +index e6e9946fbf44..02389b7c6876 100644 +--- a/drivers/net/wireless/realtek/rtw88/fw.c ++++ b/drivers/net/wireless/realtek/rtw88/fw.c +@@ -332,6 +332,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) + case C2H_RA_RPT: + rtw_fw_ra_report_handle(rtwdev, c2h->payload, len); + break; ++ case C2H_ADAPTIVITY: ++ rtw_fw_adaptivity_result(rtwdev, c2h->payload, len); ++ break; + default: + rtw_dbg(rtwdev, RTW_DBG_FW, "C2H 0x%x isn't handled\n", c2h->id); + break; +@@ -367,10 +370,6 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset, + rtw_fw_scan_result(rtwdev, c2h->payload, len); + dev_kfree_skb_any(skb); + break; +- case C2H_ADAPTIVITY: +- rtw_fw_adaptivity_result(rtwdev, c2h->payload, len); +- dev_kfree_skb_any(skb); +- break; + default: + /* pass offset for further operation */ + *((u32 *)skb->cb) = pkt_offset; +-- +2.43.0 + diff --git a/packages/linux/patches/rtlwifi/after-6.12/0035-wifi-rtw88-usb-Preallocate-and-reuse-the-RX-skbs.patch b/packages/linux/patches/rtlwifi/after-6.12/0035-wifi-rtw88-usb-Preallocate-and-reuse-the-RX-skbs.patch new file mode 100644 index 0000000000..64936d5233 --- /dev/null +++ b/packages/linux/patches/rtlwifi/after-6.12/0035-wifi-rtw88-usb-Preallocate-and-reuse-the-RX-skbs.patch @@ -0,0 +1,230 @@ +From 3e3aa566dd1803f1697530de6c8489a8350765b3 Mon Sep 17 00:00:00 2001 +From: Bitterblue Smith +Date: Thu, 19 Dec 2024 00:35:49 +0200 +Subject: [PATCH 35/35] wifi: rtw88: usb: Preallocate and reuse the RX skbs + +The USB driver uses four USB Request Blocks for RX. Before submitting +one, it allocates a 32768 byte skb for the RX data. This allocation can +fail, maybe due to temporary memory fragmentation. When the allocation +fails, the corresponding URB is never submitted again. After four such +allocation failures, all RX stops because the driver is not requesting +data from the device anymore. + +Don't allocate a 32768 byte skb when submitting a USB Request Block +(which happens very often). Instead preallocate 8 such skbs, and reuse +them over and over. If all 8 are busy, allocate a new one. This is +pretty rare. If the allocation fails, use a work to try again later. +When there are enough free skbs again, free the excess skbs. + +Also, use WQ_BH for the RX workqueue. With a normal or high priority +workqueue the skbs are processed too slowly when the system is even a +little busy, like when opening a new page in a browser, and the driver +runs out of free skbs and allocates a lot of new ones. + +This is more or less what the out-of-tree Realtek drivers do, except +they use a tasklet instead of a BH workqueue. + +Tested with RTL8723DU, RTL8821AU, RTL8812AU, RTL8812BU, RTL8822CU, +RTL8811CU. + +Closes: https://lore.kernel.org/linux-wireless/6e7ecb47-7ea0-433a-a19f-05f88a2edf6b@gmail.com/ +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/9cee7a34-c38d-4128-824d-0ec139ca5a4e@gmail.com +--- + drivers/net/wireless/realtek/rtw88/usb.c | 79 +++++++++++++++++++----- + drivers/net/wireless/realtek/rtw88/usb.h | 3 + + 2 files changed, 67 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c +index 28679d9cdffc..1572b61cf877 100644 +--- a/drivers/net/wireless/realtek/rtw88/usb.c ++++ b/drivers/net/wireless/realtek/rtw88/usb.c +@@ -586,7 +586,7 @@ static void rtw_usb_rx_handler(struct work_struct *work) + goto skip_packet; + } + +- skb = alloc_skb(skb_len, GFP_KERNEL); ++ skb = alloc_skb(skb_len, GFP_ATOMIC); + if (!skb) { + rtw_dbg(rtwdev, RTW_DBG_USB, + "failed to allocate RX skb of size %u\n", +@@ -613,32 +613,70 @@ static void rtw_usb_rx_handler(struct work_struct *work) + rx_desc += next_pkt; + } while (rx_desc + pkt_desc_sz < rx_skb->data + rx_skb->len); + +- dev_kfree_skb_any(rx_skb); ++ if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW_USB_RX_SKB_NUM) ++ dev_kfree_skb_any(rx_skb); ++ else ++ skb_queue_tail(&rtwusb->rx_free_queue, rx_skb); + } + } + + static void rtw_usb_read_port_complete(struct urb *urb); + +-static void rtw_usb_rx_resubmit(struct rtw_usb *rtwusb, struct rx_usb_ctrl_block *rxcb) ++static void rtw_usb_rx_resubmit(struct rtw_usb *rtwusb, ++ struct rx_usb_ctrl_block *rxcb, ++ gfp_t gfp) + { + struct rtw_dev *rtwdev = rtwusb->rtwdev; ++ struct sk_buff *rx_skb; + int error; + +- rxcb->rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_ATOMIC); +- if (!rxcb->rx_skb) +- return; ++ rx_skb = skb_dequeue(&rtwusb->rx_free_queue); ++ if (!rx_skb) ++ rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, gfp); ++ ++ if (!rx_skb) ++ goto try_later; ++ ++ skb_reset_tail_pointer(rx_skb); ++ rx_skb->len = 0; ++ ++ rxcb->rx_skb = rx_skb; + + usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev, + usb_rcvbulkpipe(rtwusb->udev, rtwusb->pipe_in), + rxcb->rx_skb->data, RTW_USB_MAX_RECVBUF_SZ, + rtw_usb_read_port_complete, rxcb); + +- error = usb_submit_urb(rxcb->rx_urb, GFP_ATOMIC); ++ error = usb_submit_urb(rxcb->rx_urb, gfp); + if (error) { +- kfree_skb(rxcb->rx_skb); ++ skb_queue_tail(&rtwusb->rx_free_queue, rxcb->rx_skb); ++ + if (error != -ENODEV) + rtw_err(rtwdev, "Err sending rx data urb %d\n", + error); ++ ++ if (error == -ENOMEM) ++ goto try_later; ++ } ++ ++ return; ++ ++try_later: ++ rxcb->rx_skb = NULL; ++ queue_work(rtwusb->rxwq, &rtwusb->rx_urb_work); ++} ++ ++static void rtw_usb_rx_resubmit_work(struct work_struct *work) ++{ ++ struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_urb_work); ++ struct rx_usb_ctrl_block *rxcb; ++ int i; ++ ++ for (i = 0; i < RTW_USB_RXCB_NUM; i++) { ++ rxcb = &rtwusb->rx_cb[i]; ++ ++ if (!rxcb->rx_skb) ++ rtw_usb_rx_resubmit(rtwusb, rxcb, GFP_ATOMIC); + } + } + +@@ -654,15 +692,16 @@ static void rtw_usb_read_port_complete(struct urb *urb) + urb->actual_length < 24) { + rtw_err(rtwdev, "failed to get urb length:%d\n", + urb->actual_length); +- if (skb) +- dev_kfree_skb_any(skb); ++ skb_queue_tail(&rtwusb->rx_free_queue, skb); + } else { + skb_put(skb, urb->actual_length); + skb_queue_tail(&rtwusb->rx_queue, skb); + queue_work(rtwusb->rxwq, &rtwusb->rx_work); + } +- rtw_usb_rx_resubmit(rtwusb, rxcb); ++ rtw_usb_rx_resubmit(rtwusb, rxcb, GFP_ATOMIC); + } else { ++ skb_queue_tail(&rtwusb->rx_free_queue, skb); ++ + switch (urb->status) { + case -EINVAL: + case -EPIPE: +@@ -680,8 +719,6 @@ static void rtw_usb_read_port_complete(struct urb *urb) + rtw_err(rtwdev, "status %d\n", urb->status); + break; + } +- if (skb) +- dev_kfree_skb_any(skb); + } + } + +@@ -869,16 +906,26 @@ static struct rtw_hci_ops rtw_usb_ops = { + static int rtw_usb_init_rx(struct rtw_dev *rtwdev) + { + struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ struct sk_buff *rx_skb; ++ int i; + +- rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq"); ++ rtwusb->rxwq = alloc_workqueue("rtw88_usb: rx wq", WQ_BH, 0); + if (!rtwusb->rxwq) { + rtw_err(rtwdev, "failed to create RX work queue\n"); + return -ENOMEM; + } + + skb_queue_head_init(&rtwusb->rx_queue); ++ skb_queue_head_init(&rtwusb->rx_free_queue); + + INIT_WORK(&rtwusb->rx_work, rtw_usb_rx_handler); ++ INIT_WORK(&rtwusb->rx_urb_work, rtw_usb_rx_resubmit_work); ++ ++ for (i = 0; i < RTW_USB_RX_SKB_NUM; i++) { ++ rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_KERNEL); ++ if (rx_skb) ++ skb_queue_tail(&rtwusb->rx_free_queue, rx_skb); ++ } + + return 0; + } +@@ -891,7 +938,7 @@ static void rtw_usb_setup_rx(struct rtw_dev *rtwdev) + for (i = 0; i < RTW_USB_RXCB_NUM; i++) { + struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; + +- rtw_usb_rx_resubmit(rtwusb, rxcb); ++ rtw_usb_rx_resubmit(rtwusb, rxcb, GFP_KERNEL); + } + } + +@@ -903,6 +950,8 @@ static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev) + + flush_workqueue(rtwusb->rxwq); + destroy_workqueue(rtwusb->rxwq); ++ ++ skb_queue_purge(&rtwusb->rx_free_queue); + } + + static int rtw_usb_init_tx(struct rtw_dev *rtwdev) +diff --git a/drivers/net/wireless/realtek/rtw88/usb.h b/drivers/net/wireless/realtek/rtw88/usb.h +index 86697a5c0103..9b695b688b24 100644 +--- a/drivers/net/wireless/realtek/rtw88/usb.h ++++ b/drivers/net/wireless/realtek/rtw88/usb.h +@@ -38,6 +38,7 @@ + #define RTW_USB_RXAGG_TIMEOUT 10 + + #define RTW_USB_RXCB_NUM 4 ++#define RTW_USB_RX_SKB_NUM 8 + + #define RTW_USB_EP_MAX 4 + +@@ -81,7 +82,9 @@ struct rtw_usb { + + struct rx_usb_ctrl_block rx_cb[RTW_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; + }; + + static inline struct rtw_usb_tx_data *rtw_usb_get_tx_data(struct sk_buff *skb) +-- +2.43.0 +