From 34d9a2aa7f5015f69899a8f665b052b8dcf87317 Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Tue, 24 Jun 2025 10:52:40 +0800 Subject: [PATCH 01/58] wifi: rtw88: coex: Use bitwise instead of arithmetic operator for flags This silences the following coccinelle warning: WARNING: sum of probable bitmasks, consider | Compile tested only. Signed-off-by: Pei Xiao Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/c68a8642c325f626ac34ccee71d9d9aa69f0c92c.1750733428.git.xiaopei01@kylinos.cn --- drivers/net/wireless/realtek/rtw88/coex.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 64904278ddad..b4dc6ff2c175 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -1501,28 +1501,28 @@ static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev) algorithm = COEX_ALGO_HFP; break; case BPM_HID: - case BPM_HFP + BPM_HID: + case BPM_HFP | BPM_HID: algorithm = COEX_ALGO_HID; break; - case BPM_HFP + BPM_A2DP: - case BPM_HID + BPM_A2DP: - case BPM_HFP + BPM_HID + BPM_A2DP: + case BPM_HFP | BPM_A2DP: + case BPM_HID | BPM_A2DP: + case BPM_HFP | BPM_HID | BPM_A2DP: algorithm = COEX_ALGO_A2DP_HID; break; - case BPM_HFP + BPM_PAN: - case BPM_HID + BPM_PAN: - case BPM_HFP + BPM_HID + BPM_PAN: + case BPM_HFP | BPM_PAN: + case BPM_HID | BPM_PAN: + case BPM_HFP | BPM_HID | BPM_PAN: algorithm = COEX_ALGO_PAN_HID; break; - case BPM_HFP + BPM_A2DP + BPM_PAN: - case BPM_HID + BPM_A2DP + BPM_PAN: - case BPM_HFP + BPM_HID + BPM_A2DP + BPM_PAN: + case BPM_HFP | BPM_A2DP | BPM_PAN: + case BPM_HID | BPM_A2DP | BPM_PAN: + case BPM_HFP | BPM_HID | BPM_A2DP | BPM_PAN: algorithm = COEX_ALGO_A2DP_PAN_HID; break; case BPM_PAN: algorithm = COEX_ALGO_PAN; break; - case BPM_A2DP + BPM_PAN: + case BPM_A2DP | BPM_PAN: algorithm = COEX_ALGO_A2DP_PAN; break; case BPM_A2DP: From 626afc6cd5369bbf3c4b487ab1bb87a7e5ff0b3b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:51:56 +0800 Subject: [PATCH 02/58] wifi: rtw89: 8851b: rfk: extend DPK path_ok type to u8 Originally the type of path_ok is bool to denote that DPK is ready on certain path and can be enabled. For RTL8851B, hardware design can support more than one calibration set, so use type u8 instead to record the hardware set in current use. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035201.16416-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index cdacf100a59a..06ceb77a1cc6 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5146,7 +5146,7 @@ struct rtw89_dpk_bkup_para { enum rtw89_band band; enum rtw89_bandwidth bw; u8 ch; - bool path_ok; + u8 path_ok; u8 mdpd_en; u8 txagc_dpk; u8 ther_dpk; From 64d0633f1c476ed234355f7dca3c9cf83bb9f38b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:51:57 +0800 Subject: [PATCH 03/58] wifi: rtw89: 8851b: set ADC bandwidth select according to calibration value To handle hardware characteristic of ADC, calibrate the function and add a efuse field to record result, which driver uses it to set proper value accordingly. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035201.16416-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 28 ++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 06ceb77a1cc6..a72cd6e13de2 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3480,6 +3480,7 @@ struct rtw89_efuse { u8 addr[ETH_ALEN]; u8 rfe_type; char country_code[2]; + u8 adc_td; }; struct rtw89_phy_rate_pattern { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index c55833f259de..287d53203b38 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -712,12 +712,22 @@ static void rtw8851b_phycap_parsing_gain_comp(struct rtw89_dev *rtwdev, u8 *phyc gain->comp_valid = valid; } +static void rtw8851b_phycap_parsing_adc_td(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + u32 phycap_addr = rtwdev->chip->phycap_addr; + struct rtw89_efuse *efuse = &rtwdev->efuse; + const u32 addr_adc_td = 0x5AF; + + efuse->adc_td = phycap_map[addr_adc_td - phycap_addr] & GENMASK(4, 0); +} + static int rtw8851b_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) { rtw8851b_phycap_parsing_tssi(rtwdev, phycap_map); rtw8851b_phycap_parsing_thermal_trim(rtwdev, phycap_map); rtw8851b_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); rtw8851b_phycap_parsing_gain_comp(rtwdev, phycap_map); + rtw8851b_phycap_parsing_adc_td(rtwdev, phycap_map); return 0; } @@ -1083,10 +1093,26 @@ static void rtw8851b_ctrl_ch(struct rtw89_dev *rtwdev, static void rtw8851b_bw_setting(struct rtw89_dev *rtwdev, u8 bw) { + struct rtw89_efuse *efuse = &rtwdev->efuse; + u8 adc_bw_sel; + + switch (efuse->adc_td) { + default: + case 0x19: + adc_bw_sel = 0x4; + break; + case 0x11: + adc_bw_sel = 0x5; + break; + case 0x9: + adc_bw_sel = 0x3; + break; + } + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, 0x4); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, adc_bw_sel); rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_MUL, 0xf); rtw89_phy_write32_mask(rtwdev, R_ADCMOD, B_ADCMOD_LP, 0xa); rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); From 408d55331f961b4dbbcaa2edf63999ab2b2e3907 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:51:58 +0800 Subject: [PATCH 04/58] wifi: rtw89: 8851b: adjust ADC setting for RF calibration To get expected result of RF calibration at runtime, adjust ADC setting ahead for coming changes of RF calibration. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035201.16416-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 287d53203b38..7801732d5b8b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -1109,39 +1109,56 @@ static void rtw8851b_bw_setting(struct rtw89_dev *rtwdev, u8 bw) break; } - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, adc_bw_sel); rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_MUL, 0xf); rtw89_phy_write32_mask(rtwdev, R_ADCMOD, B_ADCMOD_LP, 0xa); - rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_RC, 0x3); switch (bw) { case RTW89_CHANNEL_WIDTH_5: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x1); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x0); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_10: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x1); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_20: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x2); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_40: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x2); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x0); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; default: rtw89_warn(rtwdev, "Fail to set ADC\n"); From de2a9b2837608945d725d94d8dea44377e2fc291 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:51:59 +0800 Subject: [PATCH 05/58] wifi: rtw89: 8851b: update NCTL 0xB To support new commands in DPK 0x11, update NCTL to version 0xB. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035201.16416-5-pkshih@realtek.com --- .../wireless/realtek/rtw89/rtw8851b_table.c | 501 +++++++++--------- 1 file changed, 250 insertions(+), 251 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c index 522883c8dfb9..a9c309c245c3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c @@ -2320,9 +2320,9 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x813c, 0x40000000}, {0x8140, 0x00000000}, {0x8144, 0x0b040b03}, - {0x8148, 0x07020b04}, - {0x814c, 0x07020b04}, - {0x8150, 0xa0a00000}, + {0x8148, 0x07020a04}, + {0x814c, 0x07020a04}, + {0x8150, 0xe4e40000}, {0x8158, 0xffffffff}, {0x815c, 0xffffffff}, {0x8160, 0xffffffff}, @@ -2577,14 +2577,14 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8534, 0x400042fe}, {0x8538, 0x50554200}, {0x853c, 0xb4183000}, - {0x8540, 0xe537a50f}, + {0x8540, 0xe535a50f}, {0x8544, 0xf12bf02b}, {0x8548, 0xf32bf22b}, {0x854c, 0xf62bf42b}, {0x8550, 0xf82bf72b}, {0x8554, 0xfa2bf92b}, {0x8558, 0xfd2bfc2b}, - {0x855c, 0xe537fe2b}, + {0x855c, 0xe535fe2b}, {0x8560, 0xf12af02a}, {0x8564, 0xf32af22a}, {0x8568, 0xf52af42a}, @@ -2653,7 +2653,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8664, 0x9700140f}, {0x8668, 0x00017430}, {0x866c, 0xe39ce35e}, - {0x8670, 0xe52a0bbd}, + {0x8670, 0xe5280bbd}, {0x8674, 0xe36a0001}, {0x8678, 0x0001e3c4}, {0x867c, 0x55005b30}, @@ -2664,93 +2664,93 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8690, 0x46100005}, {0x8694, 0x00010004}, {0x8698, 0x30f8e35e}, - {0x869c, 0xe52a0023}, + {0x869c, 0xe5280023}, {0x86a0, 0x54ed0002}, {0x86a4, 0x00230baa}, - {0x86a8, 0x0002e52a}, + {0x86a8, 0x0002e528}, {0x86ac, 0xe356e3e4}, {0x86b0, 0xe35e0001}, {0x86b4, 0x002230f3}, - {0x86b8, 0x0002e52a}, + {0x86b8, 0x0002e528}, {0x86bc, 0x0baa54ec}, - {0x86c0, 0xe52a0022}, + {0x86c0, 0xe5280022}, {0x86c4, 0xe3e40002}, {0x86c8, 0x0001e356}, {0x86cc, 0x0baae35e}, {0x86d0, 0xe3e430ec}, {0x86d4, 0x0001e356}, {0x86d8, 0x6d0f6c67}, - {0x86dc, 0xe52ae39c}, + {0x86dc, 0xe528e39c}, {0x86e0, 0xe39c6c8b}, - {0x86e4, 0x0bace52a}, + {0x86e4, 0x0bace528}, {0x86e8, 0x6d0f6cb3}, - {0x86ec, 0xe52ae39c}, + {0x86ec, 0xe528e39c}, {0x86f0, 0x6cdb0bad}, {0x86f4, 0xe39c6d0f}, - {0x86f8, 0x6cf5e52a}, + {0x86f8, 0x6cf5e528}, {0x86fc, 0xe39c6d0f}, - {0x8700, 0x6c0be52a}, + {0x8700, 0x6c0be528}, {0x8704, 0xe39c6d00}, - {0x8708, 0x6c25e52a}, - {0x870c, 0xe52ae39c}, + {0x8708, 0x6c25e528}, + {0x870c, 0xe528e39c}, {0x8710, 0x6c4df8c6}, - {0x8714, 0xe52ae39c}, + {0x8714, 0xe528e39c}, {0x8718, 0x6c75f9cf}, - {0x871c, 0xe52ae39c}, + {0x871c, 0xe528e39c}, {0x8720, 0xe39c6c99}, - {0x8724, 0xfad6e52a}, + {0x8724, 0xfad6e528}, {0x8728, 0x21e87410}, {0x872c, 0x6e670009}, {0x8730, 0xe3c46f0f}, - {0x8734, 0x7410e52f}, + {0x8734, 0x7410e52d}, {0x8738, 0x000b21e8}, {0x873c, 0xe3c46e8b}, - {0x8740, 0x7410e52f}, + {0x8740, 0x7410e52d}, {0x8744, 0x000d21e8}, {0x8748, 0x6f0f6eb3}, - {0x874c, 0xe52fe3c4}, + {0x874c, 0xe52de3c4}, {0x8750, 0xfe07ff08}, {0x8754, 0x21e87410}, {0x8758, 0x6ec7000e}, - {0x875c, 0xe52fe3c4}, + {0x875c, 0xe52de3c4}, {0x8760, 0x21e87410}, {0x8764, 0x6edb000f}, {0x8768, 0xe3c46f0f}, - {0x876c, 0x7410e52f}, + {0x876c, 0x7410e52d}, {0x8770, 0x001021e8}, {0x8774, 0xe3c46eef}, - {0x8778, 0xff03e52f}, - {0x877c, 0xe52ffe02}, + {0x8778, 0xff03e52d}, + {0x877c, 0xe52dfe02}, {0x8780, 0x21e87410}, {0x8784, 0x6e110013}, {0x8788, 0xe3c46f00}, - {0x878c, 0xff03e52f}, - {0x8790, 0xe52ffe02}, + {0x878c, 0xff03e52d}, + {0x8790, 0xe52dfe02}, {0x8794, 0x21e87410}, {0x8798, 0x6e250014}, - {0x879c, 0xe52fe3c4}, + {0x879c, 0xe52de3c4}, {0x87a0, 0xff08fc24}, {0x87a4, 0x7410fe07}, {0x87a8, 0x001521e8}, {0x87ac, 0xe3c46e39}, - {0x87b0, 0x7410e52f}, + {0x87b0, 0x7410e52d}, {0x87b4, 0x001621e8}, {0x87b8, 0xe3c46e4d}, - {0x87bc, 0xfd27e52f}, + {0x87bc, 0xfd27e52d}, {0x87c0, 0x21e87410}, {0x87c4, 0x6e750018}, - {0x87c8, 0xe52fe3c4}, + {0x87c8, 0xe52de3c4}, {0x87cc, 0x21e87410}, {0x87d0, 0x6e99001a}, - {0x87d4, 0xe52fe3c4}, + {0x87d4, 0xe52de3c4}, {0x87d8, 0xe36afe24}, {0x87dc, 0x63404380}, {0x87e0, 0x43006880}, {0x87e4, 0x31300bac}, - {0x87e8, 0xe52f0022}, + {0x87e8, 0xe52d0022}, {0x87ec, 0x54ec0002}, {0x87f0, 0x00220baa}, - {0x87f4, 0x0002e52f}, + {0x87f4, 0x0002e52d}, {0x87f8, 0xe362e3e4}, {0x87fc, 0xe36a0001}, {0x8800, 0x63404380}, @@ -2770,7 +2770,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8838, 0x55010004}, {0x883c, 0x66055b40}, {0x8840, 0x62000007}, - {0x8844, 0xe40e6300}, + {0x8844, 0xe40c6300}, {0x8848, 0x09000004}, {0x884c, 0x0b400a01}, {0x8850, 0x0e010d00}, @@ -2782,13 +2782,13 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8868, 0x00044d01}, {0x886c, 0x00074300}, {0x8870, 0x05a30562}, - {0x8874, 0xe40e961f}, + {0x8874, 0xe40c961f}, {0x8878, 0xe37e0004}, {0x887c, 0x06a20007}, - {0x8880, 0xe40e07a3}, + {0x8880, 0xe40c07a3}, {0x8884, 0xe37e0004}, - {0x8888, 0x0002e3fe}, - {0x888c, 0x4380e406}, + {0x8888, 0x0002e3fc}, + {0x888c, 0x4380e404}, {0x8890, 0x4d000007}, {0x8894, 0x43000004}, {0x8898, 0x000742fe}, @@ -2815,13 +2815,13 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x88ec, 0x42000004}, {0x88f0, 0x00070001}, {0x88f4, 0x62006220}, - {0x88f8, 0x0001e406}, + {0x88f8, 0x0001e404}, {0x88fc, 0x63000007}, {0x8900, 0x09000004}, {0x8904, 0x0e010a00}, {0x8908, 0x00070032}, - {0x890c, 0xe40e06a2}, - {0x8910, 0x0002e41a}, + {0x890c, 0xe40c06a2}, + {0x8910, 0x0002e418}, {0x8914, 0x000742fe}, {0x8918, 0x00044d00}, {0x891c, 0x00014200}, @@ -2839,50 +2839,50 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x894c, 0x00014300}, {0x8950, 0x6c060005}, {0x8954, 0xe2aae298}, - {0x8958, 0xe42ae285}, - {0x895c, 0xe432e2f3}, + {0x8958, 0xe428e285}, + {0x895c, 0xe430e2f3}, {0x8960, 0x0001e30c}, {0x8964, 0x0005e285}, {0x8968, 0xe2986c06}, - {0x896c, 0xe42ae4a9}, - {0x8970, 0xe432e2f3}, + {0x896c, 0xe428e4a7}, + {0x8970, 0xe430e2f3}, {0x8974, 0x0001e30c}, {0x8978, 0x6c000005}, {0x897c, 0xe2aae298}, - {0x8980, 0xe445e285}, - {0x8984, 0xe44de2f3}, + {0x8980, 0xe443e285}, + {0x8984, 0xe44be2f3}, {0x8988, 0x0001e30c}, {0x898c, 0x0005e285}, {0x8990, 0xe2986c00}, - {0x8994, 0xe445e4a9}, - {0x8998, 0xe44de2f3}, + {0x8994, 0xe443e4a7}, + {0x8998, 0xe44be2f3}, {0x899c, 0x0001e30c}, {0x89a0, 0x6c040005}, {0x89a4, 0xe2aae298}, - {0x89a8, 0xe460e285}, - {0x89ac, 0xe468e2f3}, + {0x89a8, 0xe45ee285}, + {0x89ac, 0xe466e2f3}, {0x89b0, 0x0001e30c}, {0x89b4, 0x0005e285}, {0x89b8, 0xe2986c04}, - {0x89bc, 0xe460e4a9}, - {0x89c0, 0xe468e2f3}, + {0x89bc, 0xe45ee4a7}, + {0x89c0, 0xe466e2f3}, {0x89c4, 0x0001e30c}, {0x89c8, 0x6c020005}, {0x89cc, 0xe2aae298}, - {0x89d0, 0xe47be285}, - {0x89d4, 0xe483e2f3}, + {0x89d0, 0xe479e285}, + {0x89d4, 0xe481e2f3}, {0x89d8, 0x0001e30c}, {0x89dc, 0x0005e285}, {0x89e0, 0xe2986c02}, - {0x89e4, 0xe47be4a9}, - {0x89e8, 0xe483e2f3}, + {0x89e4, 0xe479e4a7}, + {0x89e8, 0xe481e2f3}, {0x89ec, 0x0001e30c}, {0x89f0, 0x43800004}, {0x89f4, 0x610a6008}, {0x89f8, 0x63ce6200}, {0x89fc, 0x60800006}, {0x8a00, 0x00047f00}, - {0x8a04, 0xe4e04300}, + {0x8a04, 0xe4de4300}, {0x8a08, 0x00070001}, {0x8a0c, 0x4d015500}, {0x8a10, 0x74200004}, @@ -2895,22 +2895,22 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8a2c, 0x00014300}, {0x8a30, 0x74200004}, {0x8a34, 0x77000005}, - {0x8a38, 0x73887e07}, + {0x8a38, 0x73887e06}, {0x8a3c, 0x8f007380}, {0x8a40, 0x0004140f}, {0x8a44, 0x00057430}, {0x8a48, 0x00017300}, - {0x8a4c, 0x0005e496}, + {0x8a4c, 0x0005e494}, {0x8a50, 0x00017300}, {0x8a54, 0x43800004}, {0x8a58, 0x0006b103}, {0x8a5c, 0x91037cdb}, {0x8a60, 0x40db0007}, {0x8a64, 0x43000004}, - {0x8a68, 0x0005e496}, + {0x8a68, 0x0005e494}, {0x8a6c, 0x00067380}, {0x8a70, 0x60025d01}, - {0x8a74, 0xe4ba6200}, + {0x8a74, 0xe4b86200}, {0x8a78, 0x73000005}, {0x8a7c, 0x76080007}, {0x8a80, 0x00047578}, @@ -2943,8 +2943,8 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8aec, 0x7cdb0006}, {0x8af0, 0x00079103}, {0x8af4, 0x000440db}, - {0x8af8, 0xe4964300}, - {0x8afc, 0xe4ba7e03}, + {0x8af8, 0xe4944300}, + {0x8afc, 0xe4b87e03}, {0x8b00, 0x43800004}, {0x8b04, 0x0006b103}, {0x8b08, 0x91037c5b}, @@ -2976,14 +2976,14 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8b70, 0x43000004}, {0x8b74, 0x73000005}, {0x8b78, 0x76000007}, - {0x8b7c, 0xe4c30001}, + {0x8b7c, 0xe4c10001}, {0x8b80, 0x00040001}, {0x8b84, 0x60004380}, {0x8b88, 0x62016100}, {0x8b8c, 0x00066310}, {0x8b90, 0x00046000}, {0x8b94, 0x00014300}, - {0x8b98, 0x0001e4e0}, + {0x8b98, 0x0001e4de}, {0x8b9c, 0x4e004f02}, {0x8ba0, 0x52015302}, {0x8ba4, 0x140f0001}, @@ -3030,7 +3030,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8c48, 0xbf1ae3ac}, {0x8c4c, 0xe36e300b}, {0x8c50, 0xe390e377}, - {0x8c54, 0x0001e523}, + {0x8c54, 0x0001e521}, {0x8c58, 0x54c054bf}, {0x8c5c, 0x54c154a3}, {0x8c60, 0x4c1854a4}, @@ -3039,7 +3039,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8c6c, 0xbf051402}, {0x8c70, 0x54a354c1}, {0x8c74, 0xbf011402}, - {0x8c78, 0x54dfe534}, + {0x8c78, 0x54dfe532}, {0x8c7c, 0x54bf0001}, {0x8c80, 0x050a54e5}, {0x8c84, 0x000154df}, @@ -3060,186 +3060,185 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8cc0, 0x56005610}, {0x8cc4, 0x00018c00}, {0x8cc8, 0x57005704}, - {0x8ccc, 0xa7038e00}, - {0x8cd0, 0x33f0aff7}, - {0x8cd4, 0xaf034019}, - {0x8cd8, 0x33f0402b}, - {0x8cdc, 0x33df402b}, - {0x8ce0, 0x57005708}, - {0x8ce4, 0x57818e00}, - {0x8ce8, 0x8e005780}, - {0x8cec, 0x00074380}, - {0x8cf0, 0x5c005c01}, - {0x8cf4, 0x00041403}, - {0x8cf8, 0x00014300}, - {0x8cfc, 0x0007427f}, - {0x8d00, 0x62006280}, - {0x8d04, 0x00049200}, - {0x8d08, 0x00014200}, - {0x8d0c, 0x0007427f}, - {0x8d10, 0x63146394}, - {0x8d14, 0x00049200}, - {0x8d18, 0x00014200}, - {0x8d1c, 0x42fe0004}, - {0x8d20, 0x4d010007}, - {0x8d24, 0x42000004}, - {0x8d28, 0x140f7420}, - {0x8d2c, 0x57005710}, - {0x8d30, 0x0001141f}, - {0x8d34, 0x42fe0004}, - {0x8d38, 0x4d010007}, - {0x8d3c, 0x42000004}, - {0x8d40, 0x140f7420}, - {0x8d44, 0x000742bf}, - {0x8d48, 0x62006240}, - {0x8d4c, 0x0004141f}, - {0x8d50, 0x00014200}, - {0x8d54, 0x5d060006}, - {0x8d58, 0x61046003}, - {0x8d5c, 0x00056201}, - {0x8d60, 0x00017310}, - {0x8d64, 0x43800004}, - {0x8d68, 0x5e010007}, - {0x8d6c, 0x140a5e00}, - {0x8d70, 0x0006b103}, - {0x8d74, 0x91037f07}, - {0x8d78, 0x43070007}, - {0x8d7c, 0x5c000006}, - {0x8d80, 0x5e035d02}, - {0x8d84, 0x43000004}, - {0x8d88, 0x00060001}, - {0x8d8c, 0x60005d04}, - {0x8d90, 0x62016104}, - {0x8d94, 0x73100005}, - {0x8d98, 0x00040001}, - {0x8d9c, 0x00074380}, - {0x8da0, 0x5e005e01}, - {0x8da4, 0xb103140a}, - {0x8da8, 0x7fc60006}, - {0x8dac, 0x00079103}, - {0x8db0, 0x000643c6}, - {0x8db4, 0x5d025c00}, - {0x8db8, 0x00045e03}, - {0x8dbc, 0x00014300}, - {0x8dc0, 0x5d040006}, - {0x8dc4, 0x61046000}, - {0x8dc8, 0x00056201}, - {0x8dcc, 0x00017310}, - {0x8dd0, 0x43800004}, - {0x8dd4, 0x5e010007}, - {0x8dd8, 0x140a5e00}, - {0x8ddc, 0x0006b103}, - {0x8de0, 0x91037fc6}, - {0x8de4, 0x43c60007}, - {0x8de8, 0x5c000006}, - {0x8dec, 0x5e035d02}, - {0x8df0, 0x43000004}, - {0x8df4, 0x00060001}, - {0x8df8, 0x60025d00}, - {0x8dfc, 0x62016100}, - {0x8e00, 0x73000005}, - {0x8e04, 0x00040001}, - {0x8e08, 0x00074380}, - {0x8e0c, 0x5e005e01}, - {0x8e10, 0xb103140a}, - {0x8e14, 0x7fc00006}, - {0x8e18, 0x00079103}, - {0x8e1c, 0x000643c0}, - {0x8e20, 0x5d025c00}, - {0x8e24, 0x00045e03}, - {0x8e28, 0x00014300}, - {0x8e2c, 0x7e020005}, - {0x8e30, 0x42f70004}, - {0x8e34, 0x6c080005}, - {0x8e38, 0x42700004}, - {0x8e3c, 0x73810005}, - {0x8e40, 0x93007380}, - {0x8e44, 0x42f70004}, - {0x8e48, 0x6c000005}, - {0x8e4c, 0x42000004}, - {0x8e50, 0x00040001}, - {0x8e54, 0x00074380}, - {0x8e58, 0x73007304}, - {0x8e5c, 0x72401405}, - {0x8e60, 0x43000004}, - {0x8e64, 0x74040006}, - {0x8e68, 0x40010007}, - {0x8e6c, 0xab004000}, - {0x8e70, 0x0001140f}, - {0x8e74, 0x140ae517}, - {0x8e78, 0x140ae4c3}, - {0x8e7c, 0x0001e51e}, - {0x8e80, 0xe4c3e517}, - {0x8e84, 0x00040001}, - {0x8e88, 0x00047410}, - {0x8e8c, 0x42f04380}, - {0x8e90, 0x62080007}, - {0x8e94, 0x24206301}, - {0x8e98, 0x14c80000}, - {0x8e9c, 0x00002428}, - {0x8ea0, 0x1a4215f4}, - {0x8ea4, 0x6300000b}, - {0x8ea8, 0x42000004}, - {0x8eac, 0x74304300}, - {0x8eb0, 0x4380140f}, - {0x8eb4, 0x73080007}, - {0x8eb8, 0x00047300}, - {0x8ebc, 0x00014300}, - {0x8ec0, 0x4bf00007}, - {0x8ec4, 0x490b4a8f}, - {0x8ec8, 0x4a8e48f1}, - {0x8ecc, 0x48a5490a}, - {0x8ed0, 0x49094a8d}, - {0x8ed4, 0x4a8c487d}, - {0x8ed8, 0x48754908}, - {0x8edc, 0x49074a8b}, - {0x8ee0, 0x4a8a4889}, - {0x8ee4, 0x48b74906}, - {0x8ee8, 0x49054a89}, - {0x8eec, 0x4a8848fc}, - {0x8ef0, 0x48564905}, - {0x8ef4, 0x49044a87}, - {0x8ef8, 0x4a8648c1}, - {0x8efc, 0x483d4904}, - {0x8f00, 0x49034a85}, - {0x8f04, 0x4a8448c7}, - {0x8f08, 0x485e4903}, - {0x8f0c, 0x49024a83}, - {0x8f10, 0x4a8248ac}, - {0x8f14, 0x48624902}, - {0x8f18, 0x49024a81}, - {0x8f1c, 0x4a804820}, - {0x8f20, 0x48004900}, - {0x8f24, 0x49014a90}, - {0x8f28, 0x4a10481f}, - {0x8f2c, 0x00060001}, - {0x8f30, 0x5f005f80}, - {0x8f34, 0x00059900}, - {0x8f38, 0x00017300}, - {0x8f3c, 0x63800006}, - {0x8f40, 0x98006300}, - {0x8f44, 0x549f0001}, - {0x8f48, 0x5c015400}, - {0x8f4c, 0x540054df}, - {0x8f50, 0x00015c02}, - {0x8f54, 0x07145c01}, - {0x8f58, 0x5c025400}, - {0x8f5c, 0x5c020001}, - {0x8f60, 0x54000714}, - {0x8f64, 0x00015c01}, - {0x8f68, 0x4c184c98}, - {0x8f6c, 0x00080001}, - {0x8f70, 0x5c020004}, - {0x8f74, 0x09017430}, - {0x8f78, 0x0ba60c01}, - {0x8f7c, 0x77800005}, - {0x8f80, 0x52200007}, - {0x8f84, 0x43800004}, - {0x8f88, 0x610a6008}, - {0x8f8c, 0x63c26200}, - {0x8f90, 0x5c000007}, - {0x8f94, 0x43000004}, - {0x8f98, 0x00000001}, + {0x8ccc, 0x33ee8e00}, + {0x8cd0, 0xaf034019}, + {0x8cd4, 0x33ee402b}, + {0x8cd8, 0x33df402b}, + {0x8cdc, 0x57005708}, + {0x8ce0, 0x57818e00}, + {0x8ce4, 0x8e005780}, + {0x8ce8, 0x00074380}, + {0x8cec, 0x5c005c01}, + {0x8cf0, 0x00041403}, + {0x8cf4, 0x00014300}, + {0x8cf8, 0x0007427f}, + {0x8cfc, 0x62006280}, + {0x8d00, 0x00049200}, + {0x8d04, 0x00014200}, + {0x8d08, 0x0007427f}, + {0x8d0c, 0x63146394}, + {0x8d10, 0x00049200}, + {0x8d14, 0x00014200}, + {0x8d18, 0x42fe0004}, + {0x8d1c, 0x4d010007}, + {0x8d20, 0x42000004}, + {0x8d24, 0x140f7420}, + {0x8d28, 0x57005710}, + {0x8d2c, 0x0001141f}, + {0x8d30, 0x42fe0004}, + {0x8d34, 0x4d010007}, + {0x8d38, 0x42000004}, + {0x8d3c, 0x140f7420}, + {0x8d40, 0x000742bf}, + {0x8d44, 0x62006240}, + {0x8d48, 0x0004141f}, + {0x8d4c, 0x00014200}, + {0x8d50, 0x5d060006}, + {0x8d54, 0x61046003}, + {0x8d58, 0x00056200}, + {0x8d5c, 0x00017310}, + {0x8d60, 0x43800004}, + {0x8d64, 0x5e010007}, + {0x8d68, 0x140a5e00}, + {0x8d6c, 0x0006b103}, + {0x8d70, 0x91037f07}, + {0x8d74, 0x43070007}, + {0x8d78, 0x5c000006}, + {0x8d7c, 0x5e035d02}, + {0x8d80, 0x43000004}, + {0x8d84, 0x00060001}, + {0x8d88, 0x60005d04}, + {0x8d8c, 0x62006104}, + {0x8d90, 0x73100005}, + {0x8d94, 0x00040001}, + {0x8d98, 0x00074380}, + {0x8d9c, 0x5e005e01}, + {0x8da0, 0xb103140a}, + {0x8da4, 0x7fc60006}, + {0x8da8, 0x00079103}, + {0x8dac, 0x000643c6}, + {0x8db0, 0x5d025c00}, + {0x8db4, 0x00045e03}, + {0x8db8, 0x00014300}, + {0x8dbc, 0x5d040006}, + {0x8dc0, 0x61046000}, + {0x8dc4, 0x00056200}, + {0x8dc8, 0x00017310}, + {0x8dcc, 0x43800004}, + {0x8dd0, 0x5e010007}, + {0x8dd4, 0x140a5e00}, + {0x8dd8, 0x0006b103}, + {0x8ddc, 0x91037fc6}, + {0x8de0, 0x43c60007}, + {0x8de4, 0x5c000006}, + {0x8de8, 0x5e035d02}, + {0x8dec, 0x43000004}, + {0x8df0, 0x00060001}, + {0x8df4, 0x60025d00}, + {0x8df8, 0x62006100}, + {0x8dfc, 0x73000005}, + {0x8e00, 0x00040001}, + {0x8e04, 0x00074380}, + {0x8e08, 0x5e005e01}, + {0x8e0c, 0xb103140a}, + {0x8e10, 0x7fc00006}, + {0x8e14, 0x00079103}, + {0x8e18, 0x000643c0}, + {0x8e1c, 0x5d025c00}, + {0x8e20, 0x00045e03}, + {0x8e24, 0x00014300}, + {0x8e28, 0x7e020005}, + {0x8e2c, 0x42f70004}, + {0x8e30, 0x6c080005}, + {0x8e34, 0x42700004}, + {0x8e38, 0x73810005}, + {0x8e3c, 0x93007380}, + {0x8e40, 0x42f70004}, + {0x8e44, 0x6c000005}, + {0x8e48, 0x42000004}, + {0x8e4c, 0x00040001}, + {0x8e50, 0x00074380}, + {0x8e54, 0x73007304}, + {0x8e58, 0x72401405}, + {0x8e5c, 0x43000004}, + {0x8e60, 0x74040006}, + {0x8e64, 0x40010007}, + {0x8e68, 0xab004000}, + {0x8e6c, 0x0001140f}, + {0x8e70, 0x140ae515}, + {0x8e74, 0x140ae4c1}, + {0x8e78, 0x0001e51c}, + {0x8e7c, 0xe4c1e515}, + {0x8e80, 0x00040001}, + {0x8e84, 0x00047410}, + {0x8e88, 0x42f04380}, + {0x8e8c, 0x62080007}, + {0x8e90, 0x24206301}, + {0x8e94, 0x14c80000}, + {0x8e98, 0x00002428}, + {0x8e9c, 0x1a4215f4}, + {0x8ea0, 0x6300000b}, + {0x8ea4, 0x42000004}, + {0x8ea8, 0x74304300}, + {0x8eac, 0x4380140f}, + {0x8eb0, 0x73080007}, + {0x8eb4, 0x00047300}, + {0x8eb8, 0x00014300}, + {0x8ebc, 0x4bf00007}, + {0x8ec0, 0x490b4a8f}, + {0x8ec4, 0x4a8e48f1}, + {0x8ec8, 0x48a5490a}, + {0x8ecc, 0x49094a8d}, + {0x8ed0, 0x4a8c487d}, + {0x8ed4, 0x48754908}, + {0x8ed8, 0x49074a8b}, + {0x8edc, 0x4a8a4889}, + {0x8ee0, 0x48b74906}, + {0x8ee4, 0x49054a89}, + {0x8ee8, 0x4a8848fc}, + {0x8eec, 0x48564905}, + {0x8ef0, 0x49044a87}, + {0x8ef4, 0x4a8648c1}, + {0x8ef8, 0x483d4904}, + {0x8efc, 0x49034a85}, + {0x8f00, 0x4a8448c7}, + {0x8f04, 0x485e4903}, + {0x8f08, 0x49024a83}, + {0x8f0c, 0x4a8248ac}, + {0x8f10, 0x48624902}, + {0x8f14, 0x49024a81}, + {0x8f18, 0x4a804820}, + {0x8f1c, 0x48004900}, + {0x8f20, 0x49014a90}, + {0x8f24, 0x4a10481f}, + {0x8f28, 0x00060001}, + {0x8f2c, 0x5f005f80}, + {0x8f30, 0x00059900}, + {0x8f34, 0x00017300}, + {0x8f38, 0x63800006}, + {0x8f3c, 0x98006300}, + {0x8f40, 0x549f0001}, + {0x8f44, 0x5c015400}, + {0x8f48, 0x540054df}, + {0x8f4c, 0x00015c02}, + {0x8f50, 0x07145c01}, + {0x8f54, 0x5c025400}, + {0x8f58, 0x5c020001}, + {0x8f5c, 0x54000714}, + {0x8f60, 0x00015c01}, + {0x8f64, 0x4c184c98}, + {0x8f68, 0x00080001}, + {0x8f6c, 0x5c020004}, + {0x8f70, 0x09017430}, + {0x8f74, 0x0ba60c01}, + {0x8f78, 0x77800005}, + {0x8f7c, 0x52200007}, + {0x8f80, 0x43800004}, + {0x8f84, 0x610a6008}, + {0x8f88, 0x63c26200}, + {0x8f8c, 0x5c000007}, + {0x8f90, 0x43000004}, + {0x8f94, 0x00000001}, {0x8080, 0x00000004}, {0x8080, 0x00000000}, {0x8088, 0x00000000}, From 56624544c8a63f85f6811b0c2c090d38ca6ab8dc Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:53:28 +0800 Subject: [PATCH 06/58] wifi: rtw89: 8851b: rfk: update DPK to 0x11 Update DPK with TX/RX clock to 960MHz and 1920MHz, which improve performance on certain chips. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035328.16577-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 3 + .../net/wireless/realtek/rtw89/rtw8851b_rfk.c | 109 +++++++++++++++--- .../realtek/rtw89/rtw8851b_rfk_table.c | 25 ---- .../realtek/rtw89/rtw8851b_rfk_table.h | 1 - 4 files changed, 98 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 4a65b0c9c2d1..90625d692b4d 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -8775,6 +8775,8 @@ #define B_P0_TSSI_RFC GENMASK(28, 27) #define B_P0_TSSI_OFT_EN BIT(28) #define B_P0_TSSI_OFT GENMASK(7, 0) +#define R_P0_TSSI_SLOPE_CAL 0x581c +#define B_P0_TSSI_SLOPE_CAL_EN BIT(20) #define R_P0_TSSI_AVG 0x5820 #define B_P0_TSSI_EN BIT(31) #define B_P0_TSSI_AVG GENMASK(15, 12) @@ -9268,6 +9270,7 @@ #define B_WDADC_SEL GENMASK(5, 4) #define R_ADCMOD 0xC0E8 #define B_ADCMOD_LP GENMASK(31, 16) +#define B_ADCMOD_AUTO_RST BIT(6) #define R_DCIM 0xC0EC #define B_DCIM_RC GENMASK(23, 16) #define B_DCIM_FR GENMASK(14, 13) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index f72b3ac6f149..907ce6d3c1b1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -12,8 +12,8 @@ #include "rtw8851b_rfk_table.h" #include "rtw8851b_table.h" -#define DPK_VER_8851B 0x5 -#define DPK_KIP_REG_NUM_8851B 7 +#define DPK_VER_8851B 0x11 +#define DPK_KIP_REG_NUM_8851B 8 #define DPK_RF_REG_NUM_8851B 4 #define DPK_KSET_NUM 4 #define RTW8851B_RXK_GROUP_NR 4 @@ -85,6 +85,24 @@ enum rf_mode { RF_RXK2 = 0x7, }; +enum adc_ck { + ADC_NA = 0, + ADC_480M = 1, + ADC_960M = 2, + ADC_1920M = 3, +}; + +enum dac_ck { + DAC_40M = 0, + DAC_80M = 1, + DAC_120M = 2, + DAC_160M = 3, + DAC_240M = 4, + DAC_320M = 5, + DAC_480M = 6, + DAC_960M = 7, +}; + static const u32 _tssi_de_cck_long[RF_PATH_NUM_8851B] = {0x5858}; static const u32 _tssi_de_cck_short[RF_PATH_NUM_8851B] = {0x5860}; static const u32 _tssi_de_mcs_20m[RF_PATH_NUM_8851B] = {0x5838}; @@ -116,7 +134,7 @@ static const u32 rtw8851b_backup_rf_regs[] = { #define BACKUP_RF_REGS_NR ARRAY_SIZE(rtw8851b_backup_rf_regs) static const u32 dpk_kip_reg[DPK_KIP_REG_NUM_8851B] = { - 0x813c, 0x8124, 0xc0ec, 0xc0e8, 0xc0c4, 0xc0d4, 0xc0d8}; + 0x813c, 0x8124, 0xc0ec, 0xc0e8, 0xc0c4, 0xc0d4, 0xc0d8, 0x12a0}; static const u32 dpk_rf_reg[DPK_RF_REG_NUM_8851B] = {0xde, 0x8f, 0x5, 0x10005}; static void _set_ch(struct rtw89_dev *rtwdev, u32 val); @@ -163,6 +181,51 @@ static void _rfk_drf_direct_cntrl(struct rtw89_dev *rtwdev, rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x0); } +static void _txck_force(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool force, enum dac_ck ck) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_TXCK_ON, 0x0); + + if (!force) + return; + + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_TXCK_VAL, ck); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_TXCK_ON, 0x1); +} + +static void _rxck_force(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool force, enum adc_ck ck) +{ + static const u32 ck960_8851b[] = {0x8, 0x2, 0x2, 0x4, 0xf, 0xa, 0x93}; + static const u32 ck1920_8851b[] = {0x9, 0x0, 0x0, 0x3, 0xf, 0xa, 0x49}; + const u32 *data; + + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x0); + if (!force) + return; + + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_VAL, ck); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x1); + + switch (ck) { + case ADC_960M: + data = ck960_8851b; + break; + case ADC_1920M: + default: + data = ck1920_8851b; + break; + } + + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_CTL, data[0]); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_EN, data[1]); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_BW0, data[2]); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 | (path << 8), B_P0_CFCH_BW1, data[3]); + rtw89_phy_write32_mask(rtwdev, R_DRCK | (path << 8), B_DRCK_MUL, data[4]); + rtw89_phy_write32_mask(rtwdev, R_ADCMOD | (path << 8), B_ADCMOD_LP, data[5]); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 8), B_P0_RXCK_ADJ, data[6]); +} + static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) { u32 rf_mode; @@ -1794,7 +1857,21 @@ static void _dpk_bb_afe_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path pat rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(28 + path), 0x0); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), MASKDWORD, 0xd801dffd); - rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_bb_afe_defs_tbl); + _txck_force(rtwdev, path, true, DAC_960M); + _rxck_force(rtwdev, path, true, ADC_1920M); + + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADCMOD, B_ADCMOD_AUTO_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x1f); + udelay(10); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x13); + udelay(2); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0001); + udelay(2); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0041); + udelay(10); rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(20 + path), 0x1); rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(28 + path), 0x1); @@ -1827,6 +1904,17 @@ static void _dpk_tssi_pause(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, is_pause ? "pause" : "resume"); } +static +void _dpk_tssi_slope_k_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool is_on) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_SLOPE_CAL + (path << 13), + B_P0_TSSI_SLOPE_CAL_EN, is_on); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d TSSI slpoe_k %s\n", path, + str_on_off(is_on)); +} + static void _dpk_tpg_sel(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) { struct rtw89_dpk_info *dpk = &rtwdev->dpk; @@ -1874,9 +1962,6 @@ static void _dpk_kip_control_rfc(struct rtw89_dev *rtwdev, { rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_IQK_RFC_ON, ctrl_by_kip); - - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] RFC is controlled by %s\n", - ctrl_by_kip ? "KIP" : "BB"); } static void _dpk_kip_preset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, @@ -2279,7 +2364,7 @@ static void _dpk_set_mdpd_para(struct rtw89_dev *rtwdev, u8 order) case 0: /* (5,3,1) */ rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, 0x0); rtw89_phy_write32_mask(rtwdev, R_DPK_IDL, B_DPK_IDL_SEL, 0x2); - rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x4); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x3); rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_DMAN, 0x1); break; case 1: /* (5,3,0) */ @@ -2315,8 +2400,6 @@ static void _dpk_set_mdpd_para(struct rtw89_dev *rtwdev, u8 order) static void _dpk_idl_mpa(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, enum rtw89_rf_path path, u8 kidx) { - rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_MA, 0x1); - if (rtw89_phy_read32_mask(rtwdev, R_IDL_MPA, B_IDL_MD500) == 0x1) _dpk_set_mdpd_para(rtwdev, 0x2); else if (rtw89_phy_read32_mask(rtwdev, R_IDL_MPA, B_IDL_MD530) == 0x1) @@ -2419,9 +2502,6 @@ static bool _dpk_main(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 init_xdbm = 17; bool is_fail; - if (dpk->bp[path][kidx].band != RTW89_BAND_2G) - init_xdbm = 15; - _dpk_kip_control_rfc(rtwdev, path, false); _rfk_rf_direct_cntrl(rtwdev, path, false); rtw89_write_rf(rtwdev, path, RR_BBDC, RFREG_MASK, 0x03ffd); @@ -2485,6 +2565,7 @@ static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, "[DPK] ========= S%d[%d] DPK Start =========\n", path, dpk->cur_idx[path]); + _dpk_tssi_slope_k_onoff(rtwdev, path, false); _dpk_rxagc_onoff(rtwdev, path, false); _rfk_drf_direct_cntrl(rtwdev, path, false); _dpk_bb_afe_setting(rtwdev, path); @@ -2502,7 +2583,7 @@ static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, _dpk_reload_rf(rtwdev, dpk_rf_reg, rf_bkup, path); _dpk_bb_afe_restore(rtwdev, path); _dpk_rxagc_onoff(rtwdev, path, true); - + _dpk_tssi_slope_k_onoff(rtwdev, path, true); if (rtwdev->is_tssi_mode[path]) _dpk_tssi_pause(rtwdev, path, false); } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c index 0abf7978ccab..38ce03331069 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c @@ -182,31 +182,6 @@ static const struct rtw89_reg5_def rtw8851b_iqk_macbb_defs[] = { RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_defs); -static const struct rtw89_reg5_def rtw8851b_iqk_bb_afe_defs[] = { - RTW89_DECL_RFK_WM(0x5670, 0x00004000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00008000, 0x1), - RTW89_DECL_RFK_WM(0x5670, 0x80000000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00007000, 0x7), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x3), - RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x9), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x1), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x0), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x3), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xa), - RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x0), - RTW89_DECL_RFK_WM(0xc0e8, 0x00000040, 0x1), - RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), - RTW89_DECL_RFK_WM(0x030c, MASKBYTE3, 0x1f), - RTW89_DECL_RFK_WM(0x030c, MASKBYTE3, 0x13), - RTW89_DECL_RFK_WM(0x032c, MASKHWORD, 0x0001), - RTW89_DECL_RFK_WM(0x032c, MASKHWORD, 0x0041), -}; - -RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_bb_afe_defs); - static const struct rtw89_reg5_def rtw8851b_tssi_sys_defs[] = { RTW89_DECL_RFK_WM(0x12bc, 0x000ffff0, 0xb5b5), RTW89_DECL_RFK_WM(0x32bc, 0x000ffff0, 0xb5b5), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h index febfbecb691c..4fd81456109b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h @@ -17,7 +17,6 @@ extern const struct rtw89_rfk_tbl rtw8851b_iqk_rxclk_others_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_2ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_5ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_afebb_restore_defs_tbl; -extern const struct rtw89_rfk_tbl rtw8851b_iqk_bb_afe_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_macbb_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_a_defs_2g_tbl; From 58f1510a8b6deb9872a23bc636b4859c08518f66 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 27 Jun 2025 11:53:38 +0800 Subject: [PATCH 07/58] wifi: rtw89: 8851b: rfk: update IQK to 0x14 Update IQK along with TX/RX clock to 960MHz and 1920MHz to improve performance. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250627035338.16637-1-pkshih@realtek.com --- .../net/wireless/realtek/rtw89/rtw8851b_rfk.c | 47 +++++++++++++++-- .../realtek/rtw89/rtw8851b_rfk_table.c | 52 ++++++++----------- .../realtek/rtw89/rtw8851b_rfk_table.h | 1 + 3 files changed, 66 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 907ce6d3c1b1..7a319a6c838a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -19,7 +19,7 @@ #define RTW8851B_RXK_GROUP_NR 4 #define RTW8851B_RXK_GROUP_IDX_NR 2 #define RTW8851B_TXK_GROUP_NR 1 -#define RTW8851B_IQK_VER 0x2a +#define RTW8851B_IQK_VER 0x14 #define RTW8851B_IQK_SS 1 #define RTW8851B_LOK_GRAM 10 #define RTW8851B_TSSI_PATH_NR 1 @@ -1107,10 +1107,43 @@ static void _iqk_rxclk_setting(struct rtw89_dev *rtwdev, u8 path) rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); - if (iqk_info->iqk_bw[path] == RTW89_CHANNEL_WIDTH_80) + if (iqk_info->iqk_bw[path] == RTW89_CHANNEL_WIDTH_80) { + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0101); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_DPD_GDIS, 0x1); + + _rxck_force(rtwdev, path, true, ADC_960M); + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_rxclk_80_defs_tbl); - else + } else { + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0101); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_DPD_GDIS, 0x1); + + _rxck_force(rtwdev, path, true, ADC_960M); + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_rxclk_others_defs_tbl); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, (2)before RXK IQK\n", path); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[07:10] = 0x%x\n", path, + 0xc0d4, rtw89_phy_read32_mask(rtwdev, 0xc0d4, GENMASK(10, 7))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[11:14] = 0x%x\n", path, + 0xc0d4, rtw89_phy_read32_mask(rtwdev, 0xc0d4, GENMASK(14, 11))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[26:27] = 0x%x\n", path, + 0xc0d4, rtw89_phy_read32_mask(rtwdev, 0xc0d4, GENMASK(27, 26))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[05:08] = 0x%x\n", path, + 0xc0d8, rtw89_phy_read32_mask(rtwdev, 0xc0d8, GENMASK(8, 5))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[17:21] = 0x%x\n", path, + 0xc0c4, rtw89_phy_read32_mask(rtwdev, 0xc0c4, GENMASK(21, 17))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[16:31] = 0x%x\n", path, + 0xc0e8, rtw89_phy_read32_mask(rtwdev, 0xc0e8, GENMASK(31, 16))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[04:05] = 0x%x\n", path, + 0xc0e4, rtw89_phy_read32_mask(rtwdev, 0xc0e4, GENMASK(5, 4))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[23:31] = 0x%x\n", path, + 0x12a0, rtw89_phy_read32_mask(rtwdev, 0x12a0, GENMASK(31, 23))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[13:14] = 0x%x\n", path, + 0xc0ec, rtw89_phy_read32_mask(rtwdev, 0xc0ec, GENMASK(14, 13))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[16:23] = 0x%x\n", path, + 0xc0ec, rtw89_phy_read32_mask(rtwdev, 0xc0ec, GENMASK(23, 16))); } static bool _txk_5g_group_sel(struct rtw89_dev *rtwdev, @@ -1616,6 +1649,14 @@ static void _iqk_macbb_setting(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_macbb_defs_tbl); + + _txck_force(rtwdev, path, true, DAC_960M); + + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_DPD_GDIS, 0x1); + + _rxck_force(rtwdev, path, true, ADC_1920M); + + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_macbb_bh_defs_tbl); } static void _iqk_init(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c index 38ce03331069..c5f70c045692 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c @@ -63,16 +63,7 @@ static const struct rtw89_reg5_def rtw8851b_dack_manual_off_defs[] = { RTW89_DECLARE_RFK_TBL(rtw8851b_dack_manual_off_defs); static const struct rtw89_reg5_def rtw8851b_iqk_rxclk_80_defs[] = { - RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x0101), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x2), RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x1), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x8), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x5), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xf), RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x0), RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x0f), @@ -85,16 +76,7 @@ static const struct rtw89_reg5_def rtw8851b_iqk_rxclk_80_defs[] = { RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_rxclk_80_defs); static const struct rtw89_reg5_def rtw8851b_iqk_rxclk_others_defs[] = { - RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x0101), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x2), RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x0), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x8), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x5), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xf), RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x2), RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x0f), @@ -157,30 +139,38 @@ static const struct rtw89_reg5_def rtw8851b_iqk_macbb_defs[] = { RTW89_DECL_RFK_WM(0x20fc, 0x10000000, 0x0), RTW89_DECL_RFK_WM(0x5670, MASKDWORD, 0xf801fffd), RTW89_DECL_RFK_WM(0x5670, 0x00004000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00008000, 0x1), RTW89_DECL_RFK_WM(0x5670, 0x80000000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00007000, 0x7), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x3), +}; + +RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_defs); + +static const struct rtw89_reg5_def rtw8851b_iqk_macbb_bh_defs[] = { RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x9), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x1), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x0), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x3), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xa), - RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x0), - RTW89_DECL_RFK_WM(0xc0e8, 0x00000040, 0x1), RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), + RTW89_DECL_RFK_DELAY(2), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x1f), + RTW89_DECL_RFK_DELAY(10), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x13), + RTW89_DECL_RFK_DELAY(2), RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0001), + RTW89_DECL_RFK_DELAY(2), RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0041), + RTW89_DECL_RFK_DELAY(10), + RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), + RTW89_DECL_RFK_DELAY(2), + RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x1f), + RTW89_DECL_RFK_DELAY(10), + RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x13), + RTW89_DECL_RFK_DELAY(2), + RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0001), + RTW89_DECL_RFK_DELAY(2), + RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0041), + RTW89_DECL_RFK_DELAY(10), RTW89_DECL_RFK_WM(0x20fc, 0x00100000, 0x1), RTW89_DECL_RFK_WM(0x20fc, 0x10000000, 0x1), }; -RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_defs); +RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_bh_defs); static const struct rtw89_reg5_def rtw8851b_tssi_sys_defs[] = { RTW89_DECL_RFK_WM(0x12bc, 0x000ffff0, 0xb5b5), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h index 4fd81456109b..3f1547f57505 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h @@ -18,6 +18,7 @@ extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_2ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_5ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_afebb_restore_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_macbb_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8851b_iqk_macbb_bh_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_a_defs_2g_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_a_defs_5g_tbl; From 4b6ea5a381979239758a1979cdf29f8d34201110 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:40:58 +0300 Subject: [PATCH 08/58] wifi: rtw89: 8851b: Accept USB devices and load their MAC address Make rtw8851b_read_efuse() accept USB devices and load the MAC address from the correct offset. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/6b2a1382-3be4-4038-8005-cf96922e4332@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 7801732d5b8b..11584ef6ef48 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -461,14 +461,6 @@ static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) return 0; } -static void rtw8851b_efuse_parsing(struct rtw89_efuse *efuse, - struct rtw8851b_efuse *map) -{ - ether_addr_copy(efuse->addr, map->e.mac_addr); - efuse->rfe_type = map->rfe_type; - efuse->xtal_cap = map->xtal_k; -} - static void rtw8851b_efuse_parsing_tssi(struct rtw89_dev *rtwdev, struct rtw8851b_efuse *map) { @@ -549,12 +541,18 @@ static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, switch (rtwdev->hci.type) { case RTW89_HCI_TYPE_PCIE: - rtw8851b_efuse_parsing(efuse, map); + ether_addr_copy(efuse->addr, map->e.mac_addr); + break; + case RTW89_HCI_TYPE_USB: + ether_addr_copy(efuse->addr, map->u.mac_addr); break; default: return -EOPNOTSUPP; } + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); return 0; From ee47816f24a1c07ea31f251546c75b42362d6cef Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:41:34 +0300 Subject: [PATCH 09/58] wifi: rtw89: Make dle_mem in rtw89_chip_info an array USB 2, USB 3, and SDIO will need different sets of values compared to PCIe. Add a new dle_type member in struct rtw89_hci_info and make dle_mem in struct rtw89_chip_info an array to hold the four different sets of values. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/c9152735-dbc4-4473-ae29-a79625cfbf78@gmail.com --- drivers/net/wireless/realtek/rtw89/core.h | 12 +++++++++++- drivers/net/wireless/realtek/rtw89/mac.c | 7 ++++--- drivers/net/wireless/realtek/rtw89/pci.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852bt.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 +- 9 files changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a72cd6e13de2..bf32b4eb41dd 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -132,6 +132,15 @@ enum rtw89_hci_type { RTW89_HCI_TYPE_SDIO, }; +enum rtw89_hci_dle_type { + RTW89_HCI_DLE_TYPE_PCIE, + RTW89_HCI_DLE_TYPE_USB2, + RTW89_HCI_DLE_TYPE_USB3, + RTW89_HCI_DLE_TYPE_SDIO, + + RTW89_HCI_DLE_TYPE_NUM, +}; + enum rtw89_core_chip_id { RTL8852A, RTL8852B, @@ -3660,6 +3669,7 @@ struct rtw89_hci_ops { struct rtw89_hci_info { const struct rtw89_hci_ops *ops; enum rtw89_hci_type type; + enum rtw89_hci_dle_type dle_type; u32 rpwm_addr; u32 cpwm_addr; bool paused; @@ -4359,7 +4369,7 @@ struct rtw89_chip_info { bool dis_2g_40m_ul_ofdma; u32 rsvd_ple_ofst; const struct rtw89_hfc_param_ini *hfc_param_ini; - const struct rtw89_dle_mem *dle_mem; + const struct rtw89_dle_mem *dle_mem[RTW89_HCI_DLE_TYPE_NUM]; u8 wde_qempty_acq_grpnum; u8 wde_qempty_mgq_grpsel; u32 rf_base_addr[2]; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 53628838a7c5..8e7ce45207da 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1717,12 +1717,13 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) { struct rtw89_mac_info *mac = &rtwdev->mac; - const struct rtw89_dle_mem *cfg; + const struct rtw89_dle_mem *cfg, *cfgs; - cfg = &rtwdev->chip->dle_mem[mode]; - if (!cfg) + cfgs = rtwdev->chip->dle_mem[rtwdev->hci.dle_type]; + if (!cfgs) return NULL; + cfg = &cfgs[mode]; if (cfg->mode != mode) { rtw89_warn(rtwdev, "qta mode unmatch!\n"); return NULL; diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 204a3748d913..597de632e364 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -4486,6 +4486,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) rtwdev->pci_info = info->bus.pci; rtwdev->hci.ops = &rtw89_pci_ops; rtwdev->hci.type = RTW89_HCI_TYPE_PCIE; + rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_PCIE; rtwdev->hci.rpwm_addr = pci_info->rpwm_addr; rtwdev->hci.cpwm_addr = pci_info->cpwm_addr; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 11584ef6ef48..daec656341af 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2509,7 +2509,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8851b_hfc_param_ini_pcie, - .dle_mem = rtw8851b_dle_mem_pcie, + .dle_mem = {rtw8851b_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 080636e8d0c3..8bf222bdb927 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2185,7 +2185,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852a_hfc_param_ini_pcie, - .dle_mem = rtw8852a_dle_mem_pcie, + .dle_mem = {rtw8852a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xc000, 0xd000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index c0bf80450acf..a6faae0d031a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -821,7 +821,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, - .dle_mem = rtw8852b_dle_mem_pcie, + .dle_mem = {rtw8852b_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 95e088734423..f536181bfb66 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -755,7 +755,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852bt_hfc_param_ini_pcie, - .dle_mem = rtw8852bt_dle_mem_pcie, + .dle_mem = {rtw8852bt_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 8f3d0c91a3f8..67db480940b3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -3005,7 +3005,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852c_hfc_param_ini_pcie, - .dle_mem = rtw8852c_dle_mem_pcie, + .dle_mem = {rtw8852c_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xe000, 0xf000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 603212ed4558..09dbe4008b89 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2860,7 +2860,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x8f800, .hfc_param_ini = rtw8922a_hfc_param_ini_pcie, - .dle_mem = rtw8922a_dle_mem_pcie, + .dle_mem = {rtw8922a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, From 82870ba25f32b8f38fb882ce1336789f11bae969 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:42:01 +0300 Subject: [PATCH 10/58] wifi: rtw89: Make hfc_param_ini in rtw89_chip_info an array USB and SDIO will need different sets of values, so make hfc_param_ini in struct rtw89_chip_info an array. Also make param_ini a pointer instead of copying the struct. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/1356f901-9ebf-451e-827f-50dd3efda534@gmail.com --- drivers/net/wireless/realtek/rtw89/core.h | 4 ++- drivers/net/wireless/realtek/rtw89/mac.c | 29 +++++++++---------- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 2 +- .../net/wireless/realtek/rtw89/rtw8852bt.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 +- 8 files changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index bf32b4eb41dd..3057ab3d2e7d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -130,6 +130,8 @@ enum rtw89_hci_type { RTW89_HCI_TYPE_PCIE, RTW89_HCI_TYPE_USB, RTW89_HCI_TYPE_SDIO, + + RTW89_HCI_TYPE_NUM, }; enum rtw89_hci_dle_type { @@ -4368,7 +4370,7 @@ struct rtw89_chip_info { u16 max_amsdu_limit; bool dis_2g_40m_ul_ofdma; u32 rsvd_ple_ofst; - const struct rtw89_hfc_param_ini *hfc_param_ini; + const struct rtw89_hfc_param_ini *hfc_param_ini[RTW89_HCI_TYPE_NUM]; const struct rtw89_dle_mem *dle_mem[RTW89_HCI_DLE_TYPE_NUM]; u8 wde_qempty_acq_grpnum; u8 wde_qempty_mgq_grpsel; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 8e7ce45207da..4432b03e8f7a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -875,31 +875,30 @@ EXPORT_SYMBOL(rtw89_mac_set_err_status); static int hfc_reset_param(struct rtw89_dev *rtwdev) { + const struct rtw89_hfc_param_ini *param_ini, *param_inis; struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; - struct rtw89_hfc_param_ini param_ini = {NULL}; u8 qta_mode = rtwdev->mac.dle_info.qta_mode; - switch (rtwdev->hci.type) { - case RTW89_HCI_TYPE_PCIE: - param_ini = rtwdev->chip->hfc_param_ini[qta_mode]; - param->en = 0; - break; - default: + param_inis = rtwdev->chip->hfc_param_ini[rtwdev->hci.type]; + if (!param_inis) return -EINVAL; - } - if (param_ini.pub_cfg) - param->pub_cfg = *param_ini.pub_cfg; + param_ini = ¶m_inis[qta_mode]; - if (param_ini.prec_cfg) - param->prec_cfg = *param_ini.prec_cfg; + param->en = 0; - if (param_ini.ch_cfg) - param->ch_cfg = param_ini.ch_cfg; + if (param_ini->pub_cfg) + param->pub_cfg = *param_ini->pub_cfg; + + if (param_ini->prec_cfg) + param->prec_cfg = *param_ini->prec_cfg; + + if (param_ini->ch_cfg) + param->ch_cfg = param_ini->ch_cfg; memset(¶m->ch_info, 0, sizeof(param->ch_info)); memset(¶m->pub_info, 0, sizeof(param->pub_info)); - param->mode = param_ini.mode; + param->mode = param_ini->mode; return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index daec656341af..b678edb00c03 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2508,7 +2508,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = rtw8851b_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8851b_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 8bf222bdb927..0496deb7278f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2184,7 +2184,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, - .hfc_param_ini = rtw8852a_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8852a_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8852a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index a6faae0d031a..b0b73a4a70a0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -820,7 +820,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .max_amsdu_limit = 5000, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8852b_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index f536181bfb66..10d09c12f318 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -754,7 +754,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .max_amsdu_limit = 5000, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, - .hfc_param_ini = rtw8852bt_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8852bt_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8852bt_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 67db480940b3..6e27f1ff94dc 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -3004,7 +3004,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .max_amsdu_limit = 8000, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x6f800, - .hfc_param_ini = rtw8852c_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8852c_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8852c_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 09dbe4008b89..e23655f3e4c1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2859,7 +2859,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .max_amsdu_limit = 8000, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x8f800, - .hfc_param_ini = rtw8922a_hfc_param_ini_pcie, + .hfc_param_ini = {rtw8922a_hfc_param_ini_pcie, NULL, NULL}, .dle_mem = {rtw8922a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, From 3c63450c872300546f2454e5972719dc725f8416 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:42:24 +0300 Subject: [PATCH 11/58] wifi: rtw89: Add rtw8851b_dle_mem_usb{2,3} Add rtw8851b_dle_mem_usb2 and rtw8851b_dle_mem_usb3 and their various quotas and sizes in struct rtw89_mac_size_set. "dle" could be "Data Link Engine" or "Double Link Engine". These are some parameters needed for RTL8851BU. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/91622304-614e-4e91-bf2f-7688cf44070b@gmail.com --- drivers/net/wireless/realtek/rtw89/mac.c | 15 +++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 8 +++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 31 ++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 4432b03e8f7a..4c469379be6e 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1645,6 +1645,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { /* 8852C PCIE SCC */ .wde_size19 = {RTW89_WDE_PG_64, 3328, 0,}, .wde_size23 = {RTW89_WDE_PG_64, 1022, 2,}, + /* 8852B USB2.0/USB3.0 SCC */ + .wde_size25 = {RTW89_WDE_PG_64, 162, 94,}, /* PCIE */ .ple_size0 = {RTW89_PLE_PG_128, 1520, 16,}, .ple_size0_v1 = {RTW89_PLE_PG_128, 2688, 240, 212992,}, @@ -1660,6 +1662,10 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_size18 = {RTW89_PLE_PG_128, 2544, 16,}, /* 8852C PCIE SCC */ .ple_size19 = {RTW89_PLE_PG_128, 1904, 16,}, + /* 8852B USB2.0 SCC */ + .ple_size32 = {RTW89_PLE_PG_128, 620, 20,}, + /* 8852B USB3.0 SCC */ + .ple_size33 = {RTW89_PLE_PG_128, 632, 8,}, /* PCIE 64 */ .wde_qt0 = {3792, 196, 0, 107,}, .wde_qt0_v1 = {3302, 6, 0, 20,}, @@ -1674,6 +1680,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { /* 8852C PCIE SCC */ .wde_qt18 = {3228, 60, 0, 40,}, .wde_qt23 = {958, 48, 0, 16,}, + /* 8852B USB2.0/USB3.0 SCC */ + .wde_qt25 = {152, 2, 0, 8,}, .ple_qt0 = {320, 320, 32, 16, 13, 13, 292, 292, 64, 18, 1, 4, 0,}, .ple_qt1 = {320, 320, 32, 16, 1316, 1316, 1595, 1595, 1367, 1321, 1, 1307, 0,}, /* PCIE SCC */ @@ -1697,6 +1705,13 @@ const struct rtw89_mac_size_set rtw89_mac_size = { /* PCIE 64 */ .ple_qt58 = {147, 0, 16, 20, 157, 13, 229, 0, 172, 14, 24, 0,}, .ple_qt59 = {147, 0, 32, 20, 1860, 13, 2025, 0, 1879, 14, 24, 0,}, + /* USB2.0 52B SCC */ + .ple_qt72 = {130, 0, 16, 48, 4, 13, 322, 0, 32, 14, 8, 0, 0,}, + /* USB2.0 52B 92K */ + .ple_qt73 = {130, 0, 32, 48, 37, 13, 355, 0, 65, 14, 24, 0, 0,}, + /* USB3.0 52B 92K */ + .ple_qt74 = {286, 0, 16, 48, 4, 13, 178, 0, 32, 14, 8, 0, 0,}, + .ple_qt75 = {286, 0, 32, 48, 37, 13, 211, 0, 65, 14, 24, 0, 0,}, /* 8852A PCIE WOW */ .ple_qt_52a_wow = {264, 0, 32, 20, 64, 13, 1005, 0, 64, 128, 120,}, /* 8852B PCIE WOW */ diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index b7fd4a0fdb84..9f596a06b3d0 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -924,6 +924,7 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size wde_size18; const struct rtw89_dle_size wde_size19; const struct rtw89_dle_size wde_size23; + const struct rtw89_dle_size wde_size25; const struct rtw89_dle_size ple_size0; const struct rtw89_dle_size ple_size0_v1; const struct rtw89_dle_size ple_size3_v1; @@ -933,6 +934,8 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size ple_size9; const struct rtw89_dle_size ple_size18; const struct rtw89_dle_size ple_size19; + const struct rtw89_dle_size ple_size32; + const struct rtw89_dle_size ple_size33; const struct rtw89_wde_quota wde_qt0; const struct rtw89_wde_quota wde_qt0_v1; const struct rtw89_wde_quota wde_qt4; @@ -941,6 +944,7 @@ struct rtw89_mac_size_set { const struct rtw89_wde_quota wde_qt17; const struct rtw89_wde_quota wde_qt18; const struct rtw89_wde_quota wde_qt23; + const struct rtw89_wde_quota wde_qt25; const struct rtw89_ple_quota ple_qt0; const struct rtw89_ple_quota ple_qt1; const struct rtw89_ple_quota ple_qt4; @@ -955,6 +959,10 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt57; const struct rtw89_ple_quota ple_qt58; const struct rtw89_ple_quota ple_qt59; + const struct rtw89_ple_quota ple_qt72; + const struct rtw89_ple_quota ple_qt73; + const struct rtw89_ple_quota ple_qt74; + const struct rtw89_ple_quota ple_qt75; const struct rtw89_ple_quota ple_qt_52a_wow; const struct rtw89_ple_quota ple_qt_52b_wow; const struct rtw89_ple_quota ple_qt_52bt_wow; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index b678edb00c03..5cdc42ee59a3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -68,6 +68,32 @@ static const struct rtw89_dle_mem rtw8851b_dle_mem_pcie[] = { NULL}, }; +static const struct rtw89_dle_mem rtw8851b_dle_mem_usb2[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25, + &rtw89_mac_size.ple_size32, &rtw89_mac_size.wde_qt25, + &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt72, + &rtw89_mac_size.ple_qt73}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + +static const struct rtw89_dle_mem rtw8851b_dle_mem_usb3[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25, + &rtw89_mac_size.ple_size33, &rtw89_mac_size.wde_qt25, + &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt74, + &rtw89_mac_size.ple_qt75}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + static const struct rtw89_reg3_def rtw8851b_btc_preagc_en_defs[] = { {0x46D0, GENMASK(1, 0), 0x3}, {0x4AD4, GENMASK(31, 0), 0xf}, @@ -2509,7 +2535,10 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, NULL, NULL}, - .dle_mem = {rtw8851b_dle_mem_pcie, NULL, NULL, NULL}, + .dle_mem = {rtw8851b_dle_mem_pcie, + rtw8851b_dle_mem_usb2, + rtw8851b_dle_mem_usb3, + NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000}, From 02a44c2630318b880d49000f151a6d1e450e76e2 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:42:55 +0300 Subject: [PATCH 12/58] wifi: rtw89: Add rtw8851b_hfc_param_ini_usb "hfc" means "hci fc" which is "Host Control Interface Flow Control". These are some parameters needed for RTL8851BU. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/a0dec631-de05-4302-9ef1-e730eb233f08@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 5cdc42ee59a3..ad41c8bf39fc 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -51,6 +51,48 @@ static const struct rtw89_hfc_param_ini rtw8851b_hfc_param_ini_pcie[] = { [RTW89_QTA_INVALID] = {NULL}, }; +static const struct rtw89_hfc_ch_cfg rtw8851b_hfc_chcfg_usb[] = { + {18, 152, grp_0}, /* ACH 0 */ + {18, 152, grp_0}, /* ACH 1 */ + {18, 152, grp_0}, /* ACH 2 */ + {18, 152, grp_0}, /* ACH 3 */ + {0, 0, grp_0}, /* ACH 4 */ + {0, 0, grp_0}, /* ACH 5 */ + {0, 0, grp_0}, /* ACH 6 */ + {0, 0, grp_0}, /* ACH 7 */ + {18, 152, grp_0}, /* B0MGQ */ + {18, 152, grp_0}, /* B0HIQ */ + {0, 0, grp_0}, /* B1MGQ */ + {0, 0, grp_0}, /* B1HIQ */ + {0, 0, 0} /* FWCMDQ */ +}; + +static const struct rtw89_hfc_pub_cfg rtw8851b_hfc_pubcfg_usb = { + 152, /* Group 0 */ + 0, /* Group 1 */ + 152, /* Public Max */ + 0 /* WP threshold */ +}; + +static const struct rtw89_hfc_prec_cfg rtw8851b_hfc_preccfg_usb = { + 9, /* CH 0-11 pre-cost */ + 32, /* H2C pre-cost */ + 64, /* WP CH 0-7 pre-cost */ + 24, /* WP CH 8-11 pre-cost */ + 1, /* CH 0-11 full condition */ + 1, /* H2C full condition */ + 1, /* WP CH 0-7 full condition */ + 1, /* WP CH 8-11 full condition */ +}; + +static const struct rtw89_hfc_param_ini rtw8851b_hfc_param_ini_usb[] = { + [RTW89_QTA_SCC] = {rtw8851b_hfc_chcfg_usb, &rtw8851b_hfc_pubcfg_usb, + &rtw8851b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_DLFW] = {NULL, NULL, + &rtw8851b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_INVALID] = {NULL}, +}; + static const struct rtw89_dle_mem rtw8851b_dle_mem_pcie[] = { [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size6, &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt6, @@ -2534,7 +2576,9 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, NULL, NULL}, + .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, + rtw8851b_hfc_param_ini_usb, + NULL}, .dle_mem = {rtw8851b_dle_mem_pcie, rtw8851b_dle_mem_usb2, rtw8851b_dle_mem_usb3, From a3b871a0f7c083c2a632a31da8bc3de554ae8550 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:43:25 +0300 Subject: [PATCH 13/58] wifi: rtw89: Disable deep power saving for USB/SDIO Disable deep power saving for USB and SDIO because rtw89_mac_send_rpwm() is called in atomic context and accessing hardware registers results in "scheduling while atomic" errors. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/0f49eceb-0de0-47e2-ba36-3c6a0dddd17d@gmail.com --- drivers/net/wireless/realtek/rtw89/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 1f5639a5d166..fe6b19a078c5 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2884,6 +2884,9 @@ static enum rtw89_ps_mode rtw89_update_ps_mode(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + if (rtwdev->hci.type != RTW89_HCI_TYPE_PCIE) + return RTW89_PS_MODE_NONE; + if (rtw89_disable_ps_mode || !chip->ps_mode_supported || RTW89_CHK_FW_FEATURE(NO_DEEP_PS, &rtwdev->fw)) return RTW89_PS_MODE_NONE; From ec542d5e4bf660463d8d578ecebb511cbfe66558 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:44:28 +0300 Subject: [PATCH 14/58] wifi: rtw89: Add extra TX headroom for USB In the case of USB the TX descriptor is transmitted in the same buffer as the 802.11 frame, so add the required headroom. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/91fb7579-60e5-4a06-8007-3312639beea6@gmail.com --- drivers/net/wireless/realtek/rtw89/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index fe6b19a078c5..776d2e5ce8a0 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -5591,6 +5591,9 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) int ret; int tx_headroom = IEEE80211_HT_CTL_LEN; + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + tx_headroom += chip->txwd_body_size + chip->txwd_info_size; + hw->vif_data_size = struct_size_t(struct rtw89_vif, links_inst, n); hw->sta_data_size = struct_size_t(struct rtw89_sta, links_inst, n); hw->txq_data_size = sizeof(struct rtw89_txq); From 0740c6beefae03066a562e3047959528d8893709 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:45:02 +0300 Subject: [PATCH 15/58] wifi: rtw89: Hide some errors when the device is unplugged A few unnecessary error messages are printed when the device is unplugged. "read swsi busy" in particular can appear ~1000 times when RTL8851BU is unplugged. Add a new flag RTW89_FLAG_UNPLUGGED and print some error messages only when this flag is not set. The new USB driver will set the flag when the device is unplugged. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/cc18b739-6f38-4c1a-a681-1e2a0d4ed60d@gmail.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 13 ++++++++----- drivers/net/wireless/realtek/rtw89/phy.c | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 3057ab3d2e7d..a08d07e44498 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4995,6 +4995,7 @@ enum rtw89_flags { RTW89_FLAG_FORBIDDEN_TRACK_WORK, RTW89_FLAG_CHANGING_INTERFACE, RTW89_FLAG_HW_RFKILL_STATE, + RTW89_FLAG_UNPLUGGED, NUM_OF_RTW89_FLAGS, }; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 4c469379be6e..877944cbb8da 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -88,7 +88,7 @@ int rtw89_mac_write_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 val) ret = read_poll_timeout(rtw89_read8, lte_ctrl, (lte_ctrl & BIT(5)) != 0, 50, 50000, false, rtwdev, R_AX_LTE_CTRL + 3); - if (ret) + if (ret && !test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) rtw89_err(rtwdev, "[ERR]lte not ready(W)\n"); rtw89_write32(rtwdev, R_AX_LTE_WDATA, val); @@ -104,7 +104,7 @@ int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val) ret = read_poll_timeout(rtw89_read8, lte_ctrl, (lte_ctrl & BIT(5)) != 0, 50, 50000, false, rtwdev, R_AX_LTE_CTRL + 3); - if (ret) + if (ret && !test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) rtw89_err(rtwdev, "[ERR]lte not ready(W)\n"); rtw89_write32(rtwdev, R_AX_LTE_CTRL, 0x800F0000 | offset); @@ -5922,13 +5922,15 @@ int rtw89_mac_coex_init(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex ret = rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_2, &val32); if (ret) { - rtw89_err(rtwdev, "Read R_AX_LTE_SW_CFG_2 fail!\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "Read R_AX_LTE_SW_CFG_2 fail!\n"); return ret; } val32 = val32 & B_AX_WL_RX_CTRL; ret = rtw89_mac_write_lte(rtwdev, R_AX_LTE_SW_CFG_2, val32); if (ret) { - rtw89_err(rtwdev, "Write R_AX_LTE_SW_CFG_2 fail!\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "Write R_AX_LTE_SW_CFG_2 fail!\n"); return ret; } @@ -6052,7 +6054,8 @@ int rtw89_mac_cfg_gnt(struct rtw89_dev *rtwdev, ret = rtw89_mac_write_lte(rtwdev, R_AX_LTE_SW_CFG_1, val); if (ret) { - rtw89_err(rtwdev, "Write LTE fail!\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "Write LTE fail!\n"); return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index f81bee4149bf..7d005db211e5 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -897,7 +897,8 @@ static u32 rtw89_phy_read_rf_a(struct rtw89_dev *rtwdev, 30, false, rtwdev, R_SWSI_V1, B_SWSI_R_DATA_DONE_V1); if (ret) { - rtw89_err(rtwdev, "read swsi busy\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "read swsi busy\n"); return INV_RF_DATA; } From e906a11753c96d553c4ace3201f57e08e21bfdba Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:45:32 +0300 Subject: [PATCH 16/58] wifi: rtw89: 8851b: Modify rtw8851b_pwr_{on,off}_func() for USB There are a few differences in the power on/off functions between PCIE and USB. While the RTL8851BU appears to work without these changes, it's probably best to implement them, in case they are needed in some situations. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/469f6882-1859-464d-8a84-9ef1b6c8ce3e@gmail.com --- drivers/net/wireless/realtek/rtw89/reg.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 90625d692b4d..196700f0e3b2 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -21,6 +21,7 @@ #define R_AX_SYS_PW_CTRL 0x0004 #define B_AX_SOP_ASWRM BIT(31) #define B_AX_SOP_PWMM_DSWR BIT(29) +#define B_AX_SOP_EDSWR BIT(28) #define B_AX_XTAL_OFF_A_DIE BIT(22) #define B_AX_DIS_WLBT_PDNSUSEN_SOPC BIT(18) #define B_AX_RDY_SYSPWR BIT(17) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index ad41c8bf39fc..96edaf8e9ec4 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -385,7 +385,8 @@ static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); - rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_OFF_WEI, XTAL_SI_OFF_WEI); @@ -430,8 +431,9 @@ static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write32_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14); rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); - rtw89_write32_set(rtwdev, R_AX_GPIO0_16_EECS_EESK_LED1_PULL_LOW_EN, - B_AX_GPIO10_PULL_LOW_EN | B_AX_GPIO16_PULL_LOW_EN_V1); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32_set(rtwdev, R_AX_GPIO0_16_EECS_EESK_LED1_PULL_LOW_EN, + B_AX_GPIO10_PULL_LOW_EN | B_AX_GPIO16_PULL_LOW_EN_V1); if (rtwdev->hal.cv == CHIP_CAV) { ret = rtw89_read_efuse_ver(rtwdev, &val8); @@ -515,7 +517,10 @@ static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) if (ret) return ret; - rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_EDSWR); if (rtwdev->hal.cv == CHIP_CAV) { rtw8851b_patch_swr_pfm2pwm(rtwdev); @@ -524,7 +529,14 @@ static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_AX_SPSANA_ON_CTRL1, B_AX_FPWMDELAY); } - rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + } else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) { + val32 = rtw89_read32(rtwdev, R_AX_SYS_PW_CTRL); + val32 &= ~B_AX_AFSM_PCIE_SUS_EN; + val32 |= B_AX_AFSM_WLSUS_EN; + rtw89_write32(rtwdev, R_AX_SYS_PW_CTRL, val32); + } return 0; } From e2b71603333a9dd73ee88347d8894fffc3456ac1 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:45:55 +0300 Subject: [PATCH 17/58] wifi: rtw89: Fix rtw89_mac_power_switch() for USB Clear some bits in some registers in order to allow RTL8851BU to power on. This is done both when powering on and when powering off because that's what the vendor driver does. Also tested with RTL8832BU and RTL8832CU. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/a39da939-d640-4486-ad38-f658f220afc8@gmail.com --- drivers/net/wireless/realtek/rtw89/mac.c | 19 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 877944cbb8da..ff4335ef4033 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1440,6 +1440,23 @@ void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev) rtw89_mac_send_rpwm(rtwdev, state, true); } +static void rtw89_mac_power_switch_boot_mode(struct rtw89_dev *rtwdev) +{ + u32 boot_mode; + + if (rtwdev->hci.type != RTW89_HCI_TYPE_USB) + return; + + boot_mode = rtw89_read32_mask(rtwdev, R_AX_GPIO_MUXCFG, B_AX_BOOT_MODE); + if (!boot_mode) + return; + + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFN_ONMAC); + rtw89_write32_clr(rtwdev, R_AX_SYS_STATUS1, B_AX_AUTO_WLPON); + rtw89_write32_clr(rtwdev, R_AX_GPIO_MUXCFG, B_AX_BOOT_MODE); + rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); +} + static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) { #define PWR_ACT 1 @@ -1450,6 +1467,8 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) int ret; u8 val; + rtw89_mac_power_switch_boot_mode(rtwdev); + if (on) { cfg_seq = chip->pwr_on_seq; cfg_func = chip->ops->pwr_on_func; diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 196700f0e3b2..74b964e02159 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -183,6 +183,7 @@ #define R_AX_SYS_STATUS1 0x00F4 #define B_AX_SEL_0XC0_MASK GENMASK(17, 16) +#define B_AX_AUTO_WLPON BIT(10) #define B_AX_PAD_HCI_SEL_V2_MASK GENMASK(5, 3) #define MAC_AX_HCI_SEL_SDIO_UART 0 #define MAC_AX_HCI_SEL_MULTI_USB 1 From ed88640ea1ac441d5cda98f7c478fcdf34263fa7 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:46:32 +0300 Subject: [PATCH 18/58] wifi: rtw89: Add some definitions for USB Add various register and bit definitions which will be used by the new USB driver. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/5812bb0c-20d0-48df-916d-25225eee8132@gmail.com --- drivers/net/wireless/realtek/rtw89/reg.h | 29 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/txrx.h | 1 + 2 files changed, 30 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 74b964e02159..de81103a072f 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -382,6 +382,18 @@ #define B_AX_ACH1_BUSY BIT(9) #define B_AX_ACH0_BUSY BIT(8) +#define R_AX_USB_ENDPOINT_0 0x1060 +#define B_AX_EP_IDX GENMASK(3, 0) +#define R_AX_USB_ENDPOINT_2 0x1068 +#define NUMP 0x1 +#define R_AX_USB_HOST_REQUEST_2 0x1078 +#define B_AX_R_USBIO_MODE BIT(4) +#define R_AX_USB3_MAC_NPI_CONFIG_INTF_0 0x1114 +#define B_AX_SSPHY_LFPS_FILTER BIT(31) +#define R_AX_USB_WLAN0_1 0x1174 +#define B_AX_USBRX_RST BIT(9) +#define B_AX_USBTX_RST BIT(8) + #define R_AX_PCIE_DBG_CTRL 0x11C0 #define B_AX_DBG_DUMMY_MASK GENMASK(23, 16) #define B_AX_PCIE_DBG_SEL_MASK GENMASK(15, 13) @@ -461,6 +473,17 @@ #define R_AX_WP_PAGE_CTRL2_V1 0x17A4 #define R_AX_WP_PAGE_INFO1_V1 0x17A8 +#define R_AX_USB_ENDPOINT_0_V1 0x5060 +#define B_AX_EP_IDX_V1 GENMASK(3, 0) +#define R_AX_USB_ENDPOINT_2_V1 0x5068 +#define R_AX_USB_HOST_REQUEST_2_V1 0x5078 +#define B_AX_R_USBIO_MODE_V1 BIT(4) +#define R_AX_USB3_MAC_NPI_CONFIG_INTF_0_V1 0x5114 +#define B_AX_SSPHY_LFPS_FILTER_V1 BIT(31) +#define R_AX_USB_WLAN0_1_V1 0x5174 +#define B_AX_USBRX_RST_V1 BIT(9) +#define B_AX_USBTX_RST_V1 BIT(8) + #define R_AX_H2CREG_DATA0_V1 0x7140 #define R_AX_H2CREG_DATA1_V1 0x7144 #define R_AX_H2CREG_DATA2_V1 0x7148 @@ -1027,6 +1050,12 @@ #define B_AX_DISPATCHER_INTN_SEL_MASK GENMASK(7, 4) #define B_AX_DISPATCHER_CH_SEL_MASK GENMASK(3, 0) +#define R_AX_RXDMA_SETTING 0x8908 +#define B_AX_BULK_SIZE GENMASK(1, 0) +#define USB11_BULKSIZE 0x2 +#define USB2_BULKSIZE 0x1 +#define USB3_BULKSIZE 0x0 + #define R_AX_RX_FUNCTION_STOP 0x8920 #define B_AX_HDR_RX_STOP BIT(0) diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 94f27a9ee9f7..ec01bfc363da 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -73,6 +73,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define RTW89_TXWD_BODY0_FW_DL BIT(20) #define RTW89_TXWD_BODY0_CHANNEL_DMA GENMASK(19, 16) #define RTW89_TXWD_BODY0_HDR_LLC_LEN GENMASK(15, 11) +#define RTW89_TXWD_BODY0_STF_MODE BIT(10) #define RTW89_TXWD_BODY0_WD_PAGE BIT(7) #define RTW89_TXWD_BODY0_HW_AMSDU BIT(5) #define RTW89_TXWD_BODY0_HW_SSN_SEL GENMASK(3, 2) From 2135c28be6a84313580a974f7d6890830b83107e Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:46:55 +0300 Subject: [PATCH 19/58] wifi: rtw89: Add usb.{c,h} Add basic USB support. No TX/RX aggregation, no switching to USB 3 mode. RTL8851BU and RTL8832BU work. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/f9ad1664-2d63-4a8f-88bf-c7b7bececbfe@gmail.com --- drivers/net/wireless/realtek/rtw89/usb.c | 1042 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/usb.h | 65 ++ 2 files changed, 1107 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/usb.c create mode 100644 drivers/net/wireless/realtek/rtw89/usb.h diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c new file mode 100644 index 000000000000..6cf89aee252e --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/usb.c @@ -0,0 +1,1042 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2025 Realtek Corporation + */ + +#include +#include "debug.h" +#include "mac.h" +#include "reg.h" +#include "txrx.h" +#include "usb.h" + +static void rtw89_usb_read_port_complete(struct urb *urb); + +static void rtw89_usb_vendorreq(struct rtw89_dev *rtwdev, u32 addr, + void *data, u16 len, u8 reqtype) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct usb_device *udev = rtwusb->udev; + unsigned int pipe; + u16 value, index; + int attempt, ret; + + if (test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + return; + + value = u32_get_bits(addr, GENMASK(15, 0)); + index = u32_get_bits(addr, GENMASK(23, 16)); + + for (attempt = 0; attempt < 10; attempt++) { + *rtwusb->vendor_req_buf = 0; + + if (reqtype == RTW89_USB_VENQT_READ) { + pipe = usb_rcvctrlpipe(udev, 0); + } else { /* RTW89_USB_VENQT_WRITE */ + pipe = usb_sndctrlpipe(udev, 0); + + memcpy(rtwusb->vendor_req_buf, data, len); + } + + ret = usb_control_msg(udev, pipe, RTW89_USB_VENQT, reqtype, + value, index, rtwusb->vendor_req_buf, + len, 500); + + if (ret == len) { /* Success */ + atomic_set(&rtwusb->continual_io_error, 0); + + if (reqtype == RTW89_USB_VENQT_READ) + memcpy(data, rtwusb->vendor_req_buf, len); + + break; + } + + if (ret == -ESHUTDOWN || ret == -ENODEV) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + else if (ret < 0) + rtw89_warn(rtwdev, + "usb %s%u 0x%x fail ret=%d value=0x%x attempt=%d\n", + reqtype == RTW89_USB_VENQT_READ ? "read" : "write", + len * 8, addr, ret, + le32_to_cpup(rtwusb->vendor_req_buf), + attempt); + else if (ret > 0 && reqtype == RTW89_USB_VENQT_READ) + memcpy(data, rtwusb->vendor_req_buf, len); + + if (atomic_inc_return(&rtwusb->continual_io_error) > 4) { + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + break; + } + } +} + +static u32 rtw89_usb_read_cmac(struct rtw89_dev *rtwdev, u32 addr) +{ + u32 addr32, val32, shift; + __le32 data = 0; + int count; + + addr32 = addr & ~0x3; + shift = (addr & 0x3) * 8; + + for (count = 0; ; count++) { + rtw89_usb_vendorreq(rtwdev, addr32, &data, 4, + RTW89_USB_VENQT_READ); + + val32 = le32_to_cpu(data); + if (val32 != RTW89_R32_DEAD) + break; + + if (count >= MAC_REG_POOL_COUNT) { + rtw89_warn(rtwdev, "%s: addr %#x = %#x\n", + __func__, addr32, val32); + val32 = RTW89_R32_DEAD; + break; + } + + rtw89_write32(rtwdev, R_AX_CK_EN, B_AX_CMAC_ALLCKEN); + } + + return val32 >> shift; +} + +static u8 rtw89_usb_ops_read8(struct rtw89_dev *rtwdev, u32 addr) +{ + u8 data = 0; + + if (ACCESS_CMAC(addr)) + return rtw89_usb_read_cmac(rtwdev, addr); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 1, RTW89_USB_VENQT_READ); + + return data; +} + +static u16 rtw89_usb_ops_read16(struct rtw89_dev *rtwdev, u32 addr) +{ + __le16 data = 0; + + if (ACCESS_CMAC(addr)) + return rtw89_usb_read_cmac(rtwdev, addr); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 2, RTW89_USB_VENQT_READ); + + return le16_to_cpu(data); +} + +static u32 rtw89_usb_ops_read32(struct rtw89_dev *rtwdev, u32 addr) +{ + __le32 data = 0; + + if (ACCESS_CMAC(addr)) + return rtw89_usb_read_cmac(rtwdev, addr); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 4, + RTW89_USB_VENQT_READ); + + return le32_to_cpu(data); +} + +static void rtw89_usb_ops_write8(struct rtw89_dev *rtwdev, u32 addr, u8 val) +{ + u8 data = val; + + rtw89_usb_vendorreq(rtwdev, addr, &data, 1, RTW89_USB_VENQT_WRITE); +} + +static void rtw89_usb_ops_write16(struct rtw89_dev *rtwdev, u32 addr, u16 val) +{ + __le16 data = cpu_to_le16(val); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 2, RTW89_USB_VENQT_WRITE); +} + +static void rtw89_usb_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 val) +{ + __le32 data = cpu_to_le32(val); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 4, RTW89_USB_VENQT_WRITE); +} + +static u32 +rtw89_usb_ops_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, + u8 txch) +{ + if (txch == RTW89_TXCH_CH12) + return 1; + + return 42; /* TODO some kind of calculation? */ +} + +static u8 rtw89_usb_get_bulkout_id(u8 ch_dma) +{ + switch (ch_dma) { + case RTW89_DMA_ACH0: + return 3; + case RTW89_DMA_ACH1: + return 4; + case RTW89_DMA_ACH2: + return 5; + case RTW89_DMA_ACH3: + return 6; + default: + case RTW89_DMA_B0MG: + return 0; + case RTW89_DMA_B0HI: + return 1; + case RTW89_DMA_H2C: + return 2; + } +} + +static void rtw89_usb_write_port_complete(struct urb *urb) +{ + struct rtw89_usb_tx_ctrl_block *txcb = urb->context; + struct rtw89_dev *rtwdev = txcb->rtwdev; + struct ieee80211_tx_info *info; + struct rtw89_txwd_body *txdesc; + struct sk_buff *skb; + u32 txdesc_size; + + while (true) { + skb = skb_dequeue(&txcb->tx_ack_queue); + if (!skb) + break; + + if (txcb->txch == RTW89_TXCH_CH12) { + dev_kfree_skb_any(skb); + continue; + } + + txdesc = (struct rtw89_txwd_body *)skb->data; + + txdesc_size = rtwdev->chip->txwd_body_size; + if (le32_get_bits(txdesc->dword0, RTW89_TXWD_BODY0_WD_INFO_EN)) + txdesc_size += rtwdev->chip->txwd_info_size; + + skb_pull(skb, txdesc_size); + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + + if (urb->status == 0) { + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + info->flags |= IEEE80211_TX_STAT_ACK; + } + + ieee80211_tx_status_irqsafe(rtwdev->hw, skb); + } + + switch (urb->status) { + case 0: + case -EPIPE: + case -EPROTO: + case -EINPROGRESS: + case -ENOENT: + case -ECONNRESET: + break; + default: + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + break; + } + + kfree(txcb); + usb_free_urb(urb); +} + +static int rtw89_usb_write_port(struct rtw89_dev *rtwdev, u8 ch_dma, + void *data, int len, void *context) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct usb_device *usbd = rtwusb->udev; + struct urb *urb; + u8 bulkout_id = rtw89_usb_get_bulkout_id(ch_dma); + unsigned int pipe; + int ret; + + if (test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + return 0; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + return -ENOMEM; + + pipe = usb_sndbulkpipe(usbd, rtwusb->out_pipe[bulkout_id]); + + usb_fill_bulk_urb(urb, usbd, pipe, data, len, + rtw89_usb_write_port_complete, context); + urb->transfer_flags |= URB_ZERO_PACKET; + ret = usb_submit_urb(urb, GFP_ATOMIC); + + if (ret) + usb_free_urb(urb); + + if (ret == -ENODEV) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + + return ret; +} + +static void rtw89_usb_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct rtw89_usb_tx_ctrl_block *txcb; + struct sk_buff *skb; + int ret; + + while (true) { + skb = skb_dequeue(&rtwusb->tx_queue[txch]); + if (!skb) + break; + + txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC); + if (!txcb) { + dev_kfree_skb_any(skb); + continue; + } + + txcb->rtwdev = rtwdev; + txcb->txch = txch; + skb_queue_head_init(&txcb->tx_ack_queue); + + skb_queue_tail(&txcb->tx_ack_queue, skb); + + ret = rtw89_usb_write_port(rtwdev, txch, skb->data, skb->len, + txcb); + if (ret) { + rtw89_err(rtwdev, "write port txch %d failed: %d\n", + txch, ret); + + skb_dequeue(&txcb->tx_ack_queue); + kfree(txcb); + dev_kfree_skb_any(skb); + } + } +} + +static int rtw89_usb_tx_write_fwcmd(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req) +{ + struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *skb = tx_req->skb; + struct sk_buff *skb512; + u32 txdesc_size = rtwdev->chip->h2c_desc_size; + void *txdesc; + + if (((desc_info->pkt_size + txdesc_size) % 512) == 0) { + rtw89_debug(rtwdev, RTW89_DBG_HCI, "avoiding multiple of 512\n"); + + skb512 = dev_alloc_skb(txdesc_size + desc_info->pkt_size + + RTW89_USB_MOD512_PADDING); + if (!skb512) { + rtw89_err(rtwdev, "%s: failed to allocate skb\n", + __func__); + + return -ENOMEM; + } + + skb_pull(skb512, txdesc_size); + skb_put_data(skb512, skb->data, skb->len); + skb_put_zero(skb512, RTW89_USB_MOD512_PADDING); + + dev_kfree_skb_any(skb); + skb = skb512; + tx_req->skb = skb512; + + desc_info->pkt_size += RTW89_USB_MOD512_PADDING; + } + + txdesc = skb_push(skb, txdesc_size); + memset(txdesc, 0, txdesc_size); + rtw89_chip_fill_txdesc_fwcmd(rtwdev, desc_info, txdesc); + + skb_queue_tail(&rtwusb->tx_queue[desc_info->ch_dma], skb); + + return 0; +} + +static int rtw89_usb_ops_tx_write(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req) +{ + struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *skb = tx_req->skb; + struct rtw89_txwd_body *txdesc; + u32 txdesc_size; + + if ((desc_info->ch_dma == RTW89_TXCH_CH12 || + tx_req->tx_type == RTW89_CORE_TX_TYPE_FWCMD) && + (desc_info->ch_dma != RTW89_TXCH_CH12 || + tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD)) { + rtw89_err(rtwdev, "dma channel %d/TX type %d mismatch\n", + desc_info->ch_dma, tx_req->tx_type); + return -EINVAL; + } + + if (desc_info->ch_dma == RTW89_TXCH_CH12) + return rtw89_usb_tx_write_fwcmd(rtwdev, tx_req); + + txdesc_size = rtwdev->chip->txwd_body_size; + if (desc_info->en_wd_info) + txdesc_size += rtwdev->chip->txwd_info_size; + + txdesc = skb_push(skb, txdesc_size); + memset(txdesc, 0, txdesc_size); + rtw89_chip_fill_txdesc(rtwdev, desc_info, txdesc); + + le32p_replace_bits(&txdesc->dword0, 1, RTW89_TXWD_BODY0_STF_MODE); + + skb_queue_tail(&rtwusb->tx_queue[desc_info->ch_dma], skb); + + return 0; +} + +static void rtw89_usb_rx_handler(struct work_struct *work) +{ + struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_work); + struct rtw89_dev *rtwdev = rtwusb->rtwdev; + struct rtw89_rx_desc_info desc_info; + struct sk_buff *rx_skb; + struct sk_buff *skb; + u32 pkt_offset; + int limit; + + for (limit = 0; limit < 200; limit++) { + rx_skb = skb_dequeue(&rtwusb->rx_queue); + if (!rx_skb) + break; + + if (skb_queue_len(&rtwusb->rx_queue) >= RTW89_USB_MAX_RXQ_LEN) { + rtw89_warn(rtwdev, "rx_queue overflow\n"); + dev_kfree_skb_any(rx_skb); + continue; + } + + memset(&desc_info, 0, sizeof(desc_info)); + rtw89_chip_query_rxdesc(rtwdev, &desc_info, rx_skb->data, 0); + + 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); + continue; + } + + pkt_offset = desc_info.offset + desc_info.rxd_len; + + skb_put_data(skb, rx_skb->data + pkt_offset, + desc_info.pkt_size); + + rtw89_core_rx(rtwdev, &desc_info, skb); + + if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW89_USB_RX_SKB_NUM) + dev_kfree_skb_any(rx_skb); + else + skb_queue_tail(&rtwusb->rx_free_queue, rx_skb); + } + + if (limit == 200) { + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "left %d rx skbs in the queue for later\n", + skb_queue_len(&rtwusb->rx_queue)); + queue_work(rtwusb->rxwq, &rtwusb->rx_work); + } +} + +static void rtw89_usb_rx_resubmit(struct rtw89_usb *rtwusb, + struct rtw89_usb_rx_ctrl_block *rxcb, + gfp_t gfp) +{ + struct rtw89_dev *rtwdev = rtwusb->rtwdev; + struct sk_buff *rx_skb; + int ret; + + rx_skb = skb_dequeue(&rtwusb->rx_free_queue); + if (!rx_skb) + rx_skb = alloc_skb(RTW89_USB_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->in_pipe), + rxcb->rx_skb->data, RTW89_USB_RECVBUF_SZ, + rtw89_usb_read_port_complete, rxcb); + + ret = usb_submit_urb(rxcb->rx_urb, gfp); + if (ret) { + skb_queue_tail(&rtwusb->rx_free_queue, rxcb->rx_skb); + + if (ret == -ENODEV) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + else + rtw89_err(rtwdev, "Err sending rx data urb %d\n", ret); + + if (ret == -ENOMEM) + goto try_later; + } + + return; + +try_later: + rxcb->rx_skb = NULL; + queue_work(rtwusb->rxwq, &rtwusb->rx_urb_work); +} + +static void rtw89_usb_rx_resubmit_work(struct work_struct *work) +{ + struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_urb_work); + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + + if (!rxcb->rx_skb) + rtw89_usb_rx_resubmit(rtwusb, rxcb, GFP_ATOMIC); + } +} + +static void rtw89_usb_read_port_complete(struct urb *urb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb = urb->context; + struct rtw89_dev *rtwdev = rxcb->rtwdev; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *skb = rxcb->rx_skb; + + if (urb->status == 0) { + if (urb->actual_length > urb->transfer_buffer_length || + urb->actual_length < sizeof(struct rtw89_rxdesc_short)) { + rtw89_err(rtwdev, "failed to get urb length: %d\n", + urb->actual_length); + 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); + } + + rtw89_usb_rx_resubmit(rtwusb, rxcb, GFP_ATOMIC); + } else { + skb_queue_tail(&rtwusb->rx_free_queue, skb); + + if (atomic_inc_return(&rtwusb->continual_io_error) > 4) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + + switch (urb->status) { + case -EINVAL: + case -EPIPE: + case -ENODEV: + case -ESHUTDOWN: + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + break; + case -EPROTO: + case -EILSEQ: + case -ETIME: + case -ECOMM: + case -EOVERFLOW: + case -ENOENT: + break; + case -EINPROGRESS: + rtw89_info(rtwdev, "URB is in progress\n"); + break; + default: + rtw89_err(rtwdev, "%s status %d\n", + __func__, urb->status); + break; + } + } +} + +static void rtw89_usb_cancel_rx_bufs(struct rtw89_usb *rtwusb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + usb_kill_urb(rxcb->rx_urb); + } +} + +static void rtw89_usb_free_rx_bufs(struct rtw89_usb *rtwusb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + usb_free_urb(rxcb->rx_urb); + } +} + +static int rtw89_usb_alloc_rx_bufs(struct rtw89_usb *rtwusb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + + rxcb->rtwdev = rtwusb->rtwdev; + rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rxcb->rx_urb) { + rtw89_usb_free_rx_bufs(rtwusb); + return -ENOMEM; + } + } + + return 0; +} + +static int rtw89_usb_init_rx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *rx_skb; + int i; + + rtwusb->rxwq = alloc_workqueue("rtw89_usb: rx wq", WQ_BH, 0); + if (!rtwusb->rxwq) { + rtw89_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, rtw89_usb_rx_handler); + INIT_WORK(&rtwusb->rx_urb_work, rtw89_usb_rx_resubmit_work); + + for (i = 0; i < RTW89_USB_RX_SKB_NUM; i++) { + rx_skb = alloc_skb(RTW89_USB_RECVBUF_SZ, GFP_KERNEL); + if (rx_skb) + skb_queue_tail(&rtwusb->rx_free_queue, rx_skb); + } + + return 0; +} + +static void rtw89_usb_deinit_rx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + + skb_queue_purge(&rtwusb->rx_queue); + + destroy_workqueue(rtwusb->rxwq); + + skb_queue_purge(&rtwusb->rx_free_queue); +} + +static void rtw89_usb_start_rx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) + rtw89_usb_rx_resubmit(rtwusb, &rtwusb->rx_cb[i], GFP_KERNEL); +} + +static void rtw89_usb_init_tx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int i; + + for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) + skb_queue_head_init(&rtwusb->tx_queue[i]); +} + +static void rtw89_usb_deinit_tx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int i; + + for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) { + if (i == RTW89_TXCH_CH12) + skb_queue_purge(&rtwusb->tx_queue[i]); + else + ieee80211_purge_tx_queue(rtwdev->hw, &rtwusb->tx_queue[i]); + } +} + +static void rtw89_usb_ops_reset(struct rtw89_dev *rtwdev) +{ + /* TODO: anything to do here? */ +} + +static int rtw89_usb_ops_start(struct rtw89_dev *rtwdev) +{ + return 0; /* Nothing to do. */ +} + +static void rtw89_usb_ops_stop(struct rtw89_dev *rtwdev) +{ + /* Nothing to do. */ +} + +static void rtw89_usb_ops_pause(struct rtw89_dev *rtwdev, bool pause) +{ + /* Nothing to do? */ +} + +static void rtw89_usb_ops_switch_mode(struct rtw89_dev *rtwdev, bool low_power) +{ + /* Nothing to do. */ +} + +static int rtw89_usb_ops_deinit(struct rtw89_dev *rtwdev) +{ + return 0; /* Nothing to do. */ +} + +static int rtw89_usb_ops_mac_pre_init(struct rtw89_dev *rtwdev) +{ + u32 val32; + + rtw89_write32_set(rtwdev, R_AX_USB_HOST_REQUEST_2, B_AX_R_USBIO_MODE); + + /* fix USB IO hang suggest by chihhanli@realtek.com */ + rtw89_write32_clr(rtwdev, R_AX_USB_WLAN0_1, + B_AX_USBRX_RST | B_AX_USBTX_RST); + + val32 = rtw89_read32(rtwdev, R_AX_HCI_FUNC_EN); + val32 &= ~(B_AX_HCI_RXDMA_EN | B_AX_HCI_TXDMA_EN); + rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val32); + + val32 |= B_AX_HCI_RXDMA_EN | B_AX_HCI_TXDMA_EN; + rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val32); + /* fix USB TRX hang suggest by chihhanli@realtek.com */ + + return 0; +} + +static int rtw89_usb_ops_mac_pre_deinit(struct rtw89_dev *rtwdev) +{ + return 0; /* Nothing to do. */ +} + +static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + enum usb_device_speed speed; + u32 ep; + + rtw89_write32_clr(rtwdev, R_AX_USB3_MAC_NPI_CONFIG_INTF_0, + B_AX_SSPHY_LFPS_FILTER); + + speed = rtwusb->udev->speed; + + if (speed == USB_SPEED_SUPER) + rtw89_write8(rtwdev, R_AX_RXDMA_SETTING, USB3_BULKSIZE); + else if (speed == USB_SPEED_HIGH) + rtw89_write8(rtwdev, R_AX_RXDMA_SETTING, USB2_BULKSIZE); + else + rtw89_write8(rtwdev, R_AX_RXDMA_SETTING, USB11_BULKSIZE); + + for (ep = 5; ep <= 12; ep++) { + if (ep == 8) + continue; + + rtw89_write8_mask(rtwdev, R_AX_USB_ENDPOINT_0, + B_AX_EP_IDX, ep); + rtw89_write8(rtwdev, R_AX_USB_ENDPOINT_2 + 1, NUMP); + } + + return 0; +} + +static void rtw89_usb_ops_recalc_int_mit(struct rtw89_dev *rtwdev) +{ + /* Nothing to do. */ +} + +static int rtw89_usb_ops_mac_lv1_rcvy(struct rtw89_dev *rtwdev, + enum rtw89_lv1_rcvy_step step) +{ + u32 reg, mask; + + switch (rtwdev->chip->chip_id) { + case RTL8851B: + case RTL8852A: + case RTL8852B: + reg = R_AX_USB_WLAN0_1; + mask = B_AX_USBRX_RST | B_AX_USBTX_RST; + break; + case RTL8852C: + reg = R_AX_USB_WLAN0_1_V1; + mask = B_AX_USBRX_RST_V1 | B_AX_USBTX_RST_V1; + break; + default: + rtw89_err(rtwdev, "%s: fix me\n", __func__); + return -EOPNOTSUPP; + } + + switch (step) { + case RTW89_LV1_RCVY_STEP_1: + rtw89_write32_set(rtwdev, reg, mask); + + msleep(30); + break; + case RTW89_LV1_RCVY_STEP_2: + rtw89_write32_clr(rtwdev, reg, mask); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void rtw89_usb_ops_dump_err_status(struct rtw89_dev *rtwdev) +{ + rtw89_warn(rtwdev, "%s TODO\n", __func__); +} + +static const struct rtw89_hci_ops rtw89_usb_ops = { + .tx_write = rtw89_usb_ops_tx_write, + .tx_kick_off = rtw89_usb_ops_tx_kick_off, + .flush_queues = NULL, /* Not needed? */ + .reset = rtw89_usb_ops_reset, + .start = rtw89_usb_ops_start, + .stop = rtw89_usb_ops_stop, + .pause = rtw89_usb_ops_pause, + .switch_mode = rtw89_usb_ops_switch_mode, + .recalc_int_mit = rtw89_usb_ops_recalc_int_mit, + + .read8 = rtw89_usb_ops_read8, + .read16 = rtw89_usb_ops_read16, + .read32 = rtw89_usb_ops_read32, + .write8 = rtw89_usb_ops_write8, + .write16 = rtw89_usb_ops_write16, + .write32 = rtw89_usb_ops_write32, + + .mac_pre_init = rtw89_usb_ops_mac_pre_init, + .mac_pre_deinit = rtw89_usb_ops_mac_pre_deinit, + .mac_post_init = rtw89_usb_ops_mac_post_init, + .deinit = rtw89_usb_ops_deinit, + + .check_and_reclaim_tx_resource = rtw89_usb_ops_check_and_reclaim_tx_resource, + .mac_lv1_rcvy = rtw89_usb_ops_mac_lv1_rcvy, + .dump_err_status = rtw89_usb_ops_dump_err_status, + .napi_poll = NULL, + + .recovery_start = NULL, + .recovery_complete = NULL, + + .ctrl_txdma_ch = NULL, + .ctrl_txdma_fw_ch = NULL, + .ctrl_trxhci = NULL, + .poll_txdma_ch_idle = NULL, + + .clr_idx_all = NULL, + .clear = NULL, + .disable_intr = NULL, + .enable_intr = NULL, + .rst_bdram = NULL, +}; + +static int rtw89_usb_parse(struct rtw89_dev *rtwdev, + struct usb_interface *intf) +{ + struct usb_host_interface *host_interface = &intf->altsetting[0]; + struct usb_interface_descriptor *intf_desc = &host_interface->desc; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct usb_endpoint_descriptor *endpoint; + int num_out_pipes = 0; + u8 num; + int i; + + if (intf_desc->bNumEndpoints > RTW89_MAX_ENDPOINT_NUM) { + rtw89_err(rtwdev, "found %d endpoints, expected %d max\n", + intf_desc->bNumEndpoints, RTW89_MAX_ENDPOINT_NUM); + return -EINVAL; + } + + for (i = 0; i < intf_desc->bNumEndpoints; i++) { + endpoint = &host_interface->endpoint[i].desc; + num = usb_endpoint_num(endpoint); + + if (usb_endpoint_dir_in(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + if (rtwusb->in_pipe) { + rtw89_err(rtwdev, + "found more than 1 bulk in endpoint\n"); + return -EINVAL; + } + + rtwusb->in_pipe = num; + } + + if (usb_endpoint_dir_out(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + if (num_out_pipes >= RTW89_MAX_BULKOUT_NUM) { + rtw89_err(rtwdev, + "found more than %d bulk out endpoints\n", + RTW89_MAX_BULKOUT_NUM); + return -EINVAL; + } + + rtwusb->out_pipe[num_out_pipes++] = num; + } + } + + if (num_out_pipes < 1) { + rtw89_err(rtwdev, "no bulk out endpoints found\n"); + return -EINVAL; + } + + return 0; +} + +static int rtw89_usb_intf_init(struct rtw89_dev *rtwdev, + struct usb_interface *intf) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int ret; + + ret = rtw89_usb_parse(rtwdev, intf); + if (ret) + return ret; + + rtwusb->vendor_req_buf = kmalloc(sizeof(*rtwusb->vendor_req_buf), + GFP_KERNEL); + if (!rtwusb->vendor_req_buf) + return -ENOMEM; + + rtwusb->udev = usb_get_dev(interface_to_usbdev(intf)); + + usb_set_intfdata(intf, rtwdev->hw); + + SET_IEEE80211_DEV(rtwdev->hw, &intf->dev); + + return 0; +} + +static void rtw89_usb_intf_deinit(struct rtw89_dev *rtwdev, + struct usb_interface *intf) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + + usb_put_dev(rtwusb->udev); + kfree(rtwusb->vendor_req_buf); + usb_set_intfdata(intf, NULL); +} + +int rtw89_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + const struct rtw89_driver_info *info; + struct rtw89_dev *rtwdev; + struct rtw89_usb *rtwusb; + int ret; + + info = (const struct rtw89_driver_info *)id->driver_info; + + rtwdev = rtw89_alloc_ieee80211_hw(&intf->dev, + sizeof(struct rtw89_usb), + info->chip, info->variant); + if (!rtwdev) { + dev_err(&intf->dev, "failed to allocate hw\n"); + return -ENOMEM; + } + + rtwusb = rtw89_usb_priv(rtwdev); + rtwusb->rtwdev = rtwdev; + + rtwdev->hci.ops = &rtw89_usb_ops; + rtwdev->hci.type = RTW89_HCI_TYPE_USB; + + ret = rtw89_usb_intf_init(rtwdev, intf); + if (ret) { + rtw89_err(rtwdev, "failed to initialise intf: %d\n", ret); + goto err_free_hw; + } + + if (rtwusb->udev->speed == USB_SPEED_SUPER) + rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_USB3; + else + rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_USB2; + + rtw89_usb_init_tx(rtwdev); + + ret = rtw89_usb_alloc_rx_bufs(rtwusb); + if (ret) + goto err_intf_deinit; + + ret = rtw89_usb_init_rx(rtwdev); + if (ret) + goto err_free_rx_bufs; + + ret = rtw89_core_init(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to initialise core: %d\n", ret); + goto err_deinit_rx; + } + + ret = rtw89_chip_info_setup(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to setup chip information\n"); + goto err_core_deinit; + } + + ret = rtw89_core_register(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to register core\n"); + goto err_core_deinit; + } + + rtw89_usb_start_rx(rtwdev); + + set_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags); + + return 0; + +err_core_deinit: + rtw89_core_deinit(rtwdev); +err_deinit_rx: + rtw89_usb_deinit_rx(rtwdev); +err_free_rx_bufs: + rtw89_usb_free_rx_bufs(rtwusb); +err_intf_deinit: + rtw89_usb_intf_deinit(rtwdev, intf); +err_free_hw: + rtw89_free_ieee80211_hw(rtwdev); + + return ret; +} +EXPORT_SYMBOL(rtw89_usb_probe); + +void rtw89_usb_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(intf); + struct rtw89_dev *rtwdev; + struct rtw89_usb *rtwusb; + + if (!hw) + return; + + rtwdev = hw->priv; + rtwusb = rtw89_usb_priv(rtwdev); + + rtw89_usb_cancel_rx_bufs(rtwusb); + + rtw89_core_unregister(rtwdev); + rtw89_core_deinit(rtwdev); + rtw89_usb_deinit_rx(rtwdev); + rtw89_usb_free_rx_bufs(rtwusb); + rtw89_usb_deinit_tx(rtwdev); + rtw89_usb_intf_deinit(rtwdev, intf); + rtw89_free_ieee80211_hw(rtwdev); +} +EXPORT_SYMBOL(rtw89_usb_disconnect); + +MODULE_AUTHOR("Bitterblue Smith "); +MODULE_DESCRIPTION("Realtek USB 802.11ax wireless driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/usb.h b/drivers/net/wireless/realtek/rtw89/usb.h new file mode 100644 index 000000000000..c1b4bfa20979 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/usb.h @@ -0,0 +1,65 @@ +/* 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 + +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; + + __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 sk_buff_head tx_queue[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 From 52cf4432378568ba1ed275b5aecc61c66dad7368 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:47:19 +0300 Subject: [PATCH 20/58] wifi: rtw89: Add rtw8851bu.c This is the entry point for the new rtw89_8851bu module. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/9d40c265-2982-4073-84a3-d3781defdbca@gmail.com --- .../net/wireless/realtek/rtw89/rtw8851bu.c | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8851bu.c diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c new file mode 100644 index 000000000000..c3722547c6b0 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2025 Realtek Corporation + */ + +#include +#include +#include "rtw8851b.h" +#include "usb.h" + +static const struct rtw89_driver_info rtw89_8851bu_info = { + .chip = &rtw8851b_chip_info, + .variant = NULL, + .quirks = NULL, +}; + +static const struct usb_device_id rtw_8851bu_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb851, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8851bu_info }, + /* TP-Link Archer TX10UB Nano */ + { USB_DEVICE_AND_INTERFACE_INFO(0x3625, 0x010b, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8851bu_info }, + /* Edimax EW-7611UXB */ + { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xe611, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8851bu_info }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8851bu_id_table); + +static struct usb_driver rtw_8851bu_driver = { + .name = KBUILD_MODNAME, + .id_table = rtw_8851bu_id_table, + .probe = rtw89_usb_probe, + .disconnect = rtw89_usb_disconnect, +}; +module_usb_driver(rtw_8851bu_driver); + +MODULE_AUTHOR("Bitterblue Smith "); +MODULE_DESCRIPTION("Realtek 802.11ax wireless 8851BU driver"); +MODULE_LICENSE("Dual BSD/GPL"); From 0030088148d5a070f445c1522989e490b311286b Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 30 Jun 2025 23:47:52 +0300 Subject: [PATCH 21/58] wifi: rtw89: Enable the new USB modules Enable compilation of the new rtw89_usb and rtw89_8851bu modules. Tested mostly in station mode, and a little bit in AP mode. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/4968a9d5-02c8-4d35-a5ad-b75ece8f5d36@gmail.com --- drivers/net/wireless/realtek/rtw89/Kconfig | 14 ++++++++++++++ drivers/net/wireless/realtek/rtw89/Makefile | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/Kconfig b/drivers/net/wireless/realtek/rtw89/Kconfig index 205d7ecca7d7..bd180f3369c3 100644 --- a/drivers/net/wireless/realtek/rtw89/Kconfig +++ b/drivers/net/wireless/realtek/rtw89/Kconfig @@ -17,6 +17,9 @@ config RTW89_CORE config RTW89_PCI tristate +config RTW89_USB + tristate + config RTW89_8851B tristate @@ -49,6 +52,17 @@ config RTW89_8851BE 802.11ax PCIe wireless network (Wi-Fi 6) adapter +config RTW89_8851BU + tristate "Realtek 8851BU USB wireless network (Wi-Fi 6) adapter" + depends on USB + select RTW89_CORE + select RTW89_USB + select RTW89_8851B + help + Select this option will enable support for 8851BU chipset + + 802.11ax USB wireless network (Wi-Fi 6) adapter + config RTW89_8852AE tristate "Realtek 8852AE PCI wireless network (Wi-Fi 6) adapter" depends on PCI diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index c751013e811e..891e2d55c335 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -31,6 +31,9 @@ rtw89_8851b-objs := rtw8851b.o \ obj-$(CONFIG_RTW89_8851BE) += rtw89_8851be.o rtw89_8851be-objs := rtw8851be.o +obj-$(CONFIG_RTW89_8851BU) += rtw89_8851bu.o +rtw89_8851bu-objs := rtw8851bu.o + obj-$(CONFIG_RTW89_8852A) += rtw89_8852a.o rtw89_8852a-objs := rtw8852a.o \ rtw8852a_table.o \ @@ -81,3 +84,6 @@ rtw89_core-$(CONFIG_RTW89_DEBUG) += debug.o obj-$(CONFIG_RTW89_PCI) += rtw89_pci.o rtw89_pci-y := pci.o pci_be.o +obj-$(CONFIG_RTW89_USB) += rtw89_usb.o +rtw89_usb-y := usb.o + From 480dd4dddfc510c70e45f3d35a7df8a8a1511a7b Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Tue, 1 Jul 2025 15:38:39 +0800 Subject: [PATCH 22/58] wifi: rtw89: enter power save mode aggressively Currently the driver allows the WiFi chip enter power save mode by checking the transmitting and receiving traffic is very low per two seconds. But it's hard for some applications to enter power save mode, like video streaming, which sends burst traffic regularly for other side to buffer and only send little traffic at most time. So adjust the criteria to enter power save while lower than 10Mbps and check it per 100ms. Thus WiFi chip could reduce power consumption under these applications. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250701073839.31905-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 110 +++++++++++++----- drivers/net/wireless/realtek/rtw89/core.h | 20 +++- drivers/net/wireless/realtek/rtw89/mac80211.c | 3 + drivers/net/wireless/realtek/rtw89/ser.c | 3 + drivers/net/wireless/realtek/rtw89/wow.c | 2 +- drivers/net/wireless/realtek/rtw89/wow.h | 14 ++- 6 files changed, 123 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 776d2e5ce8a0..23d050041583 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -319,15 +319,25 @@ static const struct ieee80211_supported_band rtw89_sband_6ghz = { .n_bitrates = ARRAY_SIZE(rtw89_bitrates) - 4, }; +static void __rtw89_traffic_stats_accu(struct rtw89_traffic_stats *stats, + struct sk_buff *skb, bool tx) +{ + if (tx) { + stats->tx_cnt++; + stats->tx_unicast += skb->len; + } else { + stats->rx_cnt++; + stats->rx_unicast += skb->len; + } +} + static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev, - struct rtw89_traffic_stats *stats, - struct sk_buff *skb, bool tx) + struct rtw89_vif *rtwvif, + struct sk_buff *skb, + bool accu_dev, bool tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - if (tx && ieee80211_is_assoc_req(hdr->frame_control)) - rtw89_wow_parse_akm(rtwdev, skb); - if (!ieee80211_is_data(hdr->frame_control)) return; @@ -335,12 +345,12 @@ static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev, is_multicast_ether_addr(hdr->addr1)) return; - if (tx) { - stats->tx_cnt++; - stats->tx_unicast += skb->len; - } else { - stats->rx_cnt++; - stats->rx_unicast += skb->len; + if (accu_dev) + __rtw89_traffic_stats_accu(&rtwdev->stats, skb, tx); + + if (rtwvif) { + __rtw89_traffic_stats_accu(&rtwvif->stats, skb, tx); + __rtw89_traffic_stats_accu(&rtwvif->stats_ps, skb, tx); } } @@ -1150,8 +1160,8 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, tx_req.rtwsta_link = rtwsta_link; tx_req.desc_info.sw_mld = sw_mld; - rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true); - rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true); + rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, true, true); + rtw89_wow_parse_akm(rtwdev, skb); rtw89_core_tx_update_desc_info(rtwdev, &tx_req); rtw89_core_tx_wake(rtwdev, &tx_req); @@ -2267,7 +2277,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, if (desc_info->data_rate < RTW89_HW_RATE_NR) pkt_stat->rx_rate_cnt[desc_info->data_rate]++; - rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, false); + rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, false, false); out: rcu_read_unlock(); @@ -2280,7 +2290,7 @@ static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev, { struct rtw89_vif_rx_stats_iter_data iter_data; - rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, false); + rtw89_traffic_stats_accu(rtwdev, NULL, skb, true, false); iter_data.rtwdev = rtwdev; iter_data.phy_ppdu = phy_ppdu; @@ -3570,9 +3580,22 @@ void rtw89_roc_work(struct wiphy *wiphy, struct wiphy_work *work) } static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev, - u32 throughput, u64 cnt) + u32 throughput, u64 cnt, + enum rtw89_tfc_interval interval) { - if (cnt < 100) + u64 cnt_level; + + switch (interval) { + default: + case RTW89_TFC_INTERVAL_100MS: + cnt_level = 5; + break; + case RTW89_TFC_INTERVAL_2SEC: + cnt_level = 100; + break; + } + + if (cnt < cnt_level) return RTW89_TFC_IDLE; if (throughput > 50) return RTW89_TFC_HIGH; @@ -3584,13 +3607,14 @@ static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev, } static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, - struct rtw89_traffic_stats *stats) + struct rtw89_traffic_stats *stats, + enum rtw89_tfc_interval interval) { enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv; enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv; - stats->tx_throughput_raw = (u32)(stats->tx_unicast >> RTW89_TP_SHIFT); - stats->rx_throughput_raw = (u32)(stats->rx_unicast >> RTW89_TP_SHIFT); + stats->tx_throughput_raw = rtw89_bytes_to_mbps(stats->tx_unicast, interval); + stats->rx_throughput_raw = rtw89_bytes_to_mbps(stats->rx_unicast, interval); ewma_tp_add(&stats->tx_ewma_tp, stats->tx_throughput_raw); ewma_tp_add(&stats->rx_ewma_tp, stats->rx_throughput_raw); @@ -3598,9 +3622,9 @@ static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp); stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp); stats->tx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->tx_throughput, - stats->tx_cnt); + stats->tx_cnt, interval); stats->rx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->rx_throughput, - stats->rx_cnt); + stats->rx_cnt, interval); stats->tx_avg_len = stats->tx_cnt ? DIV_ROUND_DOWN_ULL(stats->tx_unicast, stats->tx_cnt) : 0; stats->rx_avg_len = stats->rx_cnt ? @@ -3626,10 +3650,12 @@ static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev) unsigned int link_id; bool tfc_changed; - tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats); + tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats, + RTW89_TFC_INTERVAL_2SEC); rtw89_for_each_rtwvif(rtwdev, rtwvif) { - rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats); + rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats, + RTW89_TFC_INTERVAL_2SEC); rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) rtw89_fw_h2c_tp_offload(rtwdev, rtwvif_link); @@ -3649,8 +3675,8 @@ static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev) if (rtwvif->offchan) continue; - if (rtwvif->stats.tx_tfc_lv != RTW89_TFC_IDLE || - rtwvif->stats.rx_tfc_lv != RTW89_TFC_IDLE) + if (rtwvif->stats_ps.tx_tfc_lv >= RTW89_TFC_MID || + rtwvif->stats_ps.rx_tfc_lv >= RTW89_TFC_MID) continue; vif = rtwvif_to_vif(rtwvif); @@ -3789,6 +3815,34 @@ static void rtw89_core_mlo_track(struct rtw89_dev *rtwdev) } } +static void rtw89_track_ps_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + track_ps_work.work); + struct rtw89_vif *rtwvif; + + lockdep_assert_wiphy(wiphy); + + if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags)) + return; + + if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) + return; + + wiphy_delayed_work_queue(wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); + + rtw89_for_each_rtwvif(rtwdev, rtwvif) + rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats_ps, + RTW89_TFC_INTERVAL_100MS); + + if (rtwdev->scanning) + return; + + if (rtwdev->lps_enabled && !rtwdev->btc.lps) + rtw89_enter_lps_track(rtwdev); +} + static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work) { struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, @@ -4875,6 +4929,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); set_bit(RTW89_FLAG_RUNNING, rtwdev->flags); @@ -4909,6 +4965,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) wiphy_work_cancel(wiphy, &btc->icmp_notify_work); cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->chanctx_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_act1_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_bt_devinfo_work); @@ -5136,6 +5193,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work); INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work); wiphy_delayed_work_init(&rtwdev->track_work, rtw89_track_work); + wiphy_delayed_work_init(&rtwdev->track_ps_work, rtw89_track_ps_work); wiphy_delayed_work_init(&rtwdev->chanctx_work, rtw89_chanctx_work); wiphy_delayed_work_init(&rtwdev->coex_act1_work, rtw89_coex_act1_work); wiphy_delayed_work_init(&rtwdev->coex_bt_devinfo_work, rtw89_coex_bt_devinfo_work); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a08d07e44498..1d8f89e83c9a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -40,6 +40,7 @@ extern const struct ieee80211_ops rtw89_ops; #define BYPASS_CR_DATA 0xbabecafe #define RTW89_TRACK_WORK_PERIOD round_jiffies_relative(HZ * 2) +#define RTW89_TRACK_PS_WORK_PERIOD msecs_to_jiffies(100) #define RTW89_FORBID_BA_TIMER round_jiffies_relative(HZ * 4) #define CFO_TRACK_MAX_USER 64 #define MAX_RSSI 110 @@ -1392,6 +1393,11 @@ struct rtw89_btc_wl_smap { u32 emlsr: 1; }; +enum rtw89_tfc_interval { + RTW89_TFC_INTERVAL_100MS, + RTW89_TFC_INTERVAL_2SEC, +}; + enum rtw89_tfc_lv { RTW89_TFC_IDLE, RTW89_TFC_ULTRA_LOW, @@ -1400,7 +1406,6 @@ enum rtw89_tfc_lv { RTW89_TFC_HIGH, }; -#define RTW89_TP_SHIFT 18 /* bytes/2s --> Mbps */ DECLARE_EWMA(tp, 10, 2); struct rtw89_traffic_stats { @@ -5943,6 +5948,7 @@ struct rtw89_dev { } bbs[RTW89_PHY_NUM]; struct wiphy_delayed_work track_work; + struct wiphy_delayed_work track_ps_work; struct wiphy_delayed_work chanctx_work; struct wiphy_delayed_work coex_act1_work; struct wiphy_delayed_work coex_bt_devinfo_work; @@ -5993,6 +5999,7 @@ struct rtw89_vif { __be32 ip_addr; struct rtw89_traffic_stats stats; + struct rtw89_traffic_stats stats_ps; u32 tdls_peer; struct ieee80211_scan_ies *scan_ies; @@ -7305,6 +7312,17 @@ static inline bool rtw89_is_rtl885xb(struct rtw89_dev *rtwdev) return false; } +static inline u32 rtw89_bytes_to_mbps(u64 bytes, enum rtw89_tfc_interval interval) +{ + switch (interval) { + default: + case RTW89_TFC_INTERVAL_2SEC: + return bytes >> 18; /* bytes/2s --> Mbps */; + case RTW89_TFC_INTERVAL_100MS: + return (bytes * 10) >> 17; /* bytes/100ms --> Mbps */ + } +} + int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel); int rtw89_h2c_tx(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index a3ae1e654a98..c982ad633b4a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -1772,6 +1772,7 @@ static int rtw89_ops_suspend(struct ieee80211_hw *hw, set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_ps_work); ret = rtw89_wow_suspend(rtwdev, wowlan); if (ret) { @@ -1797,6 +1798,8 @@ static int rtw89_ops_resume(struct ieee80211_hw *hw) clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); return ret ? 1 : 0; } diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index d504518b8a57..bb39fdbcba0d 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -492,6 +492,7 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) case SER_EV_STATE_IN: wiphy_lock(wiphy); wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work); wiphy_unlock(wiphy); drv_stop_tx(ser); @@ -525,6 +526,8 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) drv_resume_tx(ser); wiphy_delayed_work_queue(wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); break; default: diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 34a0ab49bd7a..c935d6683d83 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -12,7 +12,7 @@ #include "util.h" #include "wow.h" -void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) +void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h index f91991e8f2e3..6606528d31c7 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -116,9 +116,21 @@ static inline bool rtw_wow_has_mgd_features(struct rtw89_dev *rtwdev) return !bitmap_empty(rtw_wow->flags, RTW89_WOW_FLAG_NUM); } +void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb); + +static inline +void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (likely(!ieee80211_is_assoc_req(hdr->frame_control))) + return; + + __rtw89_wow_parse_akm(rtwdev, skb); +} + int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan); int rtw89_wow_resume(struct rtw89_dev *rtwdev); -void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb); #else static inline void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) From 5e9184ae7207c828d3721e9fdaeeb61da0994995 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:36:59 +0300 Subject: [PATCH 23/58] wifi: rtw89: 8852bx: Accept USB devices and load their MAC address Make __rtw8852bx_read_efuse() accept USB devices and load the MAC address from the correct offset. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/1f58d168-67a9-4d86-9e6a-73789c7a59f4@gmail.com --- .../net/wireless/realtek/rtw89/rtw8852b_common.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index 0cf03f18cbb1..3fb2972ae6f6 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -172,14 +172,6 @@ static const struct rtw89_reg3_def rtw8852bx_btc_preagc_dis_defs[] = { static DECLARE_PHY_REG3_TBL(rtw8852bx_btc_preagc_dis_defs); -static void rtw8852be_efuse_parsing(struct rtw89_efuse *efuse, - struct rtw8852bx_efuse *map) -{ - ether_addr_copy(efuse->addr, map->e.mac_addr); - efuse->rfe_type = map->rfe_type; - efuse->xtal_cap = map->xtal_k; -} - static void rtw8852bx_efuse_parsing_tssi(struct rtw89_dev *rtwdev, struct rtw8852bx_efuse *map) { @@ -261,12 +253,18 @@ static int __rtw8852bx_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, switch (rtwdev->hci.type) { case RTW89_HCI_TYPE_PCIE: - rtw8852be_efuse_parsing(efuse, map); + ether_addr_copy(efuse->addr, map->e.mac_addr); + break; + case RTW89_HCI_TYPE_USB: + ether_addr_copy(efuse->addr, map->u.mac_addr); break; default: return -EOPNOTSUPP; } + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); return 0; From 0980de01da08338d4a7ceaf5e7ab25a56142c75a Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:37:32 +0300 Subject: [PATCH 24/58] wifi: rtw89: 8852b: Fix rtw8852b_pwr_{on,off}_func() for USB There are a few differences in the power on/off functions between PCIE and USB. The changes in the power off function in particular are needed for the RTL8832BU to be able to power on again after it's powered off. While the RTL8832BU appears to work without the changes in the power on function, it's probably best to implement them, in case they are needed in some situations. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/c12da54f-88e6-4b11-8587-36f9cac13bf3@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index b0b73a4a70a0..85b6849db798 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -299,7 +299,8 @@ static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); - rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); rtw89_write32_set(rtwdev, R_AX_SYS_ADIE_PAD_PWR_CTRL, B_AX_SYM_PADPDN_WL_PTA_1P3); @@ -361,7 +362,7 @@ static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_VOL_L1_MASK, 0x9); rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_VREFPFM_L_MASK, 0xA); - if (rtwdev->hal.cv == CHIP_CBV) { + if (rtwdev->hal.cv == CHIP_CBV && rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { rtw89_write32_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); rtw89_write16_mask(rtwdev, R_AX_HCI_LDO_CTRL, B_AX_R_AX_VADJ_MASK, 0xA); rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); @@ -443,10 +444,22 @@ static int rtw8852b_pwr_off_func(struct rtw89_dev *rtwdev) if (ret) return ret; - rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_EDSWR); + rtw89_write32_set(rtwdev, R_AX_SYS_SWR_CTRL1, B_AX_SYM_CTRL_SPS_PWMFREQ); rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_REG_ZCDC_H_MASK, 0x3); - rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + } else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) { + val32 = rtw89_read32(rtwdev, R_AX_SYS_PW_CTRL); + val32 &= ~B_AX_AFSM_PCIE_SUS_EN; + val32 |= B_AX_AFSM_WLSUS_EN; + rtw89_write32(rtwdev, R_AX_SYS_PW_CTRL, val32); + } return 0; } From b57b556a02e6ac1192ab57d5c3a045ad34182b7a Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:38:14 +0300 Subject: [PATCH 25/58] wifi: rtw89: 8852b: Add rtw8852b_dle_mem_usb3 "dle" could be "Data Link Engine" or "Double Link Engine". These are some parameters needed for RTL8852BU. In this case the same parameters are used for USB 2 and USB 3. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/7224021b-4fb5-44bc-aeb1-3a6fd3625f2a@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 85b6849db798..50eed21371a5 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -66,6 +66,19 @@ static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = { NULL}, }; +static const struct rtw89_dle_mem rtw8852b_dle_mem_usb3[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25, + &rtw89_mac_size.ple_size33, &rtw89_mac_size.wde_qt25, + &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt74, + &rtw89_mac_size.ple_qt75}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + static const u32 rtw8852b_h2c_regs[RTW89_H2CREG_MAX] = { R_AX_H2CREG_DATA0, R_AX_H2CREG_DATA1, R_AX_H2CREG_DATA2, R_AX_H2CREG_DATA3 @@ -834,7 +847,10 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, NULL, NULL}, - .dle_mem = {rtw8852b_dle_mem_pcie, NULL, NULL, NULL}, + .dle_mem = {rtw8852b_dle_mem_pcie, + rtw8852b_dle_mem_usb3, + rtw8852b_dle_mem_usb3, + NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, From f56b4446d07ac42ef7e71789a9256fa2f8260876 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:38:35 +0300 Subject: [PATCH 26/58] wifi: rtw89: 8852b: Add rtw8852b_hfc_param_ini_usb "hfc" means "hci fc" which is "Host Control Interface Flow Control". These are some parameters needed for RTL8852BU. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/40dd1597-27d8-4316-ac3b-4bf7ff9f3e2f@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 50eed21371a5..33ab71d84ffc 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -49,6 +49,48 @@ static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_pcie[] = { [RTW89_QTA_INVALID] = {NULL}, }; +static const struct rtw89_hfc_ch_cfg rtw8852b_hfc_chcfg_usb[] = { + {18, 152, grp_0}, /* ACH 0 */ + {18, 152, grp_0}, /* ACH 1 */ + {18, 152, grp_0}, /* ACH 2 */ + {18, 152, grp_0}, /* ACH 3 */ + {0, 0, grp_0}, /* ACH 4 */ + {0, 0, grp_0}, /* ACH 5 */ + {0, 0, grp_0}, /* ACH 6 */ + {0, 0, grp_0}, /* ACH 7 */ + {18, 152, grp_0}, /* B0MGQ */ + {18, 152, grp_0}, /* B0HIQ */ + {0, 0, grp_0}, /* B1MGQ */ + {0, 0, grp_0}, /* B1HIQ */ + {0, 0, 0} /* FWCMDQ */ +}; + +static const struct rtw89_hfc_pub_cfg rtw8852b_hfc_pubcfg_usb = { + 152, /* Group 0 */ + 0, /* Group 1 */ + 152, /* Public Max */ + 0 /* WP threshold */ +}; + +static const struct rtw89_hfc_prec_cfg rtw8852b_hfc_preccfg_usb = { + 9, /* CH 0-11 pre-cost */ + 32, /* H2C pre-cost */ + 64, /* WP CH 0-7 pre-cost */ + 24, /* WP CH 8-11 pre-cost */ + 1, /* CH 0-11 full condition */ + 1, /* H2C full condition */ + 1, /* WP CH 0-7 full condition */ + 1, /* WP CH 8-11 full condition */ +}; + +static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_usb[] = { + [RTW89_QTA_SCC] = {rtw8852b_hfc_chcfg_usb, &rtw8852b_hfc_pubcfg_usb, + &rtw8852b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_DLFW] = {NULL, NULL, + &rtw8852b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_INVALID] = {NULL}, +}; + static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = { [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size7, &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt7, @@ -846,7 +888,9 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .max_amsdu_limit = 5000, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, NULL, NULL}, + .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, + rtw8852b_hfc_param_ini_usb, + NULL}, .dle_mem = {rtw8852b_dle_mem_pcie, rtw8852b_dle_mem_usb3, rtw8852b_dle_mem_usb3, From 0ed2a8b1a14e9ebaa72a98b8ee9938cb16c2d606 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:38:55 +0300 Subject: [PATCH 27/58] wifi: rtw89: Add rtw8852bu.c This is the entry point for the new rtw89_8852bu module. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/bac25b31-8146-4738-b8f2-eba66c51f3d8@gmail.com --- .../net/wireless/realtek/rtw89/rtw8852bu.c | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852bu.c diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c new file mode 100644 index 000000000000..b315cb997758 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2025 Realtek Corporation + */ + +#include +#include +#include "rtw8852b.h" +#include "usb.h" + +static const struct rtw89_driver_info rtw89_8852bu_info = { + .chip = &rtw8852b_chip_info, + .variant = NULL, + .quirks = NULL, +}; + +static const struct usb_device_id rtw_8852bu_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb832, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb83a, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb852, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb85a, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xa85b, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0586, 0x3428, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1a62, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0db0, 0x6931, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6121, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0100, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0108, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x6822, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8852bu_id_table); + +static struct usb_driver rtw_8852bu_driver = { + .name = KBUILD_MODNAME, + .id_table = rtw_8852bu_id_table, + .probe = rtw89_usb_probe, + .disconnect = rtw89_usb_disconnect, +}; +module_usb_driver(rtw_8852bu_driver); + +MODULE_AUTHOR("Bitterblue Smith "); +MODULE_DESCRIPTION("Realtek 802.11ax wireless 8852BU driver"); +MODULE_LICENSE("Dual BSD/GPL"); From 4b295f4fdc80e9b13bd2ca05f4c9434fa0857cab Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 5 Jul 2025 22:39:21 +0300 Subject: [PATCH 28/58] wifi: rtw89: Enable the new rtw89_8852bu module Enable compilation of the new rtw89_8852bu module. Tested mostly in station mode, and a little bit in AP mode. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/627e9e92-6f10-45de-a340-19b10d7bad82@gmail.com --- drivers/net/wireless/realtek/rtw89/Kconfig | 12 ++++++++++++ drivers/net/wireless/realtek/rtw89/Makefile | 3 +++ 2 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/Kconfig b/drivers/net/wireless/realtek/rtw89/Kconfig index bd180f3369c3..4288c30b400a 100644 --- a/drivers/net/wireless/realtek/rtw89/Kconfig +++ b/drivers/net/wireless/realtek/rtw89/Kconfig @@ -86,6 +86,18 @@ config RTW89_8852BE 802.11ax PCIe wireless network (Wi-Fi 6) adapter +config RTW89_8852BU + tristate "Realtek 8852BU USB wireless network (Wi-Fi 6) adapter" + depends on USB + select RTW89_CORE + select RTW89_USB + select RTW89_8852B + select RTW89_8852B_COMMON + help + Select this option will enable support for 8852BU chipset + + 802.11ax USB wireless network (Wi-Fi 6) adapter + config RTW89_8852BTE tristate "Realtek 8852BE-VT PCI wireless network (Wi-Fi 6) adapter" depends on PCI diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index 891e2d55c335..23e43c444f69 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -55,6 +55,9 @@ rtw89_8852b-objs := rtw8852b.o \ obj-$(CONFIG_RTW89_8852BE) += rtw89_8852be.o rtw89_8852be-objs := rtw8852be.o +obj-$(CONFIG_RTW89_8852BU) += rtw89_8852bu.o +rtw89_8852bu-objs := rtw8852bu.o + obj-$(CONFIG_RTW89_8852BT) += rtw89_8852bt.o rtw89_8852bt-objs := rtw8852bt.o \ rtw8852bt_rfk.o \ From 75bb7774a16b1e835f67baff6f5174ca17491db6 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 9 Jul 2025 14:50:03 +0800 Subject: [PATCH 29/58] wifi: rtw89: regd/acpi: support country CA by BIT(1) in 6 GHz SP conf ACPI DSM function 7 is used to decide whether 6 GHz Standard Power (SP) is allowed on given countries. Now, add BIT(1) for country CA. Besides, for searching country index, replace for-loop with index getter function. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709065006.32028-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.h | 1 + drivers/net/wireless/realtek/rtw89/regd.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index 8c918ee02d2e..8217cdfbbc49 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -56,6 +56,7 @@ struct rtw89_acpi_policy_6ghz { enum rtw89_acpi_conf_6ghz_sp { RTW89_ACPI_CONF_6GHZ_SP_US = BIT(0), + RTW89_ACPI_CONF_6GHZ_SP_CA = BIT(1), }; struct rtw89_acpi_policy_6ghz_sp { diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 3ad14cab1f58..c91a86332b17 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -490,12 +490,11 @@ static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev) static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; - const struct rtw89_regd_ctrl *regd_ctrl = ®ulatory->ctrl; const struct rtw89_acpi_policy_6ghz_sp *ptr; struct rtw89_acpi_dsm_result res = {}; - bool enable_by_us; + bool enable; + u8 index; int ret; - int i; ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP, &res); if (ret) { @@ -520,14 +519,15 @@ static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev) bitmap_fill(regulatory->block_6ghz_sp, RTW89_REGD_MAX_COUNTRY_NUM); - enable_by_us = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_US); + index = rtw89_regd_get_index_by_name(rtwdev, "US"); + enable = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_US); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_6ghz_sp); - for (i = 0; i < regd_ctrl->nr; i++) { - const struct rtw89_regd *tmp = ®d_ctrl->map[i]; - - if (enable_by_us && memcmp(tmp->alpha2, "US", 2) == 0) - clear_bit(i, regulatory->block_6ghz_sp); - } + index = rtw89_regd_get_index_by_name(rtwdev, "CA"); + enable = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_CA); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_6ghz_sp); out: kfree(ptr); From 01186c303ba363262d546eadd0adde6f37df91b2 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 9 Jul 2025 14:50:04 +0800 Subject: [PATCH 30/58] wifi: rtw89: regd/acpi: update field definition to specific country in UNII-4 conf Originally, fields of ACPI DSM function 6 were handled for countries following specific regulatory. BIT(0) for countries following FCC regulatory BIT(1) for countries following IC regulatory Now, update to the following (one field for one specific country). BIT(0) for country US BIT(1) for country CA Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709065006.32028-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.h | 4 +-- drivers/net/wireless/realtek/rtw89/regd.c | 34 ++++++++--------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index 8217cdfbbc49..8cf261505539 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -22,8 +22,8 @@ enum rtw89_acpi_dsm_func { }; enum rtw89_acpi_conf_unii4 { - RTW89_ACPI_CONF_UNII4_FCC = BIT(0), - RTW89_ACPI_CONF_UNII4_IC = BIT(1), + RTW89_ACPI_CONF_UNII4_US = BIT(0), + RTW89_ACPI_CONF_UNII4_CA = BIT(1), }; enum rtw89_acpi_policy_mode { diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index c91a86332b17..ea44b8311cb2 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -360,15 +360,13 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, struct wiphy *wiphy) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; - const struct rtw89_regd_ctrl *regd_ctrl = ®ulatory->ctrl; const struct rtw89_chip_info *chip = rtwdev->chip; struct ieee80211_supported_band *sband; struct rtw89_acpi_dsm_result res = {}; - bool enable_by_fcc; - bool enable_by_ic; + bool enable; + u8 index; int ret; u8 val; - int i; sband = wiphy->bands[NL80211_BAND_5GHZ]; if (!sband) @@ -385,35 +383,25 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, if (ret) { rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: cannot eval unii 4: %d\n", ret); - enable_by_fcc = true; - enable_by_ic = false; + val = u8_encode_bits(1, RTW89_ACPI_CONF_UNII4_US); goto bottom; } val = res.u.value; - enable_by_fcc = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_FCC); - enable_by_ic = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_IC); rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: eval if allow unii-4: 0x%x\n", val); bottom: - for (i = 0; i < regd_ctrl->nr; i++) { - const struct rtw89_regd *regd = ®d_ctrl->map[i]; + index = rtw89_regd_get_index_by_name(rtwdev, "US"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_US); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_unii4); - switch (regd->txpwr_regd[RTW89_BAND_5G]) { - case RTW89_FCC: - if (enable_by_fcc) - clear_bit(i, regulatory->block_unii4); - break; - case RTW89_IC: - if (enable_by_ic) - clear_bit(i, regulatory->block_unii4); - break; - default: - break; - } - } + index = rtw89_regd_get_index_by_name(rtwdev, "CA"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_CA); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_unii4); } static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block, From 08fbc2b6881b5228cb961b1efa6cb4bf41193105 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 9 Jul 2025 14:50:05 +0800 Subject: [PATCH 31/58] wifi: rtw89: regd/acpi: support regulatory rules via ACPI DSM and parse rule of regd_UK ACPI DSM function 10 is defined for the enablement for Realtek regulatory rules. The first rule is whether to allow regd_UK regulatory settings or not. If not, the strict one, i.e. regd_ETSI, regulatory settings will be used on country GB. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709065006.32028-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.c | 48 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/acpi.h | 13 ++++++ drivers/net/wireless/realtek/rtw89/regd.c | 27 ++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c index 581d6d4154d3..c35a36e0f4d9 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.c +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -279,6 +279,51 @@ static int rtw89_acpi_dsm_get_policy_tas(struct rtw89_dev *rtwdev, return 0; } +static +bool chk_acpi_policy_reg_rules_sig(const struct rtw89_acpi_policy_reg_rules *p) +{ + return p->signature[0] == 0x52 && + p->signature[1] == 0x54 && + p->signature[2] == 0x4B && + p->signature[3] == 0x0A; +} + +static +int rtw89_acpi_dsm_get_policy_reg_rules(struct rtw89_dev *rtwdev, + union acpi_object *obj, + struct rtw89_acpi_policy_reg_rules **policy) +{ + const struct rtw89_acpi_policy_reg_rules *ptr; + u32 buf_len; + + if (obj->type != ACPI_TYPE_BUFFER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect buffer but type: %d\n", obj->type); + return -EINVAL; + } + + buf_len = obj->buffer.length; + if (buf_len < sizeof(*ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", + __func__, buf_len); + return -EINVAL; + } + + ptr = (typeof(ptr))obj->buffer.pointer; + if (!chk_acpi_policy_reg_rules_sig(ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); + return -EINVAL; + } + + *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL); + if (!*policy) + return -ENOMEM; + + rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_reg_rules: ", *policy, + sizeof(*ptr)); + return 0; +} + int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, enum rtw89_acpi_dsm_func func, struct rtw89_acpi_dsm_result *res) @@ -302,6 +347,9 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, &res->u.policy_6ghz_sp); else if (func == RTW89_ACPI_DSM_FUNC_TAS_EN) ret = rtw89_acpi_dsm_get_policy_tas(rtwdev, obj, &res->u.policy_tas); + else if (func == RTW89_ACPI_DSM_FUNC_REG_RULES_EN) + ret = rtw89_acpi_dsm_get_policy_reg_rules(rtwdev, obj, + &res->u.policy_reg_rules); else ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value); diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index 8cf261505539..5811afebc2e6 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -19,6 +19,7 @@ enum rtw89_acpi_dsm_func { RTW89_ACPI_DSM_FUNC_TAS_EN = 5, RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP = 7, + RTW89_ACPI_DSM_FUNC_REG_RULES_EN = 10, }; enum rtw89_acpi_conf_unii4 { @@ -75,6 +76,17 @@ struct rtw89_acpi_policy_tas { u8 rsvd[3]; } __packed; +enum rtw89_acpi_conf_reg_rules { + RTW89_ACPI_CONF_REG_RULE_REGD_UK = BIT(0), +}; + +struct rtw89_acpi_policy_reg_rules { + u8 signature[4]; + u8 revision; + u8 conf; + u8 rsvd[3]; +} __packed; + struct rtw89_acpi_dsm_result { union { u8 value; @@ -82,6 +94,7 @@ struct rtw89_acpi_dsm_result { struct rtw89_acpi_policy_6ghz *policy_6ghz; struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp; struct rtw89_acpi_policy_tas *policy_tas; + struct rtw89_acpi_policy_reg_rules *policy_reg_rules; } u; }; diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index ea44b8311cb2..42678ff2a045 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -608,6 +608,30 @@ const char *rtw89_regd_get_string(enum rtw89_regulation_type regd) return rtw89_regd_string[regd]; } +static void rtw89_regd_setup_reg_rules(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_acpi_policy_reg_rules *ptr; + struct rtw89_acpi_dsm_result res = {}; + int ret; + + regulatory->txpwr_uk_follow_etsi = true; + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_REG_RULES_EN, &res); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval policy reg-rules: %d\n", ret); + return; + } + + ptr = res.u.policy_reg_rules; + + regulatory->txpwr_uk_follow_etsi = + !u8_get_bits(ptr->conf, RTW89_ACPI_CONF_REG_RULE_REGD_UK); + + kfree(ptr); +} + int rtw89_regd_setup(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; @@ -624,7 +648,8 @@ int rtw89_regd_setup(struct rtw89_dev *rtwdev) } regulatory->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; - regulatory->txpwr_uk_follow_etsi = true; + + rtw89_regd_setup_reg_rules(rtwdev); if (!wiphy) return -EINVAL; From b99d7cd36da835544da02d75b6398eb7b26412ee Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 9 Jul 2025 14:50:06 +0800 Subject: [PATCH 32/58] wifi: rtw89: regd/acpi: support 6 GHz VLP policy via ACPI DSM Process ACPI DSM function 11 to get 6 GHz VLP support by country. If not allowed, return error to block the connection. By default, i.e. ACPI DSM function is not configured, disallow 6 GHz VLP on country US and country CA, because some platform-level certifications are needed in FCC regulation before operating on 6 GHz VLP connection. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709065006.32028-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.c | 47 ++++++++++++++++ drivers/net/wireless/realtek/rtw89/acpi.h | 15 +++++ drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/regd.c | 68 +++++++++++++++++++++++ 4 files changed, 131 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c index c35a36e0f4d9..f1e758a5f32b 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.c +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -236,6 +236,50 @@ int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev, return 0; } +static bool chk_acpi_policy_6ghz_vlp_sig(const struct rtw89_acpi_policy_6ghz_vlp *p) +{ + return p->signature[0] == 0x52 && + p->signature[1] == 0x54 && + p->signature[2] == 0x4B && + p->signature[3] == 0x0B; +} + +static +int rtw89_acpi_dsm_get_policy_6ghz_vlp(struct rtw89_dev *rtwdev, + union acpi_object *obj, + struct rtw89_acpi_policy_6ghz_vlp **policy) +{ + const struct rtw89_acpi_policy_6ghz_vlp *ptr; + u32 buf_len; + + if (obj->type != ACPI_TYPE_BUFFER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect buffer but type: %d\n", obj->type); + return -EINVAL; + } + + buf_len = obj->buffer.length; + if (buf_len < sizeof(*ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", + __func__, buf_len); + return -EINVAL; + } + + ptr = (typeof(ptr))obj->buffer.pointer; + if (!chk_acpi_policy_6ghz_vlp_sig(ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); + return -EINVAL; + } + + *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL); + if (!*policy) + return -ENOMEM; + + rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_vlp: ", *policy, + sizeof(*ptr)); + return 0; +} + static bool chk_acpi_policy_tas_sig(const struct rtw89_acpi_policy_tas *p) { return p->signature[0] == 0x52 && @@ -345,6 +389,9 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP) ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj, &res->u.policy_6ghz_sp); + else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP) + ret = rtw89_acpi_dsm_get_policy_6ghz_vlp(rtwdev, obj, + &res->u.policy_6ghz_vlp); else if (func == RTW89_ACPI_DSM_FUNC_TAS_EN) ret = rtw89_acpi_dsm_get_policy_tas(rtwdev, obj, &res->u.policy_tas); else if (func == RTW89_ACPI_DSM_FUNC_REG_RULES_EN) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index 5811afebc2e6..48a46f2005b1 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -20,6 +20,7 @@ enum rtw89_acpi_dsm_func { RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP = 7, RTW89_ACPI_DSM_FUNC_REG_RULES_EN = 10, + RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP = 11, }; enum rtw89_acpi_conf_unii4 { @@ -68,6 +69,19 @@ struct rtw89_acpi_policy_6ghz_sp { u8 rsvd; } __packed; +enum rtw89_acpi_conf_6ghz_vlp { + RTW89_ACPI_CONF_6GHZ_VLP_US = BIT(0), + RTW89_ACPI_CONF_6GHZ_VLP_CA = BIT(1), +}; + +struct rtw89_acpi_policy_6ghz_vlp { + u8 signature[4]; + u8 revision; + u8 override; + u8 conf; + u8 rsvd; +} __packed; + struct rtw89_acpi_policy_tas { u8 signature[4]; u8 revision; @@ -93,6 +107,7 @@ struct rtw89_acpi_dsm_result { /* caller needs to free it after using */ struct rtw89_acpi_policy_6ghz *policy_6ghz; struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp; + struct rtw89_acpi_policy_6ghz_vlp *policy_6ghz_vlp; struct rtw89_acpi_policy_tas *policy_tas; struct rtw89_acpi_policy_reg_rules *policy_reg_rules; } u; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 1d8f89e83c9a..8c53c5db0cbc 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5386,6 +5386,7 @@ struct rtw89_regulatory_info { DECLARE_BITMAP(block_unii4, RTW89_REGD_MAX_COUNTRY_NUM); DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM); DECLARE_BITMAP(block_6ghz_sp, RTW89_REGD_MAX_COUNTRY_NUM); + DECLARE_BITMAP(block_6ghz_vlp, RTW89_REGD_MAX_COUNTRY_NUM); }; enum rtw89_ifs_clm_application { diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 42678ff2a045..58582f8d2b74 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -521,6 +521,55 @@ static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev) kfree(ptr); } +static void rtw89_regd_setup_policy_6ghz_vlp(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_acpi_policy_6ghz_vlp *ptr = NULL; + struct rtw89_acpi_dsm_result res = {}; + bool enable; + u8 index; + int ret; + u8 val; + + /* By default, allow 6 GHz VLP on all countries except US and CA. */ + val = ~(RTW89_ACPI_CONF_6GHZ_VLP_US | RTW89_ACPI_CONF_6GHZ_VLP_CA); + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP, &res); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval policy 6ghz-vlp: %d\n", ret); + goto bottom; + } + + ptr = res.u.policy_6ghz_vlp; + + switch (ptr->override) { + default: + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "%s: unknown override case: %d\n", __func__, + ptr->override); + fallthrough; + case 0: + break; + case 1: + val = ptr->conf; + break; + } + +bottom: + index = rtw89_regd_get_index_by_name(rtwdev, "US"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_6GHZ_VLP_US); + if (!enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + set_bit(index, regulatory->block_6ghz_vlp); + + index = rtw89_regd_get_index_by_name(rtwdev, "CA"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_6GHZ_VLP_CA); + if (!enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + set_bit(index, regulatory->block_6ghz_vlp); + + kfree(ptr); +} + static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) { const struct rtw89_chip_info *chip = rtwdev->chip; @@ -564,6 +613,7 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) if (regd_allow_6ghz) { rtw89_regd_setup_policy_6ghz(rtwdev); rtw89_regd_setup_policy_6ghz_sp(rtwdev); + rtw89_regd_setup_policy_6ghz_vlp(rtwdev); return; } @@ -1059,7 +1109,16 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool active, unsigned int *changed) { + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_regd *regd = regulatory->regd; + bool blocked[NUM_OF_RTW89_REG_6GHZ_POWER] = {}; + u8 index = rtw89_regd_get_index(rtwdev, regd); struct ieee80211_bss_conf *bss_conf; + bool dflt = false; + + if (index == RTW89_REGD_MAX_COUNTRY_NUM || + test_bit(index, regulatory->block_6ghz_vlp)) + blocked[RTW89_REG_6GHZ_POWER_VLP] = true; rcu_read_lock(); @@ -1078,6 +1137,7 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, break; default: rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + dflt = true; break; } } else { @@ -1086,6 +1146,14 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, rcu_read_unlock(); + if (!dflt && blocked[rtwvif_link->reg_6ghz_power]) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "%c%c 6 GHz power type-%u is blocked by policy\n", + regd->alpha2[0], regd->alpha2[1], + rtwvif_link->reg_6ghz_power); + return -EINVAL; + } + *changed += __rtw89_reg_6ghz_power_recalc(rtwdev); return 0; } From ad22869bc5a64a5a51f27951ced772499b2bf4bc Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:10 +0800 Subject: [PATCH 33/58] wifi: rtw89: mcc: add H2C command to support different PD level in MCC Packet detection(PD) lower bound is the threshold for sensing packet, and it is dynamically calculated based on RSSI. In MCC, the two interfaces have different RSSI values, so it is necessary to set different values to ensure packets can be received. Therefore, add H2C command to let firmware to switch PD lower bound when MCC mode. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 25 +++ drivers/net/wireless/realtek/rtw89/chan.h | 5 + drivers/net/wireless/realtek/rtw89/fw.c | 53 ++++++ drivers/net/wireless/realtek/rtw89/fw.h | 25 +++ drivers/net/wireless/realtek/rtw89/phy.c | 188 ++++++++++++++++++---- 5 files changed, 265 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 6f10235647a1..32cd09f77e37 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -2371,6 +2371,7 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP); rtw89_mcc_stop_beacon_noa(rtwdev); + rtw89_fw_h2c_mcc_dig(rtwdev, RTW89_CHANCTX_0, 0, 0, false); rtw89_mcc_prepare(rtwdev, false); } @@ -2622,6 +2623,30 @@ static void rtw89_mcc_update_limit(struct rtw89_dev *rtwdev) rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_lmt_iterator, NULL); } +static int rtw89_mcc_get_links_iterator(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *mcc_role, + unsigned int ordered_idx, + void *data) +{ + struct rtw89_mcc_links_info *info = data; + + info->links[ordered_idx] = mcc_role->rtwvif_link; + return 0; +} + +void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info) +{ + enum rtw89_entity_mode mode; + + memset(info, 0, sizeof(*info)); + + mode = rtw89_get_entity_mode(rtwdev); + if (unlikely(mode != RTW89_ENTITY_MODE_MCC)) + return; + + rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_get_links_iterator, info); +} + void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work) { struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 57355cb3d765..0e2ffb920455 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -178,6 +178,11 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, #define rtw89_mgnt_chan_get(rtwdev, link_index) \ __rtw89_mgnt_chan_get(rtwdev, __func__, link_index) +struct rtw89_mcc_links_info { + struct rtw89_vif_link *links[NUM_OF_RTW89_MCC_ROLES]; +}; + +void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info); void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work); int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index c613431e754f..3a3109ab7111 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5985,6 +5985,59 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_fw_h2c_rf_ntfy_mcc); +int rtw89_fw_h2c_mcc_dig(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx chanctx_idx, + u8 mcc_role_idx, u8 pd_val, bool en) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); + const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; + struct rtw89_h2c_mcc_dig *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c mcc_dig\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_mcc_dig *)skb->data; + + h2c->w0 = le32_encode_bits(1, RTW89_H2C_MCC_DIG_W0_REG_CNT) | + le32_encode_bits(en, RTW89_H2C_MCC_DIG_W0_DM_EN) | + le32_encode_bits(mcc_role_idx, RTW89_H2C_MCC_DIG_W0_IDX) | + le32_encode_bits(1, RTW89_H2C_MCC_DIG_W0_SET) | + le32_encode_bits(1, RTW89_H2C_MCC_DIG_W0_PHY0_EN) | + le32_encode_bits(chan->channel, RTW89_H2C_MCC_DIG_W0_CENTER_CH) | + le32_encode_bits(chan->band_type, RTW89_H2C_MCC_DIG_W0_BAND_TYPE); + h2c->w1 = le32_encode_bits(dig_regs->seg0_pd_reg, + RTW89_H2C_MCC_DIG_W1_ADDR_LSB) | + le32_encode_bits(dig_regs->seg0_pd_reg >> 8, + RTW89_H2C_MCC_DIG_W1_ADDR_MSB) | + le32_encode_bits(dig_regs->pd_lower_bound_mask, + RTW89_H2C_MCC_DIG_W1_BMASK_LSB) | + le32_encode_bits(dig_regs->pd_lower_bound_mask >> 8, + RTW89_H2C_MCC_DIG_W1_BMASK_MSB); + h2c->w2 = le32_encode_bits(pd_val, RTW89_H2C_MCC_DIG_W2_VAL_LSB); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_DM, + H2C_FUNC_FW_MCC_DIG, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { const struct rtw89_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 24d2e8b0d079..22b2b2a716ef 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4341,6 +4341,7 @@ enum rtw89_mrc_h2c_func { #define H2C_FUNC_OUTSRC_RA_MACIDCFG 0x0 #define H2C_CL_OUTSRC_DM 0x2 +#define H2C_FUNC_FW_MCC_DIG 0x6 #define H2C_FUNC_FW_LPS_CH_INFO 0xb #define H2C_FUNC_FW_LPS_ML_CMN_INFO 0xe @@ -4378,6 +4379,27 @@ struct rtw89_fw_h2c_rf_get_mccch_v0 { __le32 current_band_type; } __packed; +struct rtw89_h2c_mcc_dig { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; + +#define RTW89_H2C_MCC_DIG_W0_REG_CNT GENMASK(7, 0) +#define RTW89_H2C_MCC_DIG_W0_DM_EN BIT(8) +#define RTW89_H2C_MCC_DIG_W0_IDX GENMASK(10, 9) +#define RTW89_H2C_MCC_DIG_W0_SET BIT(11) +#define RTW89_H2C_MCC_DIG_W0_PHY0_EN BIT(12) +#define RTW89_H2C_MCC_DIG_W0_PHY1_EN BIT(13) +#define RTW89_H2C_MCC_DIG_W0_CENTER_CH GENMASK(23, 16) +#define RTW89_H2C_MCC_DIG_W0_BAND_TYPE GENMASK(31, 24) +#define RTW89_H2C_MCC_DIG_W1_ADDR_LSB GENMASK(7, 0) +#define RTW89_H2C_MCC_DIG_W1_ADDR_MSB GENMASK(15, 8) +#define RTW89_H2C_MCC_DIG_W1_BMASK_LSB GENMASK(23, 16) +#define RTW89_H2C_MCC_DIG_W1_BMASK_MSB GENMASK(31, 24) +#define RTW89_H2C_MCC_DIG_W2_VAL_LSB GENMASK(7, 0) +#define RTW89_H2C_MCC_DIG_W2_VAL_MSB GENMASK(15, 8) + #define NUM_OF_RTW89_FW_RFK_PATH 2 #define NUM_OF_RTW89_FW_RFK_TBL 3 @@ -4774,6 +4796,9 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_mcc_dig(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx chanctx_idx, + u8 mcc_role_idx, u8 pd_val, bool en); int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, enum rtw89_tssi_mode tssi_mode); int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 7d005db211e5..a7412d139902 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -6316,18 +6316,13 @@ static void rtw89_phy_dig_config_igi(struct rtw89_dev *rtwdev, } } -static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, - struct rtw89_bb_ctx *bb, - u8 rssi, bool enable) +static u8 rtw89_phy_dig_cal_under_region(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + const struct rtw89_chan *chan) { - const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, bb->phy_idx); - const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; enum rtw89_bandwidth cbw = chan->band_width; struct rtw89_dig_info *dig = &bb->dig; - u8 final_rssi = 0, under_region = dig->pd_low_th_ofst; - u8 ofdm_cca_th; - s8 cck_cca_th; - u32 pd_val = 0; + u8 under_region = dig->pd_low_th_ofst; if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) under_region += PD_TH_SB_FLTR_CMP_VAL; @@ -6349,6 +6344,20 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, break; } + return under_region; +} + +static u32 __rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + u8 rssi, bool enable, + const struct rtw89_chan *chan) +{ + struct rtw89_dig_info *dig = &bb->dig; + u8 ofdm_cca_th, under_region; + u8 final_rssi; + u32 pd_val; + + under_region = rtw89_phy_dig_cal_under_region(rtwdev, bb, chan); dig->dyn_pd_th_max = dig->igi_rssi; final_rssi = min_t(u8, rssi, dig->igi_rssi); @@ -6361,10 +6370,27 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, "igi=%d, ofdm_ccaTH=%d, backoff=%d, PD_low=%d\n", final_rssi, ofdm_cca_th, under_region, pd_val); } else { + pd_val = 0; rtw89_debug(rtwdev, RTW89_DBG_DIG, "Dynamic PD th disabled, Set PD_low_bd=0\n"); } + return pd_val; +} + +static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + u8 rssi, bool enable) +{ + const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, bb->phy_idx); + const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; + struct rtw89_dig_info *dig = &bb->dig; + u8 final_rssi, under_region = dig->pd_low_th_ofst; + s8 cck_cca_th; + u32 pd_val; + + pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, rssi, enable, chan); + rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx); rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, @@ -6373,6 +6399,8 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, if (!rtwdev->hal.support_cckpd) return; + final_rssi = min_t(u8, rssi, dig->igi_rssi); + under_region = rtw89_phy_dig_cal_under_region(rtwdev, bb, chan); cck_cca_th = max_t(s8, final_rssi - under_region, CCKPD_TH_MIN_RSSI); pd_val = (u32)(cck_cca_th - IGI_RSSI_MAX); @@ -6400,32 +6428,12 @@ void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) #define IGI_RSSI_MIN 10 #define ABS_IGI_MIN 0xc -static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +static +void rtw89_phy_cal_igi_fa_rssi(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) { struct rtw89_dig_info *dig = &bb->dig; - bool is_linked = rtwdev->total_sta_assoc > 0; u8 igi_min; - if (unlikely(dig->bypass_dig)) { - dig->bypass_dig = false; - return; - } - - rtw89_debug(rtwdev, RTW89_DBG_DIG, "BB-%d dig track\n", bb->phy_idx); - - rtw89_phy_dig_update_rssi_info(rtwdev, bb); - - if (!dig->is_linked_pre && is_linked) { - rtw89_debug(rtwdev, RTW89_DBG_DIG, "First connected\n"); - rtw89_phy_dig_update_para(rtwdev, bb); - dig->igi_fa_rssi = dig->igi_rssi; - } else if (dig->is_linked_pre && !is_linked) { - rtw89_debug(rtwdev, RTW89_DBG_DIG, "First disconnected\n"); - rtw89_phy_dig_update_para(rtwdev, bb); - dig->igi_fa_rssi = dig->igi_rssi; - } - dig->is_linked_pre = is_linked; - rtw89_phy_dig_igi_offset_by_env(rtwdev, bb); igi_min = max_t(int, dig->igi_rssi - IGI_RSSI_MIN, 0); @@ -6439,6 +6447,124 @@ static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) } else { dig->igi_fa_rssi = dig->dyn_igi_max; } +} + +struct rtw89_phy_iter_mcc_dig { + struct rtw89_vif_link *rtwvif_link; + bool has_sta; + u8 rssi_min; +}; + +static void rtw89_phy_set_mcc_dig(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_bb_ctx *bb, + u8 rssi_min, u8 mcc_role_idx, + bool is_linked) +{ + struct rtw89_dig_info *dig = &bb->dig; + const struct rtw89_chan *chan; + u8 pd_val; + + if (is_linked) { + dig->igi_rssi = rssi_min >> 1; + dig->igi_fa_rssi = dig->igi_rssi; + } else { + rtw89_debug(rtwdev, RTW89_DBG_DIG, "RSSI update : NO Link\n"); + dig->igi_rssi = rssi_nolink; + dig->igi_fa_rssi = dig->igi_rssi; + } + + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + rtw89_phy_cal_igi_fa_rssi(rtwdev, bb); + pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, dig->igi_fa_rssi, + is_linked, chan); + rtw89_fw_h2c_mcc_dig(rtwdev, rtwvif_link->chanctx_idx, + mcc_role_idx, pd_val, true); + + rtw89_debug(rtwdev, RTW89_DBG_DIG, + "MCC chanctx_idx %d chan %d rssi %d pd_val %d", + rtwvif_link->chanctx_idx, chan->primary_channel, + dig->igi_rssi, pd_val); +} + +static void rtw89_phy_set_mcc_dig_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_phy_iter_mcc_dig *mcc_dig = (struct rtw89_phy_iter_mcc_dig *)data; + unsigned int link_id = mcc_dig->rtwvif_link->link_id; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; + + if (rtwsta->rtwvif != mcc_dig->rtwvif_link->rtwvif) + return; + + rtwsta_link = rtwsta->links[link_id]; + if (!rtwsta_link) + return; + + mcc_dig->has_sta = true; + if (ewma_rssi_read(&rtwsta_link->avg_rssi) < mcc_dig->rssi_min) + mcc_dig->rssi_min = ewma_rssi_read(&rtwsta_link->avg_rssi); +} + +static void rtw89_phy_dig_mcc(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +{ + struct rtw89_phy_iter_mcc_dig mcc_dig; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_mcc_links_info info; + int i; + + rtw89_mcc_get_links(rtwdev, &info); + for (i = 0; i < ARRAY_SIZE(info.links); i++) { + rtwvif_link = info.links[i]; + if (!rtwvif_link) + continue; + + memset(&mcc_dig, 0, sizeof(mcc_dig)); + mcc_dig.rtwvif_link = rtwvif_link; + mcc_dig.has_sta = false; + mcc_dig.rssi_min = U8_MAX; + ieee80211_iterate_stations_atomic(rtwdev->hw, + rtw89_phy_set_mcc_dig_iter, + &mcc_dig); + + rtw89_phy_set_mcc_dig(rtwdev, rtwvif_link, bb, + mcc_dig.rssi_min, i, mcc_dig.has_sta); + } +} + +static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +{ + struct rtw89_dig_info *dig = &bb->dig; + bool is_linked = rtwdev->total_sta_assoc > 0; + enum rtw89_entity_mode mode; + + if (unlikely(dig->bypass_dig)) { + dig->bypass_dig = false; + return; + } + + rtw89_debug(rtwdev, RTW89_DBG_DIG, "BB-%d dig track\n", bb->phy_idx); + + rtw89_phy_dig_update_rssi_info(rtwdev, bb); + + mode = rtw89_get_entity_mode(rtwdev); + if (mode == RTW89_ENTITY_MODE_MCC) { + rtw89_phy_dig_mcc(rtwdev, bb); + return; + } + + if (!dig->is_linked_pre && is_linked) { + rtw89_debug(rtwdev, RTW89_DBG_DIG, "First connected\n"); + rtw89_phy_dig_update_para(rtwdev, bb); + dig->igi_fa_rssi = dig->igi_rssi; + } else if (dig->is_linked_pre && !is_linked) { + rtw89_debug(rtwdev, RTW89_DBG_DIG, "First disconnected\n"); + rtw89_phy_dig_update_para(rtwdev, bb); + dig->igi_fa_rssi = dig->igi_rssi; + } + dig->is_linked_pre = is_linked; + + rtw89_phy_cal_igi_fa_rssi(rtwdev, bb); rtw89_debug(rtwdev, RTW89_DBG_DIG, "rssi=%03d, dyn_joint(max,min)=(%d,%d), final_rssi=%d\n", From 9126020ab03c60053819c19294f46fc6ce11b52e Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:11 +0800 Subject: [PATCH 34/58] wifi: rtw89: add DIG suspend/resume flow when scan and connection The PD lower bound set after one interface is connected, If second interface needs to connect, packets might not be detected because the PD lower bound is too high. Therefore, a DIG suspend/resume flow is added to decrease the PD lower bound during scanning or connection, and the original PD level is resumed afterward. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 4 ++ drivers/net/wireless/realtek/rtw89/core.c | 2 + drivers/net/wireless/realtek/rtw89/core.h | 2 + drivers/net/wireless/realtek/rtw89/fw.c | 2 + drivers/net/wireless/realtek/rtw89/phy.c | 50 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 2 + 6 files changed, 62 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 32cd09f77e37..1277b1af2a4c 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -7,6 +7,7 @@ #include "debug.h" #include "fw.h" #include "mac.h" +#include "phy.h" #include "ps.h" #include "sar.h" #include "util.h" @@ -2281,6 +2282,7 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START); rtw89_mcc_start_beacon_noa(rtwdev); + rtw89_phy_dig_suspend(rtwdev); rtw89_mcc_prepare(rtwdev, true); return 0; @@ -2372,6 +2374,7 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, rtw89_mcc_stop_beacon_noa(rtwdev); rtw89_fw_h2c_mcc_dig(rtwdev, RTW89_CHANCTX_0, 0, 0, false); + rtw89_phy_dig_resume(rtwdev, true); rtw89_mcc_prepare(rtwdev, false); } @@ -2715,6 +2718,7 @@ void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev, return; case RTW89_ENTITY_MODE_MCC_PREPARE: delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE); + rtw89_phy_dig_suspend(rtwdev); break; case RTW89_ENTITY_MODE_MCC: delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC); diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 23d050041583..da82a88cce98 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4082,6 +4082,7 @@ int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev, &rtwsta_link->tx_retry); rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, 60); } + rtw89_phy_dig_suspend(rtwdev); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta_link->mac_id, false); if (ret) { @@ -4270,6 +4271,7 @@ int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, if (vif->p2p) rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, rtwsta_link->tx_retry); + rtw89_phy_dig_resume(rtwdev, false); } rtw89_assoc_link_set(rtwsta_link); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 8c53c5db0cbc..e0992c12c4ca 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5243,8 +5243,10 @@ struct rtw89_dig_info { s8 tia_gain_a[TIA_GAIN_NUM]; s8 tia_gain_g[TIA_GAIN_NUM]; s8 *tia_gain; + u32 bak_dig; bool is_linked_pre; bool bypass_dig; + bool pause_dig; }; enum rtw89_multi_cfo_mode { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 3a3109ab7111..ae38ea640384 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -7798,6 +7798,7 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rx_fltr); rtw89_chanctx_pause(rtwdev, &pause_parm); + rtw89_phy_dig_suspend(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) rtw89_hw_scan_update_beacon_noa(rtwdev, req); @@ -7831,6 +7832,7 @@ static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data) ieee80211_wake_queues(rtwdev->hw); rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, true); rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); + rtw89_phy_dig_resume(rtwdev, true); rtw89_hw_scan_cleanup(rtwdev, rtwvif_link); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index a7412d139902..d607577b353c 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -6390,6 +6390,7 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u32 pd_val; pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, rssi, enable, chan); + dig->bak_dig = pd_val; rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx); @@ -6532,6 +6533,52 @@ static void rtw89_phy_dig_mcc(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) } } +static void rtw89_phy_dig_ctrl(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb, + bool pause_dig, bool restore) +{ + const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; + struct rtw89_dig_info *dig = &bb->dig; + bool en_dig; + u32 pd_val; + + if (dig->pause_dig == pause_dig) + return; + + if (pause_dig) { + en_dig = false; + pd_val = 0; + } else { + en_dig = rtwdev->total_sta_assoc > 0; + pd_val = restore ? dig->bak_dig : 0; + } + + rtw89_debug(rtwdev, RTW89_DBG_DIG, "%s <%s> PD_low=%d", __func__, + pause_dig ? "suspend" : "resume", pd_val); + + rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, + dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx); + rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, + dig_regs->pd_spatial_reuse_en, en_dig, bb->phy_idx); + + dig->pause_dig = pause_dig; +} + +void rtw89_phy_dig_suspend(struct rtw89_dev *rtwdev) +{ + struct rtw89_bb_ctx *bb; + + rtw89_for_each_active_bb(rtwdev, bb) + rtw89_phy_dig_ctrl(rtwdev, bb, true, false); +} + +void rtw89_phy_dig_resume(struct rtw89_dev *rtwdev, bool restore) +{ + struct rtw89_bb_ctx *bb; + + rtw89_for_each_active_bb(rtwdev, bb) + rtw89_phy_dig_ctrl(rtwdev, bb, false, restore); +} + static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) { struct rtw89_dig_info *dig = &bb->dig; @@ -6553,6 +6600,9 @@ static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) return; } + if (unlikely(dig->pause_dig)) + return; + if (!dig->is_linked_pre && is_linked) { rtw89_debug(rtwdev, RTW89_DBG_DIG, "First connected\n"); rtw89_phy_dig_update_para(rtwdev, bb); diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 63cc33c16c9a..dc156376d951 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -1010,6 +1010,8 @@ void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 val); void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb); void rtw89_phy_dig(struct rtw89_dev *rtwdev); +void rtw89_phy_dig_suspend(struct rtw89_dev *rtwdev); +void rtw89_phy_dig_resume(struct rtw89_dev *rtwdev, bool restore); void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev); void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu); From 025e39032df5cc5c110de3693f63e81cf49968be Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:12 +0800 Subject: [PATCH 35/58] wifi: rtw89: mcc: enlarge GO NoA duration to cover channel switching time MCC require time to switch channel when changing timeslot. If GC TX nulldata 0 while GO is switching channel, GO can't receive it. Therefore, enlarge the GO NoA duration to cover the channel switching time. However, the enlarged NoA duration might cause GC's timeslot less than minimum of RX beacon time. Therefore, adjust strict and anchor pattern condition to avoid it. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 7 ++++--- drivers/net/wireless/realtek/rtw89/chan.h | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 1277b1af2a4c..e5ef4f6ab5ca 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1116,7 +1116,7 @@ static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ref = &mcc->role_ref; struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_config *config = &mcc->config; - u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME; + u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_SWITCH_CH_TIME; u16 min_toa = RTW89_MCC_MIN_RX_BCN_TIME; u16 bcn_ofst = config->beacon_offset; s16 upper_toa_ref, lower_toa_ref; @@ -1272,11 +1272,11 @@ static int __rtw89_mcc_calc_pattern_anchor(struct rtw89_dev *rtwdev, u16 bcn_ofst = config->beacon_offset; bool small_bcn_ofst; - if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME) + if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) small_bcn_ofst = true; else if (bcn_ofst < aux->duration - aux->limit.max_toa) small_bcn_ofst = true; - else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME) + else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) small_bcn_ofst = false; else return -EPERM; @@ -2171,6 +2171,7 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable) rtw89_p2p_noa_renew(rtwvif_go); if (enable) { + duration += RTW89_MCC_SWITCH_CH_TIME; noa_desc.start_time = cpu_to_le32(start_time); noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(interval)); noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(duration)); diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 0e2ffb920455..9a62b7c98b83 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -18,6 +18,7 @@ #define RTW89_MCC_EARLY_RX_BCN_TIME 5 #define RTW89_MCC_MIN_RX_BCN_TIME 10 #define RTW89_MCC_DFLT_BCN_OFST_TIME 40 +#define RTW89_MCC_SWITCH_CH_TIME 3 #define RTW89_MCC_PROBE_TIMEOUT 100 #define RTW89_MCC_PROBE_MAX_TRIES 3 @@ -28,6 +29,9 @@ #define RTW89_MCC_MIN_STA_DURATION \ (RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME) +#define RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME \ + (RTW89_MCC_MIN_RX_BCN_TIME + RTW89_MCC_SWITCH_CH_TIME) + #define RTW89_MCC_DFLT_GROUP 0 #define RTW89_MCC_NEXT_GROUP(cur) (((cur) + 1) % 4) From 6332feafe37fdd0a336ab01b42fdfb5e6b8ee083 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:13 +0800 Subject: [PATCH 36/58] wifi: rtw89: mcc: when MCC stop forcing to stay at GO role MCC stop might triggered by scan, and need to force to stay at GO role to keep TX beacon. Also, AX chips need to TX more 3 beacons to ensure GC can receive once NoA beacon before scan when GC in courtesy mode. BE chips no needs to TX 3 more beacon because it can TX beacon every 200TU during scan, even GC in courtesy mode can receive beacon every 600TU. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 8 ++++++++ drivers/net/wireless/realtek/rtw89/core.h | 3 ++- drivers/net/wireless/realtek/rtw89/fw.c | 21 ++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/mac.c | 1 + drivers/net/wireless/realtek/rtw89/wow.c | 2 +- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index e5ef4f6ab5ca..6c80e08ae99d 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -2336,9 +2336,11 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_mcc_info *mcc = &rtwdev->mcc; struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_stop_sel sel = { .hint.target = pause ? pause->trigger : NULL, }; + bool rsn_scan; int ret; if (!pause) { @@ -2346,6 +2348,12 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES); } + rsn_scan = pause && pause->rsn == RTW89_CHANCTX_PAUSE_REASON_HW_SCAN; + if (rsn_scan && ref->is_go) + sel.hint.target = ref->rtwvif_link; + else if (rsn_scan && aux->is_go) + sel.hint.target = aux->rtwvif_link; + /* by default, stop at ref */ rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_stop_sel_iterator, &sel); if (!sel.filled) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index e0992c12c4ca..c003a31477bb 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3860,7 +3860,7 @@ struct rtw89_scan_option { u16 slow_pd; u16 norm_cy; u8 opch_end; - u16 delay; + u16 delay; /* in unit of ms */ u64 prohib_chan; enum rtw89_phy_idx band; enum rtw89_scan_be_operation operation; @@ -5550,6 +5550,7 @@ struct rtw89_hw_scan_info { struct rtw89_hw_scan_extra_op extra_op; bool connected; bool abort; + u16 delay; /* in unit of ms */ }; enum rtw89_phy_bb_gain_band { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index ae38ea640384..1fd88dc7da85 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5583,7 +5583,6 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, return 0; } -#define RTW89_SCAN_DELAY_TSF_UNIT 1000000 int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, struct rtw89_vif_link *rtwvif_link, @@ -5615,7 +5614,7 @@ int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, scan_mode = RTW89_SCAN_IMMEDIATE; } else { scan_mode = RTW89_SCAN_DELAY; - tsf += (u64)option->delay * RTW89_SCAN_DELAY_TSF_UNIT; + tsf += (u64)option->delay * 1000; } } @@ -5781,7 +5780,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, RTW89_H2C_SCANOFLD_BE_W4_PROBE_5G) | le32_encode_bits(probe_id[NL80211_BAND_6GHZ], RTW89_H2C_SCANOFLD_BE_W4_PROBE_6G) | - le32_encode_bits(option->delay, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START); + le32_encode_bits(option->delay / 1000, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START); h2c->w5 = le32_encode_bits(option->mlo_mode, RTW89_H2C_SCANOFLD_BE_W5_MLO_MODE); @@ -6826,6 +6825,7 @@ static void rtw89_hw_scan_cleanup(struct rtw89_dev *rtwdev, scan_info->scanning_vif = NULL; scan_info->abort = false; scan_info->connected = false; + scan_info->delay = 0; } static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev, @@ -7628,9 +7628,22 @@ static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev, u16 tu) { struct ieee80211_p2p_noa_desc noa_desc = {}; + struct ieee80211_bss_conf *bss_conf; + u16 beacon_int; u64 tsf; int ret; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + beacon_int = bss_conf->beacon_int; + + rcu_read_unlock(); + + tu += beacon_int * 3; + if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) + rtwdev->scan_info.delay = ieee80211_tu_to_usec(beacon_int * 3) / 1000; + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); if (ret) { rtw89_warn(rtwdev, "%s: failed to get tsf\n", __func__); @@ -7770,6 +7783,7 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, rtwdev->scan_info.connected = rtw89_is_any_vif_connected_or_connecting(rtwdev); rtwdev->scan_info.scanning_vif = rtwvif_link; rtwdev->scan_info.abort = false; + rtwdev->scan_info.delay = 0; rtwvif->scan_ies = &scan_req->ies; rtwvif->scan_req = req; @@ -7912,6 +7926,7 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, connected = rtwdev->scan_info.connected; opt.enable = enable; opt.target_ch_mode = connected; + opt.delay = rtwdev->scan_info.delay; if (enable) { ret = mac->add_chan_list(rtwdev, rtwvif_link); if (ret) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index ff4335ef4033..37b113e3bd26 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5049,6 +5049,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, if (rtwvif_link && rtwvif->scan_req && !list_empty(&rtwdev->scan_info.chan_list)) { + rtwdev->scan_info.delay = 0; ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true); if (ret) { rtw89_hw_scan_abort(rtwdev, rtwvif_link); diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index c935d6683d83..4f759c75389e 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -1477,7 +1477,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) opt.enable = enable; opt.repeat = RTW89_SCAN_NORMAL; opt.norm_pd = max(interval, 1) * 10; /* in unit of 100ms */ - opt.delay = max(rtw_wow->nd_config->delay, 1); + opt.delay = max(rtw_wow->nd_config->delay, 1) * 1000; if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { opt.operation = enable ? RTW89_SCAN_OP_START : RTW89_SCAN_OP_STOP; From d0b87d9eaf76703b81e511d05db29a5e7ef6c3e0 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:14 +0800 Subject: [PATCH 37/58] wifi: rtw89: extend HW scan of WiFi 7 chips for extra OP chan when concurrency HW scan of WiFi 7 chips supports multiple op channel configurations. When concurrency, fill two channels info to HW scan to avoid packet lost. However, the OP chan timing is arranged by FW, and the actual stay period depends on AP. It's hard to calculate total scan time for once NoA in advance. Therefore, change the scan back to GO OP channel every 200TU and TX beacon to ensure GC doesn't beacon loss. Additionally, add a period NoA with large duration to ensure GC doesn't TX packet during GO scanning and can still listen beacon at TBTT to update the new NoA info after scan complete. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 + drivers/net/wireless/realtek/rtw89/fw.c | 88 ++++++++++++++++++----- drivers/net/wireless/realtek/rtw89/fw.h | 1 + 3 files changed, 73 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c003a31477bb..2faf0889f7df 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5539,7 +5539,9 @@ struct rtw89_early_h2c { struct rtw89_hw_scan_extra_op { bool set; u8 macid; + u8 port; struct rtw89_chan chan; + struct rtw89_vif_link *rtwvif_link; }; struct rtw89_hw_scan_info { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 1fd88dc7da85..20b7b4b15450 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5700,26 +5700,47 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, { struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_h2c_scanofld_be_macc_role *macc_role; + struct rtw89_hw_scan_extra_op scan_op[2] = {}; struct rtw89_chan *op = &scan_info->op_chan; struct rtw89_h2c_scanofld_be_opch *opch; struct rtw89_pktofld_info *pkt_info; struct rtw89_h2c_scanofld_be *h2c; + struct ieee80211_vif *vif; struct sk_buff *skb; u8 macc_role_size = sizeof(*macc_role) * option->num_macc_role; u8 opch_size = sizeof(*opch) * option->num_opch; + enum rtw89_scan_be_opmode opmode; u8 probe_id[NUM_NL80211_BANDS]; u8 scan_offload_ver = U8_MAX; u8 cfg_len = sizeof(*h2c); unsigned int cond; + u8 ap_idx = U8_MAX; u8 ver = U8_MAX; + u8 policy_val; void *ptr; + u8 txbcn; int ret; u32 len; u8 i; + scan_op[0].macid = rtwvif_link->mac_id; + scan_op[0].port = rtwvif_link->port; + scan_op[0].chan = *op; + vif = rtwvif_to_vif(rtwvif_link->rtwvif); + if (vif->type == NL80211_IFTYPE_AP) + ap_idx = 0; + + if (ext->set) { + scan_op[1] = *ext; + vif = rtwvif_to_vif(ext->rtwvif_link->rtwvif); + if (vif->type == NL80211_IFTYPE_AP) + ap_idx = 1; + } + rtw89_scan_get_6g_disabled_chan(rtwdev, option); if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw)) { @@ -5822,29 +5843,35 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, } for (i = 0; i < option->num_opch; i++) { + bool is_ap_idx = i == ap_idx; + + opmode = is_ap_idx ? RTW89_SCAN_OPMODE_TBTT : RTW89_SCAN_OPMODE_INTV; + policy_val = is_ap_idx ? 2 : RTW89_OFF_CHAN_TIME / 10; + txbcn = is_ap_idx ? 1 : 0; + opch = ptr; - opch->w0 = le32_encode_bits(rtwvif_link->mac_id, + opch->w0 = le32_encode_bits(scan_op[i].macid, RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID) | le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND) | - le32_encode_bits(rtwvif_link->port, + le32_encode_bits(scan_op[i].port, RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) | - le32_encode_bits(RTW89_SCAN_OPMODE_INTV, + le32_encode_bits(opmode, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) | le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_OPCH_W0_TXNULL) | - le32_encode_bits(RTW89_OFF_CHAN_TIME / 10, + le32_encode_bits(policy_val, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY_VAL); - opch->w1 = le32_encode_bits(op->band_type, + opch->w1 = le32_encode_bits(scan_op[i].chan.band_type, RTW89_H2C_SCANOFLD_BE_OPCH_W1_CH_BAND) | - le32_encode_bits(op->band_width, + le32_encode_bits(scan_op[i].chan.band_width, RTW89_H2C_SCANOFLD_BE_OPCH_W1_BW) | le32_encode_bits(0x3, RTW89_H2C_SCANOFLD_BE_OPCH_W1_NOTIFY) | - le32_encode_bits(op->primary_channel, + le32_encode_bits(scan_op[i].chan.primary_channel, RTW89_H2C_SCANOFLD_BE_OPCH_W1_PRI_CH) | - le32_encode_bits(op->channel, + le32_encode_bits(scan_op[i].chan.channel, RTW89_H2C_SCANOFLD_BE_OPCH_W1_CENTRAL_CH); opch->w2 = le32_encode_bits(0, @@ -5852,7 +5879,9 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF) | le32_encode_bits(rtw89_is_mlo_1_1(rtwdev) ? 1 : 2, - RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS); + RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS) | + le32_encode_bits(txbcn, + RTW89_H2C_SCANOFLD_BE_OPCH_W2_TXBCN); opch->w3 = le32_encode_bits(RTW89_SCANOFLD_PKT_NONE, RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0) | @@ -7625,7 +7654,7 @@ static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev, static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, - u16 tu) + u16 tu, bool scan) { struct ieee80211_p2p_noa_desc noa_desc = {}; struct ieee80211_bss_conf *bss_conf; @@ -7651,17 +7680,24 @@ static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev, } noa_desc.start_time = cpu_to_le32(tsf); - noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(tu)); - noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(tu)); - noa_desc.count = 1; + if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) { + noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(tu)); + noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(tu)); + noa_desc.count = 1; + } else { + noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(20000)); + noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(20000)); + noa_desc.count = 255; + } rtw89_p2p_noa_renew(rtwvif_link); - rtw89_p2p_noa_append(rtwvif_link, &noa_desc); + if (scan) + rtw89_p2p_noa_append(rtwvif_link, &noa_desc); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); } -static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, - const struct cfg80211_scan_request *req) +static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, bool scan) { const struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; const struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; @@ -7676,6 +7712,9 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, lockdep_assert_wiphy(rtwdev->hw->wiphy); + if (!scan) + goto update; + list_for_each_safe(pos, tmp, &scan_info->chan_list) { switch (chip->chip_gen) { case RTW89_CHIP_AX: @@ -7699,6 +7738,7 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, return; } +update: list_for_each_entry(rtwvif, &mgnt->active_list, mgnt_entry) { unsigned int link_id; @@ -7707,7 +7747,8 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, continue; rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) - rtw89_hw_scan_update_link_beacon_noa(rtwdev, rtwvif_link, tu); + rtw89_hw_scan_update_link_beacon_noa(rtwdev, rtwvif_link, + tu, scan); } } @@ -7742,7 +7783,9 @@ static void rtw89_hw_scan_set_extra_op_info(struct rtw89_dev *rtwdev, *ext = (struct rtw89_hw_scan_extra_op){ .set = true, .macid = tmp_link->mac_id, + .port = tmp_link->port, .chan = *tmp_chan, + .rtwvif_link = tmp_link, }; rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, @@ -7815,7 +7858,7 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, rtw89_phy_dig_suspend(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) - rtw89_hw_scan_update_beacon_noa(rtwdev, req); + rtw89_hw_scan_update_beacon_noa(rtwdev, true); return 0; } @@ -7828,6 +7871,7 @@ struct rtw89_hw_scan_complete_cb_data { static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); struct rtw89_hw_scan_complete_cb_data *cb_data = data; struct rtw89_vif_link *rtwvif_link = cb_data->rtwvif_link; struct cfg80211_scan_info info = { @@ -7850,6 +7894,9 @@ static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data) rtw89_hw_scan_cleanup(rtwdev, rtwvif_link); + if (mode == RTW89_ENTITY_MODE_MCC) + rtw89_hw_scan_update_beacon_noa(rtwdev, false); + return 0; } @@ -7916,6 +7963,8 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, bool enable) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_scan_option opt = {0}; bool connected; int ret = 0; @@ -7940,6 +7989,9 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, opt.num_macc_role = 0; opt.mlo_mode = rtwdev->mlo_dbcc_mode; opt.num_opch = connected ? 1 : 0; + if (connected && ext->set) + opt.num_opch++; + opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 22b2b2a716ef..479a9f980b7f 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2817,6 +2817,7 @@ struct rtw89_h2c_scanofld_be_opch { #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_PKTS_CTRL GENMASK(7, 0) #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF GENMASK(15, 8) #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS GENMASK(18, 16) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W2_TXBCN BIT(19) #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0 GENMASK(7, 0) #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT1 GENMASK(15, 8) #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT2 GENMASK(23, 16) From 83f84f263420b4a11c1b3c1ba0723c3d374b33ad Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:15 +0800 Subject: [PATCH 38/58] wifi: rtw89: mcc: solve GO's TBTT change and TBTT too close to NoA issue For some implementation acting as GO under MCC(GO+STA), the GO's TBTT might change after STA roams to another AP. This could result the new GO beacon TX at the STA timeslot of GC+STA, causing GC beacon loss. Therefore, if the GC detects beacon loss, it will pause MCC and remain on the GO side for 100 TU to detect the new TBTT beacon. Additionally, some implementation acting as GO under MCC might TX beacon too close to the NoA period. The GC calculates timeslot pattern the TOB (time offset behind) or TOA(time offset ahead) less than the minimum RX beacon time, which leads to beacon loss. Therefore, disable the beacon filter in this case. Then, if the GO's TBTT changed, the pattern TOB/TOA greater than the minimum RX beacon time, the beacon filter should be retriggered during MCC update. Moreover, if the beacon filter is disabled initially but the GO timeslot change, causing QoS null data detection fail, also pause MCC to detect new TBTT beacon. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 143 ++++++++++++++++-- drivers/net/wireless/realtek/rtw89/chan.h | 6 + drivers/net/wireless/realtek/rtw89/core.h | 4 + drivers/net/wireless/realtek/rtw89/mac.c | 10 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 5 + 5 files changed, 154 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 6c80e08ae99d..ed0d89ac3495 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1000,6 +1000,11 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, *pattern = *new; memset(&pattern->courtesy, 0, sizeof(pattern->courtesy)); + if (RTW89_MCC_REQ_COURTESY(pattern, aux) && aux->is_gc) + aux->ignore_bcn = true; + else + aux->ignore_bcn = false; + if (RTW89_MCC_REQ_COURTESY(pattern, aux) && rtw89_mcc_can_courtesy(ref, aux)) { crtz = &pattern->courtesy.ref; ref->crtz = crtz; @@ -1014,6 +1019,11 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, ref->crtz = NULL; } + if (RTW89_MCC_REQ_COURTESY(pattern, ref) && ref->is_gc) + ref->ignore_bcn = true; + else + ref->ignore_bcn = false; + if (RTW89_MCC_REQ_COURTESY(pattern, ref) && rtw89_mcc_can_courtesy(aux, ref)) { crtz = &pattern->courtesy.aux; aux->crtz = crtz; @@ -2255,15 +2265,6 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) else mcc->mode = RTW89_MCC_MODE_GC_STA; - if (rtw89_mcc_ignore_bcn(rtwdev, ref)) { - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, false); - } else if (rtw89_mcc_ignore_bcn(rtwdev, aux)) { - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, false); - } else { - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, true); - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, true); - } - rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC sel mode: %d\n", mcc->mode); mcc->group = RTW89_MCC_DFLT_GROUP; @@ -2272,6 +2273,15 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) if (ret) return ret; + if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, false); + } else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, false); + } else { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, true); + } + if (rtw89_concurrent_via_mrc(rtwdev)) ret = __mrc_fw_start(rtwdev, false); else @@ -2391,7 +2401,11 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, static int rtw89_mcc_update(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; + bool old_ref_ignore_bcn = mcc->role_ref.ignore_bcn; + bool old_aux_ignore_bcn = mcc->role_aux.ignore_bcn; struct rtw89_mcc_config *config = &mcc->config; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_config old_cfg = *config; bool courtesy_changed; bool sync_changed; @@ -2406,6 +2420,11 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) if (ret) return ret; + if (old_ref_ignore_bcn != ref->ignore_bcn) + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, !ref->ignore_bcn); + else if (old_aux_ignore_bcn != aux->ignore_bcn) + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, !aux->ignore_bcn); + if (memcmp(&old_cfg.pattern.courtesy, &config->pattern.courtesy, sizeof(old_cfg.pattern.courtesy)) == 0) courtesy_changed = false; @@ -2441,10 +2460,105 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_mcc_search_gc_iterator(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *mcc_role, + unsigned int ordered_idx, + void *data) +{ + struct rtw89_mcc_role **role = data; + + if (mcc_role->is_gc) + *role = mcc_role; + + return 0; +} + +static struct rtw89_mcc_role *rtw89_mcc_get_gc_role(struct rtw89_dev *rtwdev) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_role *role = NULL; + + if (mcc->mode != RTW89_MCC_MODE_GC_STA) + return NULL; + + rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_search_gc_iterator, &role); + + return role; +} + +void rtw89_mcc_gc_detect_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_vif_link *rtwvif_link = container_of(work, struct rtw89_vif_link, + mcc_gc_detect_beacon_work.work); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + enum rtw89_entity_mode mode; + struct rtw89_dev *rtwdev; + + lockdep_assert_wiphy(wiphy); + + rtwdev = rtwvif_link->rtwvif->rtwdev; + + mode = rtw89_get_entity_mode(rtwdev); + if (mode != RTW89_ENTITY_MODE_MCC) + return; + + if (READ_ONCE(rtwvif_link->sync_bcn_tsf) > rtwvif_link->last_sync_bcn_tsf) + rtwvif_link->detect_bcn_count = 0; + else + rtwvif_link->detect_bcn_count++; + + if (rtwvif_link->detect_bcn_count < RTW89_MCC_DETECT_BCN_MAX_TRIES) + rtw89_chanctx_proceed(rtwdev, NULL); + else + ieee80211_connection_loss(vif); +} + +bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); + struct rtw89_chanctx_pause_parm pause_parm = { + .rsn = RTW89_CHANCTX_PAUSE_REASON_GC_BCN_LOSS, + .trigger = rtwvif_link, + }; + struct ieee80211_bss_conf *bss_conf; + struct rtw89_mcc_role *role; + u16 bcn_int; + + if (mode != RTW89_ENTITY_MODE_MCC) + return false; + + role = rtw89_mcc_get_gc_role(rtwdev); + if (!role) + return false; + + if (role->rtwvif_link != rtwvif_link) + return false; + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC GC beacon loss, pause MCC to detect GO beacon\n"); + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + bcn_int = bss_conf->beacon_int; + + rcu_read_unlock(); + + rtw89_chanctx_pause(rtwdev, &pause_parm); + rtwvif_link->last_sync_bcn_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf); + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwvif_link->mcc_gc_detect_beacon_work, + usecs_to_jiffies(ieee80211_tu_to_usec(bcn_int))); + + return true; +} + static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role) { struct ieee80211_vif *vif; + bool start_detect; int ret; ret = rtw89_core_send_nullfunc(rtwdev, role->rtwvif_link, true, false, @@ -2458,7 +2572,12 @@ static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, return; rtw89_debug(rtwdev, RTW89_DBG_CHAN, - "MCC can not detect AP\n", role->rtwvif_link->mac_id); + "MCC can not detect AP/GO\n", role->rtwvif_link->mac_id); + + start_detect = rtw89_mcc_detect_go_bcn(rtwdev, role->rtwvif_link); + if (start_detect) + return; + vif = rtwvif_link_to_vif(role->rtwvif_link); ieee80211_connection_loss(vif); } @@ -2474,9 +2593,9 @@ static void rtw89_mcc_track(struct rtw89_dev *rtwdev) u16 bcn_ofst; u16 diff; - if (rtw89_mcc_ignore_bcn(rtwdev, ref)) + if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) rtw89_mcc_detect_connection(rtwdev, aux); - else if (rtw89_mcc_ignore_bcn(rtwdev, aux)) + else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) rtw89_mcc_detect_connection(rtwdev, ref); if (mcc->mode != RTW89_MCC_MODE_GC_STA) diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 9a62b7c98b83..b1175419f92b 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -23,6 +23,8 @@ #define RTW89_MCC_PROBE_TIMEOUT 100 #define RTW89_MCC_PROBE_MAX_TRIES 3 +#define RTW89_MCC_DETECT_BCN_MAX_TRIES 2 + #define RTW89_MCC_MIN_GO_DURATION \ (RTW89_MCC_EARLY_TX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME) @@ -94,6 +96,7 @@ struct rtw89_mr_chanctx_info { enum rtw89_chanctx_pause_reasons { RTW89_CHANCTX_PAUSE_REASON_HW_SCAN, RTW89_CHANCTX_PAUSE_REASON_ROC, + RTW89_CHANCTX_PAUSE_REASON_GC_BCN_LOSS, }; struct rtw89_chanctx_pause_parm { @@ -188,6 +191,9 @@ struct rtw89_mcc_links_info { void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info); void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work); +void rtw89_mcc_gc_detect_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); +bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 2faf0889f7df..2e5f129ff4f8 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3597,6 +3597,7 @@ struct rtw89_vif_link { u8 hit_rule; u8 last_noa_nr; u64 sync_bcn_tsf; + u64 last_sync_bcn_tsf; bool rand_tsf_done; bool trigger; bool lsig_txop; @@ -3620,6 +3621,8 @@ struct rtw89_vif_link { struct list_head general_pkt_list; struct rtw89_p2p_noa_setter p2p_noa; struct rtw89_ps_noa_once_handler noa_once; + struct wiphy_delayed_work mcc_gc_detect_beacon_work; + u8 detect_bcn_count; }; enum rtw89_lv1_rcvy_step { @@ -5778,6 +5781,7 @@ struct rtw89_mcc_role { bool is_2ghz; bool is_go; bool is_gc; + bool ignore_bcn; }; struct rtw89_mcc_bt_role { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 37b113e3bd26..f6bbc796329c 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5088,6 +5088,7 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l const struct rtw89_c2h_mac_bcnfltr_rpt *c2h = (const struct rtw89_c2h_mac_bcnfltr_rpt *)skb->data; u8 type, event, mac_id; + bool start_detect; s8 sig; type = le32_get_bits(c2h->w2, RTW89_C2H_MAC_BCNFLTR_RPT_W2_TYPE); @@ -5105,10 +5106,15 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l switch (type) { case RTW89_BCN_FLTR_BEACON_LOSS: if (!rtwdev->scanning && !rtwvif->offchan && - !rtwvif_link->noa_once.in_duration) + !rtwvif_link->noa_once.in_duration) { + start_detect = rtw89_mcc_detect_go_bcn(rtwdev, rtwvif_link); + if (start_detect) + return; + ieee80211_connection_loss(vif); - else + } else { rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); + } return; case RTW89_BCN_FLTR_NOTIFY: nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index c982ad633b4a..c1ca6d741b32 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -113,6 +113,8 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, wiphy_work_init(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work); wiphy_delayed_work_init(&rtwvif_link->csa_beacon_work, rtw89_core_csa_beacon_work); + wiphy_delayed_work_init(&rtwvif_link->mcc_gc_detect_beacon_work, + rtw89_mcc_gc_detect_beacon_work); INIT_LIST_HEAD(&rtwvif_link->general_pkt_list); @@ -124,6 +126,7 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_idx = RTW89_CHANCTX_0; rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; rtwvif_link->rand_tsf_done = false; + rtwvif_link->detect_bcn_count = 0; rcu_read_lock(); @@ -147,6 +150,8 @@ static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev, wiphy_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->update_beacon_work); wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->csa_beacon_work); + wiphy_delayed_work_cancel(rtwdev->hw->wiphy, + &rtwvif_link->mcc_gc_detect_beacon_work); rtw89_p2p_noa_once_deinit(rtwvif_link); From 65093fab65cb79d6ae6abaefc5ebe0427cbd1c5a Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:16 +0800 Subject: [PATCH 39/58] wifi: rtw89: check LPS H2C command complete by C2H reg instead of done ack 8852B after FW 0.29.127, 8852BT after FW 0.29.127 and 8922A after FW 0.35.76 driver check LPS H2C command received by FW using C2H reg instead of done ack. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 11 ++++++++- drivers/net/wireless/realtek/rtw89/fw.h | 4 ++++ drivers/net/wireless/realtek/rtw89/ps.c | 28 ++++++++++++++++++++++- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 2e5f129ff4f8..7afb84ea0e26 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4608,6 +4608,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_BEACON_LOSS_COUNT_V1, RTW89_FW_FEATURE_SCAN_OFFLOAD_EXTRA_OP, RTW89_FW_FEATURE_RFK_NTFY_MCC_V0, + RTW89_FW_FEATURE_LPS_DACK_BY_C2H_REG, }; struct rtw89_fw_suit { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 20b7b4b15450..8157774b2bb1 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -827,11 +827,13 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 7, BEACON_FILTER), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), __CFG_FW_FEAT(RTL8852C, ge, 0, 0, 0, 0, RFK_NTFY_MCC_V0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), @@ -856,6 +858,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 51, 0, NO_PHYCAP_P1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -2824,8 +2827,14 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, struct rtw89_lps_parm *lps_param) { struct sk_buff *skb; + bool done_ack; int ret; + if (RTW89_CHK_FW_FEATURE(LPS_DACK_BY_C2H_REG, &rtwdev->fw)) + done_ack = false; + else + done_ack = !lps_param->psmode; + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LPS_PARM_LEN); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); @@ -2847,7 +2856,7 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_PS, - H2C_FUNC_MAC_LPS_PARM, 0, !lps_param->psmode, + H2C_FUNC_MAC_LPS_PARM, 0, done_ack, H2C_LPS_PARM_LEN); ret = rtw89_h2c_tx(rtwdev, skb, false); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 479a9f980b7f..629e54adcb83 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -87,6 +87,9 @@ struct rtw89_c2hreg_phycap { #define RTW89_C2HREG_AOAC_RPT_2_W3_IGTK_IPN_IV_6 GENMASK(7, 0) #define RTW89_C2HREG_AOAC_RPT_2_W3_IGTK_IPN_IV_7 GENMASK(15, 8) +#define RTW89_C2HREG_PS_LEAVE_ACK_RET GENMASK(7, 0) +#define RTW89_C2HREG_PS_LEAVE_ACK_MACID GENMASK(31, 16) + struct rtw89_h2creg_hdr { u32 w0; }; @@ -154,6 +157,7 @@ enum rtw89_mac_c2h_type { RTW89_FWCMD_C2HREG_FUNC_TX_PAUSE_RPT, RTW89_FWCMD_C2HREG_FUNC_WOW_CPUIO_RX_ACK = 0xA, RTW89_FWCMD_C2HREG_FUNC_PHY_CAP_PART1 = 0xC, + RTW89_FWCMD_C2HREG_FUNC_PS_LEAVE_ACK = 0xD, RTW89_FWCMD_C2HREG_FUNC_NULL = 0xFF, }; diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index 3411d642c84a..652f8fc81b79 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -13,6 +13,31 @@ #include "reg.h" #include "util.h" +static int rtw89_fw_receive_lps_h2c_check(struct rtw89_dev *rtwdev, u8 macid) +{ + struct rtw89_mac_c2h_info c2h_info = {}; + u16 c2hreg_macid; + u32 c2hreg_ret; + int ret; + + if (!RTW89_CHK_FW_FEATURE(LPS_DACK_BY_C2H_REG, &rtwdev->fw)) + return 0; + + c2h_info.id = RTW89_FWCMD_C2HREG_FUNC_PS_LEAVE_ACK; + ret = rtw89_fw_msg_reg(rtwdev, NULL, &c2h_info); + if (ret) + return ret; + + c2hreg_macid = u32_get_bits(c2h_info.u.c2hreg[0], + RTW89_C2HREG_PS_LEAVE_ACK_MACID); + c2hreg_ret = u32_get_bits(c2h_info.u.c2hreg[1], RTW89_C2HREG_PS_LEAVE_ACK_RET); + + if (macid != c2hreg_macid || c2hreg_ret) + rtw89_warn(rtwdev, "rtw89: check lps h2c received by firmware fail\n"); + + return 0; +} + static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -106,7 +131,8 @@ static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, }; rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); - rtw89_fw_leave_lps_check(rtwdev, 0); + rtw89_fw_receive_lps_h2c_check(rtwdev, rtwvif_link->mac_id); + rtw89_fw_leave_lps_check(rtwdev, rtwvif_link->mac_id); rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); rtw89_chip_digital_pwr_comp(rtwdev, rtwvif_link->phy_idx); } From 5693bdd58de48bc91831d8d2e60f78595205c6eb Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:17 +0800 Subject: [PATCH 40/58] wifi: rtw89: introduce fw feature group and redefine CRASH_TRIGGER Some FW features may have variants on how to deal with in leaf functions, e.g. H2C commands. However, from SW component point of view, it might not matter which variant is supported exactly. In some cases, SW component may just care whether any of the variants is supported or not. So, introduce a concept of FW feature group which can manage a set of FW features and can easily be checked if at least one of them is supported. Since CRASH_TRIGGER will have variants and then matches the case mentioned above, so redefine CRASH_TRIGGER as a FW feature group and add a variant of type 0 for original handling. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 15 ++++++++++++++- drivers/net/wireless/realtek/rtw89/debug.c | 2 +- drivers/net/wireless/realtek/rtw89/fw.c | 12 ++++++------ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7afb84ea0e26..7bc473411190 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4583,11 +4583,20 @@ enum rtw89_fw_type { RTW89_FW_LOGFMT = 255, }; +#define RTW89_FW_FEATURE_GROUP(_grp, _features...) \ + RTW89_FW_FEATURE_##_grp##_MIN, \ + __RTW89_FW_FEATURE_##_grp##_S = RTW89_FW_FEATURE_##_grp##_MIN - 1, \ + _features \ + __RTW89_FW_FEATURE_##_grp##_E, \ + RTW89_FW_FEATURE_##_grp##_MAX = __RTW89_FW_FEATURE_##_grp##_E - 1 + enum rtw89_fw_feature { RTW89_FW_FEATURE_OLD_HT_RA_FORMAT, RTW89_FW_FEATURE_SCAN_OFFLOAD, RTW89_FW_FEATURE_TX_WAKE, - RTW89_FW_FEATURE_CRASH_TRIGGER, + RTW89_FW_FEATURE_GROUP(CRASH_TRIGGER, + RTW89_FW_FEATURE_CRASH_TRIGGER_TYPE_0, + ), RTW89_FW_FEATURE_NO_PACKET_DROP, RTW89_FW_FEATURE_NO_DEEP_PS, RTW89_FW_FEATURE_NO_LPS_PG, @@ -4706,6 +4715,10 @@ struct rtw89_fw_info { #define RTW89_CHK_FW_FEATURE(_feat, _fw) \ (!!((_fw)->feature_map & BIT(RTW89_FW_FEATURE_ ## _feat))) +#define RTW89_CHK_FW_FEATURE_GROUP(_grp, _fw) \ + (!!((_fw)->feature_map & GENMASK(RTW89_FW_FEATURE_ ## _grp ## _MAX, \ + RTW89_FW_FEATURE_ ## _grp ## _MIN))) + #define RTW89_SET_FW_FEATURE(_fw_feature, _fw) \ ((_fw)->feature_map |= BIT(_fw_feature)) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 4acb567b3ad4..afdfb9647fc1 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3596,7 +3596,7 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev, switch (crash_type) { case RTW89_DBG_SIM_CPU_EXCEPTION: - if (!RTW89_CHK_FW_FEATURE(CRASH_TRIGGER, &rtwdev->fw)) + if (!RTW89_CHK_FW_FEATURE_GROUP(CRASH_TRIGGER, &rtwdev->fw)) return -EOPNOTSUPP; sim = rtw89_fw_h2c_trigger_cpu_exception; break; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 8157774b2bb1..fca79212e34f 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -814,23 +814,23 @@ struct __fw_feat_cfg { static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), - __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), - __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 37, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 38, 0, NO_PACKET_DROP), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, TX_WAKE), - __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 7, BEACON_FILTER), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), - __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), @@ -838,11 +838,11 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 0, 0, 0, RFK_NTFY_MCC_V0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD), - __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 80, 0, WOW_REASON_V1), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, BEACON_LOSS_COUNT_V1), - __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 21, 0, SCAN_OFFLOAD_BE_V0), From e044f5d40f49bfd4beab517e7fe2988d3d8ce66d Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:18 +0800 Subject: [PATCH 41/58] wifi: rtw89: update SER L2 type default value 8852BT after FW 0.29.127, 8852B after FW 0.29.128 and 8922A after FW 0.35.79, the SER L2 flow determines different L2 types by parameter, the zero value will trigger FW SER L2 assert. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 36 +++++++++++++++-------- drivers/net/wireless/realtek/rtw89/fw.h | 9 +++--- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7bc473411190..59ec81adac7e 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4596,6 +4596,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_TX_WAKE, RTW89_FW_FEATURE_GROUP(CRASH_TRIGGER, RTW89_FW_FEATURE_CRASH_TRIGGER_TYPE_0, + RTW89_FW_FEATURE_CRASH_TRIGGER_TYPE_1, ), RTW89_FW_FEATURE_NO_PACKET_DROP, RTW89_FW_FEATURE_NO_DEEP_PS, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index fca79212e34f..6b94445577fd 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -828,12 +828,14 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 7, BEACON_FILTER), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), __CFG_FW_FEAT(RTL8852C, ge, 0, 0, 0, 0, RFK_NTFY_MCC_V0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), @@ -859,6 +861,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 79, 0, CRASH_TRIGGER_TYPE_1), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -8009,41 +8012,50 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, return ret; } -#define H2C_FW_CPU_EXCEPTION_LEN 4 -#define H2C_FW_CPU_EXCEPTION_TYPE_DEF 0x5566 +#define H2C_FW_CPU_EXCEPTION_TYPE_0 0x5566 +#define H2C_FW_CPU_EXCEPTION_TYPE_1 0x0 int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev) { + struct rtw89_h2c_trig_cpu_except *h2c; + u32 cpu_exception_type_def; + u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_FW_CPU_EXCEPTION_LEN); + if (RTW89_CHK_FW_FEATURE(CRASH_TRIGGER_TYPE_1, &rtwdev->fw)) + cpu_exception_type_def = H2C_FW_CPU_EXCEPTION_TYPE_1; + else if (RTW89_CHK_FW_FEATURE(CRASH_TRIGGER_TYPE_0, &rtwdev->fw)) + cpu_exception_type_def = H2C_FW_CPU_EXCEPTION_TYPE_0; + else + return -EOPNOTSUPP; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw cpu exception\n"); return -ENOMEM; } - skb_put(skb, H2C_FW_CPU_EXCEPTION_LEN); - RTW89_SET_FWCMD_CPU_EXCEPTION_TYPE(skb->data, - H2C_FW_CPU_EXCEPTION_TYPE_DEF); + skb_put(skb, len); + h2c = (struct rtw89_h2c_trig_cpu_except *)skb->data; + + h2c->w0 = le32_encode_bits(cpu_exception_type_def, + RTW89_H2C_CPU_EXCEPTION_TYPE); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_TEST, H2C_CL_FW_STATUS_TEST, H2C_FUNC_CPU_EXCEPTION, 0, 0, - H2C_FW_CPU_EXCEPTION_LEN); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { rtw89_err(rtwdev, "failed to send h2c\n"); - goto fail; + dev_kfree_skb_any(skb); + return ret; } return 0; - -fail: - dev_kfree_skb_any(skb); - return ret; } #define H2C_PKT_DROP_LEN 24 diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 629e54adcb83..98be7e72c685 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1833,10 +1833,11 @@ struct rtw89_h2c_lps_ml_cmn_info { u8 dup_bcn_ofst[RTW89_PHY_NUM]; } __packed; -static inline void RTW89_SET_FWCMD_CPU_EXCEPTION_TYPE(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 0)); -} +struct rtw89_h2c_trig_cpu_except { + __le32 w0; +} __packed; + +#define RTW89_H2C_CPU_EXCEPTION_TYPE GENMASK(31, 0) static inline void RTW89_SET_FWCMD_PKT_DROP_SEL(void *cmd, u32 val) { From 094bb62c580dc6608736c6df4d4f238386050bf4 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Thu, 10 Jul 2025 12:24:19 +0800 Subject: [PATCH 42/58] wifi: rtw89: tweak tx wake notify matching condition 8852BT needs to call TX wake notify once entering Leisure Power Save. 8852C needs to call TX wake notify after entering low power mode. Other AX chips only MGMT packets needs to call TX wake after entering low power mode. BE chips no need to call TX wake. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index da82a88cce98..57590f5577a3 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -994,13 +994,25 @@ rtw89_core_tx_wake(struct rtw89_dev *rtwdev, if (!RTW89_CHK_FW_FEATURE(TX_WAKE, &rtwdev->fw)) return; - if (!test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) - return; + switch (chip->chip_id) { + case RTL8852BT: + if (test_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) + goto notify; + break; + case RTL8852C: + if (test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) + goto notify; + break; + default: + if (test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags) && + tx_req->tx_type == RTW89_CORE_TX_TYPE_MGMT) + goto notify; + break; + } - if (chip->chip_id != RTL8852C && - tx_req->tx_type != RTW89_CORE_TX_TYPE_MGMT) - return; + return; +notify: rtw89_mac_notify_wake(rtwdev); } From 868676662b08f43cd26a2bc3492d6a7fa1eb3414 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:20 +0800 Subject: [PATCH 43/58] wifi: rtw89: 8852bt: configure FW version for SCAN_OFFLOAD_EXTRA_OP feature After v0.29.127.0, RTL8852BT FW supports SCAN_OFFLOAD_EXTRA_OP feature. With it, FW can do back-op and TX NULL frames on the second connection. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 6b94445577fd..0b0d1fd7b02b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -834,6 +834,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), From 21911ad80512f9e4e642b9e8ecd7130e32cb63d3 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:21 +0800 Subject: [PATCH 44/58] wifi: rtw89: 8852bt: implement RFK multi-channel handling and support chanctx up to 2 To support multiple channels, 2 for this case, RFK requires to record each calibration result for each channel in different RFK tables, and also needs to notify FW. Then, when FW runs in MCC (multi-channel concurrency), it can switch to the corresponding calibration result according to the channel. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-13-pkshih@realtek.com --- .../net/wireless/realtek/rtw89/rtw8852bt.c | 12 +++- .../wireless/realtek/rtw89/rtw8852bt_rfk.c | 69 ++++++++++++++----- .../wireless/realtek/rtw89/rtw8852bt_rfk.h | 3 + 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 10d09c12f318..06a06c190553 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -533,8 +533,11 @@ static void rtw8852bt_set_channel_help(struct rtw89_dev *rtwdev, bool enter, static void rtw8852bt_rfk_init(struct rtw89_dev *rtwdev) { + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + rtwdev->is_tssi_mode[RF_PATH_A] = false; rtwdev->is_tssi_mode[RF_PATH_B] = false; + memset(rfk_mcc, 0, sizeof(*rfk_mcc)); rtw8852bt_dpk_init(rtwdev); rtw8852bt_rck(rtwdev); @@ -548,6 +551,7 @@ static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; + rtw8852bt_mcc_get_ch_info(rtwdev, phy_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, true); rtw8852bt_rx_dck(rtwdev, phy_idx, chanctx_idx); @@ -558,6 +562,7 @@ static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, rtw8852bt_dpk(rtwdev, phy_idx, chanctx_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, false); + rtw89_fw_h2c_rf_ntfy_mcc(rtwdev); } static void rtw8852bt_rfk_band_changed(struct rtw89_dev *rtwdev, @@ -727,6 +732,10 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .btc_set_policy = rtw89_btc_set_policy_v1, }; +static const struct rtw89_chanctx_listener rtw8852bt_chanctx_listener = { + .callbacks[RTW89_CHANCTX_CALLBACK_RFK] = rtw8852bt_rfk_chanctx_cb, +}; + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8852bt = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -769,6 +778,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .nctl_post_table = NULL, .dflt_parms = NULL, .rfe_parms_conf = NULL, + .chanctx_listener = &rtw8852bt_chanctx_listener, .txpwr_factor_bb = 3, .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, @@ -777,7 +787,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .tssi_dbw_table = NULL, .support_macid_num = RTW89_MAX_MAC_ID_NUM, .support_link_num = 0, - .support_chanctx_num = 1, + .support_chanctx_num = 2, .support_rnr = false, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index 6e6889eea9a0..d0e299803225 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -2,6 +2,7 @@ /* Copyright(c) 2024 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "fw.h" @@ -1529,26 +1530,11 @@ static void _iqk_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u enum rtw89_chanctx_idx chanctx_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; - u8 get_empty_table = false; + u8 idx = rfk_mcc->table_idx; u32 reg_rf18; u32 reg_35c; - u8 idx; - - for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { - if (iqk_info->iqk_mcc_ch[idx][path] == 0) { - get_empty_table = true; - break; - } - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (1)idx = %x\n", idx); - - if (!get_empty_table) { - idx = iqk_info->iqk_table_idx[path] + 1; - if (idx > 1) - idx = 0; - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (2)idx = %x\n", idx); reg_rf18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); reg_35c = rtw89_phy_read32_mask(rtwdev, R_CIRST, B_CIRST_SYN); @@ -1640,7 +1626,8 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) { - u8 idx = 0; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + u8 idx = rfk_mcc->table_idx; rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), 0x00000001, idx); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), 0x00000008, idx); @@ -4252,3 +4239,49 @@ void rtw8852bt_set_channel_rf(struct rtw89_dev *rtwdev, rtw8852bt_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type, chan->band_width); } + +void rtw8852bt_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, 0); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {}; + u8 idx; + + for (idx = 0; idx < ARRAY_SIZE(desc); idx++) { + struct rtw89_rfk_chan_desc *p = &desc[idx]; + + p->ch = rfk_mcc->ch[idx]; + + p->has_band = true; + p->band = rfk_mcc->band[idx]; + } + + idx = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); + + rfk_mcc->ch[idx] = chan->channel; + rfk_mcc->band[idx] = chan->band_type; + rfk_mcc->table_idx = idx; +} + +void rtw8852bt_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 path; + + switch (state) { + case RTW89_CHANCTX_STATE_MCC_START: + dpk->is_dpk_enable = false; + for (path = 0; path < RTW8852BT_SS; path++) + _dpk_onoff(rtwdev, path, false); + break; + case RTW89_CHANCTX_STATE_MCC_STOP: + dpk->is_dpk_enable = true; + for (path = 0; path < RTW8852BT_SS; path++) + _dpk_onoff(rtwdev, path, false); + rtw8852bt_dpk(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); + break; + default: + break; + } +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h index e34560b4905f..a663bbda4075 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h @@ -27,5 +27,8 @@ void rtw8852bt_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, void rtw8852bt_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); +void rtw8852bt_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8852bt_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state); #endif From 504937dbaddb2149d5031e924100e285d7325eef Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:22 +0800 Subject: [PATCH 45/58] wifi: rtw89: 8852b: configure FW version for SCAN_OFFLOAD_EXTRA_OP feature After v0.29.128.0, RTL8852B FW supports SCAN_OFFLOAD_EXTRA_OP feature. With it, FW can do back-op and TX NULL frames on the second connection. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-14-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 0b0d1fd7b02b..73a4ec988d16 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -829,6 +829,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), From cefcf74ae02623a80acffe5f662ed6523575ed46 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 10 Jul 2025 12:24:23 +0800 Subject: [PATCH 46/58] wifi: rtw89: 8852b: implement RFK multi-channel handling and support chanctx up to 2 To support multiple channels, 2 for this case, RFK requires to record each calibration result for each channel in different RFK tables, and also needs to notify FW. Then, when FW runs in MCC (multi-channel concurrency), it can switch to the corresponding calibration result according to the channel. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250710042423.73617-15-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 12 ++- .../net/wireless/realtek/rtw89/rtw8852b_rfk.c | 77 +++++++++++++------ .../net/wireless/realtek/rtw89/rtw8852b_rfk.h | 3 + 3 files changed, 68 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 33ab71d84ffc..389dfac26028 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -628,8 +628,11 @@ static void rtw8852b_set_channel_help(struct rtw89_dev *rtwdev, bool enter, static void rtw8852b_rfk_init(struct rtw89_dev *rtwdev) { + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + rtwdev->is_tssi_mode[RF_PATH_A] = false; rtwdev->is_tssi_mode[RF_PATH_B] = false; + memset(rfk_mcc, 0, sizeof(*rfk_mcc)); rtw8852b_dpk_init(rtwdev); rtw8852b_rck(rtwdev); @@ -643,6 +646,7 @@ static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; + rtw8852b_mcc_get_ch_info(rtwdev, phy_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, true); rtw8852b_rx_dck(rtwdev, phy_idx, chanctx_idx); @@ -653,6 +657,7 @@ static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, rtw8852b_dpk(rtwdev, phy_idx, chanctx_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, false); + rtw89_fw_h2c_rf_ntfy_mcc(rtwdev); } static void rtw8852b_rfk_band_changed(struct rtw89_dev *rtwdev, @@ -861,6 +866,10 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .btc_set_policy = rtw89_btc_set_policy_v1, }; +static const struct rtw89_chanctx_listener rtw8852b_chanctx_listener = { + .callbacks[RTW89_CHANCTX_CALLBACK_RFK] = rtw8852b_rfk_chanctx_cb, +}; + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8852b = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -909,6 +918,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .nctl_post_table = NULL, .dflt_parms = &rtw89_8852b_dflt_parms, .rfe_parms_conf = NULL, + .chanctx_listener = &rtw8852b_chanctx_listener, .txpwr_factor_bb = 3, .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, @@ -917,7 +927,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .tssi_dbw_table = NULL, .support_macid_num = RTW89_MAX_MAC_ID_NUM, .support_link_num = 0, - .support_chanctx_num = 0, + .support_chanctx_num = 2, .support_rnr = false, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c index fbf82d42687b..4796588c0256 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c @@ -2,6 +2,7 @@ /* Copyright(c) 2019-2022 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "mac.h" @@ -1145,19 +1146,19 @@ static void _lok_res_table(struct rtw89_dev *rtwdev, u8 path, u8 ibias) static bool _lok_finetune_check(struct rtw89_dev *rtwdev, u8 path) { + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 ch = rfk_mcc->table_idx; bool is_fail1, is_fail2; u32 vbuff_i; u32 vbuff_q; u32 core_i; u32 core_q; u32 tmp; - u8 ch; tmp = rtw89_read_rf(rtwdev, path, RR_TXMO, RFREG_MASK); core_i = FIELD_GET(RR_TXMO_COI, tmp); core_q = FIELD_GET(RR_TXMO_COQ, tmp); - ch = (iqk_info->iqk_times / 2) % RTW89_IQK_CHS_NR; if (core_i < 0x2 || core_i > 0x1d || core_q < 0x2 || core_q > 0x1d) is_fail1 = true; @@ -1386,26 +1387,11 @@ static void _iqk_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u enum rtw89_chanctx_idx chanctx_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 idx = rfk_mcc->table_idx; u32 reg_rf18; u32 reg_35c; - u8 idx; - u8 get_empty_table = false; - - for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { - if (iqk_info->iqk_mcc_ch[idx][path] == 0) { - get_empty_table = true; - break; - } - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (1)idx = %x\n", idx); - - if (!get_empty_table) { - idx = iqk_info->iqk_table_idx[path] + 1; - if (idx > 1) - idx = 0; - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (2)idx = %x\n", idx); reg_rf18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); reg_35c = rtw89_phy_read32_mask(rtwdev, R_CIRST, B_CIRST_SYN); @@ -1506,11 +1492,10 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) { - struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; - u8 idx; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + u8 idx = rfk_mcc->table_idx; - idx = iqk_info->iqk_table_idx[path]; - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (3)idx = %x\n", idx); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] idx = %x\n", idx); rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), B_COEF_SEL_IQC, idx); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_G3, idx); @@ -4179,3 +4164,49 @@ void rtw8852b_set_channel_rf(struct rtw89_dev *rtwdev, rtw8852b_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type, chan->band_width); } + +void rtw8852b_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, 0); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {}; + u8 idx; + + for (idx = 0; idx < ARRAY_SIZE(desc); idx++) { + struct rtw89_rfk_chan_desc *p = &desc[idx]; + + p->ch = rfk_mcc->ch[idx]; + + p->has_band = true; + p->band = rfk_mcc->band[idx]; + } + + idx = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); + + rfk_mcc->ch[idx] = chan->channel; + rfk_mcc->band[idx] = chan->band_type; + rfk_mcc->table_idx = idx; +} + +void rtw8852b_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 path; + + switch (state) { + case RTW89_CHANCTX_STATE_MCC_START: + dpk->is_dpk_enable = false; + for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) + _dpk_onoff(rtwdev, path, false); + break; + case RTW89_CHANCTX_STATE_MCC_STOP: + dpk->is_dpk_enable = true; + for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) + _dpk_onoff(rtwdev, path, false); + rtw8852b_dpk(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); + break; + default: + break; + } +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h index c31ba446e6e0..5fae980d5e2c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h @@ -27,5 +27,8 @@ void rtw8852b_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, void rtw8852b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); +void rtw8852b_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8852b_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state); #endif From d76a1abcf57734d2bcd4a7ec051617edd4513d7f Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Wed, 9 Jul 2025 14:15:22 +0200 Subject: [PATCH 47/58] wifi: rtl8xxxu: Fix RX skb size for aggregation disabled Commit 1e5b3b3fe9e0 ("rtl8xxxu: Adjust RX skb size to include space for phystats") increased the skb size when aggregation is enabled but decreased it for the aggregation disabled case. As a result, if a frame near the maximum size is received, rtl8xxxu_rx_complete() is called with status -EOVERFLOW and then the driver starts to malfunction and no further communication is possible. Restore the skb size in the aggregation disabled case. Fixes: 1e5b3b3fe9e0 ("rtl8xxxu: Adjust RX skb size to include space for phystats") Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250709121522.1992366-1-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index 496836f716aa..f6f169d2062d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -6618,7 +6618,7 @@ static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv, skb_size = fops->rx_agg_buf_size; skb_size += (rx_desc_sz + sizeof(struct rtl8723au_phy_stats)); } else { - skb_size = IEEE80211_MAX_FRAME_LEN; + skb_size = IEEE80211_MAX_FRAME_LEN + rx_desc_sz; } skb = __netdev_alloc_skb(NULL, skb_size, GFP_KERNEL); From 5f936768300f65d5856d6adf0f8591e2ae716727 Mon Sep 17 00:00:00 2001 From: Andrey Skvortsov Date: Fri, 11 Jul 2025 11:47:40 +0300 Subject: [PATCH 48/58] wifi: rtw88: enable TX reports for the management queue This is needed for AP mode. Otherwise client sees the network, but can't connect to it. REG_FWHW_TXQ_CTRL+1 is set to WLAN_TXQ_RPT_EN (0x1F) in common mac init function (__rtw8723x_mac_init), but the value was overwritten from mac table later. Tables with register values for phy parameters initialization are copied from vendor driver usually. When table will be regenerated, manual modifications to it may be lost. To avoid regressions in this case new callback mac_postinit is introduced, that is called after parameters from table are set. Tested on rtl8723cs, that reuses rtw8703b driver. Signed-off-by: Andrey Skvortsov Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250711084740.3396766-1-andrej.skvortzov@gmail.com --- drivers/net/wireless/realtek/rtw88/mac.c | 10 ++++++++++ drivers/net/wireless/realtek/rtw88/mac.h | 1 + drivers/net/wireless/realtek/rtw88/main.c | 6 ++++++ drivers/net/wireless/realtek/rtw88/main.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8703b.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8723d.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8723x.c | 9 ++++++++- drivers/net/wireless/realtek/rtw88/rtw8723x.h | 6 ++++++ drivers/net/wireless/realtek/rtw88/rtw8812a.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8814a.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8821a.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8821c.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8822b.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8822c.c | 1 + 14 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 011b81c82f3b..eaa928bab240 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -1409,3 +1409,13 @@ int rtw_mac_init(struct rtw_dev *rtwdev) return 0; } + +int rtw_mac_postinit(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + + if (!chip->ops->mac_postinit) + return 0; + + return chip->ops->mac_postinit(rtwdev); +} diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h index e92b1483728d..b73af90ee1d7 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.h +++ b/drivers/net/wireless/realtek/rtw88/mac.h @@ -38,6 +38,7 @@ void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size); int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw); int rtw_mac_init(struct rtw_dev *rtwdev); +int rtw_mac_postinit(struct rtw_dev *rtwdev); void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop); int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev); int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 97756bdf57b2..b706c5a21a6c 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1412,6 +1412,12 @@ int rtw_power_on(struct rtw_dev *rtwdev) chip->ops->phy_set_param(rtwdev); + ret = rtw_mac_postinit(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to configure mac in postinit\n"); + goto err_off; + } + ret = rtw_hci_start(rtwdev); if (ret) { rtw_err(rtwdev, "failed to start hci\n"); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index b42538cce359..43ed6d6b4291 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -858,6 +858,7 @@ struct rtw_chip_ops { int (*power_on)(struct rtw_dev *rtwdev); void (*power_off)(struct rtw_dev *rtwdev); int (*mac_init)(struct rtw_dev *rtwdev); + int (*mac_postinit)(struct rtw_dev *rtwdev); int (*dump_fw_crash)(struct rtw_dev *rtwdev); void (*shutdown)(struct rtw_dev *rtwdev); int (*read_efuse)(struct rtw_dev *rtwdev, u8 *map); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c index 03475af973b5..821c28d9cb5d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c @@ -1832,6 +1832,7 @@ static const struct rtw_chip_ops rtw8703b_ops = { .power_on = rtw_power_on, .power_off = rtw_power_off, .mac_init = rtw8723x_mac_init, + .mac_postinit = rtw8723x_mac_postinit, .dump_fw_crash = NULL, .shutdown = NULL, .read_efuse = rtw8703b_read_efuse, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index bf69f5b06ce2..8715e0435f17 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -1397,6 +1397,7 @@ static const struct rtw_chip_ops rtw8723d_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8723d_set_channel, .mac_init = rtw8723x_mac_init, + .mac_postinit = rtw8723x_mac_postinit, .shutdown = rtw8723d_shutdown, .read_rf = rtw_phy_read_rf_sipi, .write_rf = rtw_phy_write_rf_reg_sipi, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.c b/drivers/net/wireless/realtek/rtw88/rtw8723x.c index 4c77963fdd37..3f3e9b0c44e8 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723x.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.c @@ -353,7 +353,6 @@ static int __rtw8723x_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) static int __rtw8723x_mac_init(struct rtw_dev *rtwdev) { - rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, WLAN_TXQ_RPT_EN); rtw_write32(rtwdev, REG_TCR, BIT_TCR_CFG); rtw_write16(rtwdev, REG_RXFLTMAP0, WLAN_RX_FILTER0); @@ -370,6 +369,13 @@ static int __rtw8723x_mac_init(struct rtw_dev *rtwdev) return 0; } +static int __rtw8723x_mac_postinit(struct rtw_dev *rtwdev) +{ + rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, WLAN_TXQ_RPT_EN); + + return 0; +} + static void __rtw8723x_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) { u8 ldo_pwr; @@ -760,6 +766,7 @@ const struct rtw8723x_common rtw8723x_common = { .lck = __rtw8723x_lck, .read_efuse = __rtw8723x_read_efuse, .mac_init = __rtw8723x_mac_init, + .mac_postinit = __rtw8723x_mac_postinit, .cfg_ldo25 = __rtw8723x_cfg_ldo25, .set_tx_power_index = __rtw8723x_set_tx_power_index, .efuse_grant = __rtw8723x_efuse_grant, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.h b/drivers/net/wireless/realtek/rtw88/rtw8723x.h index a99af527c92c..0fc70dfdfc8b 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723x.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.h @@ -137,6 +137,7 @@ struct rtw8723x_common { void (*lck)(struct rtw_dev *rtwdev); int (*read_efuse)(struct rtw_dev *rtwdev, u8 *log_map); int (*mac_init)(struct rtw_dev *rtwdev); + int (*mac_postinit)(struct rtw_dev *rtwdev); void (*cfg_ldo25)(struct rtw_dev *rtwdev, bool enable); void (*set_tx_power_index)(struct rtw_dev *rtwdev); void (*efuse_grant)(struct rtw_dev *rtwdev, bool on); @@ -383,6 +384,11 @@ static inline int rtw8723x_mac_init(struct rtw_dev *rtwdev) return rtw8723x_common.mac_init(rtwdev); } +static inline int rtw8723x_mac_postinit(struct rtw_dev *rtwdev) +{ + return rtw8723x_common.mac_postinit(rtwdev); +} + static inline void rtw8723x_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) { rtw8723x_common.cfg_ldo25(rtwdev, enable); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c index 03b441639611..2078eb6e3628 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -919,6 +919,7 @@ static const struct rtw_chip_ops rtw8812a_ops = { .query_phy_status = rtw8812a_query_phy_status, .set_channel = rtw88xxa_set_channel, .mac_init = NULL, + .mac_postinit = NULL, .read_rf = rtw88xxa_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_antenna = NULL, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c index 4a1f850d05c8..ca1079e12023 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c @@ -2055,6 +2055,7 @@ static const struct rtw_chip_ops rtw8814a_ops = { .query_phy_status = rtw8814a_query_phy_status, .set_channel = rtw8814a_set_channel, .mac_init = rtw8814a_mac_init, + .mac_postinit = NULL, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_tx_power_index = rtw8814a_set_tx_power_index, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c index 1d02ea400b2e..414b77eef07c 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c @@ -865,6 +865,7 @@ static const struct rtw_chip_ops rtw8821a_ops = { .query_phy_status = rtw8821a_query_phy_status, .set_channel = rtw88xxa_set_channel, .mac_init = NULL, + .mac_postinit = NULL, .read_rf = rtw88xxa_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_antenna = NULL, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index a2a358d6033f..2078b067562e 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -1663,6 +1663,7 @@ static const struct rtw_chip_ops rtw8821c_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8821c_set_channel, .mac_init = rtw8821c_mac_init, + .mac_postinit = NULL, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_antenna = NULL, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index bb5c41905afe..89b6485b229a 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -2154,6 +2154,7 @@ static const struct rtw_chip_ops rtw8822b_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8822b_set_channel, .mac_init = rtw8822b_mac_init, + .mac_postinit = NULL, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_tx_power_index = rtw8822b_set_tx_power_index, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 58c1958e6170..28c121cf1e68 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -4964,6 +4964,7 @@ static const struct rtw_chip_ops rtw8822c_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8822c_set_channel, .mac_init = rtw8822c_mac_init, + .mac_postinit = NULL, .dump_fw_crash = rtw8822c_dump_fw_crash, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_mix, From 526b000991b557c40ea53e64ba24bb9e0fff0071 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sun, 13 Jul 2025 22:27:32 +0300 Subject: [PATCH 49/58] wifi: rtw88: Fix macid assigned to TDLS station When working in station mode, TDLS peers are assigned macid 0, even though 0 was already assigned to the AP. This causes the connection with the AP to stop working after the TDLS connection is torn down. Assign the next available macid to TDLS peers, same as client stations in AP mode. Fixes: 902cb7b11f9a ("wifi: rtw88: assign mac_id for vif/sta and update to TX desc") Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/58648c09-8553-4bcc-a977-9dc9afd63780@gmail.com --- drivers/net/wireless/realtek/rtw88/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index b706c5a21a6c..fa0ed39cb199 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -349,7 +349,7 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; int i; - if (vif->type == NL80211_IFTYPE_STATION) { + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { si->mac_id = rtwvif->mac_id; } else { si->mac_id = rtw_acquire_macid(rtwdev); @@ -386,7 +386,7 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, cancel_work_sync(&si->rc_work); - if (vif->type != NL80211_IFTYPE_STATION) + if (vif->type != NL80211_IFTYPE_STATION || sta->tdls) rtw_release_macid(rtwdev, si->mac_id); if (fw_exist) rtw_fw_media_status_report(rtwdev, si->mac_id, false); From cbf510e21e0ce3d75b099528859526cc24ebf628 Mon Sep 17 00:00:00 2001 From: Chia-Yuan Li Date: Tue, 15 Jul 2025 11:52:55 +0800 Subject: [PATCH 50/58] wifi: rtw89: trigger TX stuck if FIFO full In order for the situation where the dispatcher blocking causes HAXIDMA to be unable to TX to be reported as a TX stuck, so that subsequent recovery can be handled. Signed-off-by: Chia-Yuan Li Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 597de632e364..a669f2f843aa 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -2638,6 +2638,10 @@ static void rtw89_pci_set_dbg(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_AX_PCIE_DBG_CTRL, B_AX_ASFF_FULL_NO_STK | B_AX_EN_STUCK_DBG); + rtw89_write32_mask(rtwdev, R_AX_PCIE_EXP_CTRL, + B_AX_EN_STUCK_DBG | B_AX_ASFF_FULL_NO_STK, + B_AX_EN_STUCK_DBG); + if (rtwdev->chip->chip_id == RTL8852A) rtw89_write32_set(rtwdev, R_AX_PCIE_EXP_CTRL, B_AX_EN_CHKDSC_NO_RX_STUCK); From 8552f2b3153eb8d49450f1661adf62457c410660 Mon Sep 17 00:00:00 2001 From: Chia-Yuan Li Date: Tue, 15 Jul 2025 11:52:56 +0800 Subject: [PATCH 51/58] wifi: rtw89: mac: reduce PPDU status length for WiFi 6 chips Since the RX counter in the PPDU status is not used, it is disabled to reduce the waste of DLE quota. Signed-off-by: Chia-Yuan Li Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index f6bbc796329c..3de3ea1e13ad 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5865,7 +5865,7 @@ int rtw89_mac_cfg_ppdu_status_ax(struct rtw89_dev *rtwdev, u8 mac_idx, bool enab rtw89_write32(rtwdev, reg, B_AX_PPDU_STAT_RPT_EN | B_AX_APP_MAC_INFO_RPT | - B_AX_APP_RX_CNT_RPT | B_AX_APP_PLCP_HDR_RPT | + B_AX_APP_PLCP_HDR_RPT | B_AX_PPDU_STAT_RPT_CRC32); rtw89_write32_mask(rtwdev, R_AX_HW_RPT_FWD, B_AX_FWD_PPDU_STAT_MASK, RTW89_PRPT_DEST_HOST); From b552a3ef8a3d722470593349333c9b19bfe40767 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Tue, 15 Jul 2025 11:52:57 +0800 Subject: [PATCH 52/58] wifi: rtw89: dynamically update EHT preamble puncturing When the 'Disabled Subchannel Bitmap' within the EHT Operation element is changed, mac80211 parse and pass it to the driver. The driver is then updated with this puncturing bitmap to optimize bandwidth usage and prevent interference from degrading performance across the entire channel. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 47 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/core.h | 3 ++ drivers/net/wireless/realtek/rtw89/fw.c | 43 +++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 16 +++++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + .../net/wireless/realtek/rtw89/rtw8852bt.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 + 10 files changed, 115 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index ed0d89ac3495..f7d1c5d3b92e 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -129,6 +129,48 @@ void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan, bandwidth); } +static void _rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + const struct cfg80211_chan_def *chandef) +{ + struct ieee80211_bss_conf *bss_conf; + + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) + return; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->eht_support) { + rcu_read_unlock(); + return; + } + + rcu_read_unlock(); + + rtw89_chip_h2c_punctured_cmac_tbl(rtwdev, rtwvif_link, chandef->punctured); +} + +static void rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx idx, + const struct cfg80211_chan_def *chandef) +{ + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + if (!rtwvif_link->chanctx_assigned || + rtwvif_link->chanctx_idx != idx) + continue; + + _rtw89_chan_update_punctured(rtwdev, rtwvif_link, chandef); + } + } +} + bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, const struct rtw89_chan *new) @@ -3245,6 +3287,9 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, rtw89_config_entity_chandef(rtwdev, idx, &ctx->def); rtw89_set_channel(rtwdev); } + + if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) + rtw89_chan_update_punctured(rtwdev, idx, &ctx->def); } int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, @@ -3388,5 +3433,7 @@ int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev, return ret; } + _rtw89_chan_update_punctured(rtwdev, rtwvif_link, &new_ctx->def); + return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 59ec81adac7e..a99a0dc710d8 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3779,6 +3779,9 @@ struct rtw89_chip_ops { struct rtw89_sta_link *rtwsta_link); int (*h2c_txtime_cmac_tbl)(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); + int (*h2c_punctured_cmac_tbl)(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured); int (*h2c_default_dmac_tbl)(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 73a4ec988d16..8230115c29b4 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3745,6 +3745,49 @@ int rtw89_fw_h2c_txtime_cmac_tbl_g7(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_txtime_cmac_tbl_g7); +int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured) +{ + struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for punctured cmac g7\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; + + h2c->c0 = le32_encode_bits(rtwvif_link->mac_id, CCTLINFO_G7_C0_MACID) | + le32_encode_bits(1, CCTLINFO_G7_C0_OP); + + h2c->w4 = le32_encode_bits(~punctured, CCTLINFO_G7_W4_ACT_SUBCH_CBW); + h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_ACT_SUBCH_CBW); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_punctured_cmac_tbl_g7); + int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 98be7e72c685..b64edc9e8abe 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4736,6 +4736,9 @@ int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txtime_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, @@ -5038,6 +5041,19 @@ int rtw89_chip_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, return chip->ops->h2c_txtime_cmac_tbl(rtwdev, rtwsta_link); } +static inline +int rtw89_chip_h2c_punctured_cmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (!chip->ops->h2c_punctured_cmac_tbl) + return 0; + + return chip->ops->h2c_punctured_cmac_tbl(rtwdev, rtwvif_link, punctured); +} + static inline int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 96edaf8e9ec4..393df2b0dcae 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2546,6 +2546,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 0496deb7278f..3bbe2a808844 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2151,6 +2151,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 389dfac26028..7ede07f7b1eb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -851,6 +851,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 06a06c190553..9427823aca2f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -717,6 +717,7 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 6e27f1ff94dc..88cf8ea13e7c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2971,6 +2971,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index e23655f3e4c1..36c641e3bc13 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2826,6 +2826,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_g7, .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_g7, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl_g7, + .h2c_punctured_cmac_tbl = rtw89_fw_h2c_punctured_cmac_tbl_g7, .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v2, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, From f1000385d47be9e0a1d1d622a2e2e28ffd0fe384 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 15 Jul 2025 11:52:58 +0800 Subject: [PATCH 53/58] wifi: rtw89: purge obsoleted scan events with software sequence number The queued and obsoleted scan events can be wrongly treated as events of new scan request, causing unexpected scan result. Attach a software sequence number to scan request and its corresponding events. When a new scan request is acknowledged by firmware, purge the scan events if its sequence number is not belong to current request. Normal case: mac80211 event work event BH ------------- ---------- -------- scan req #1 ---->o | <----o <...........................o o | <--------------------------+ ieee80211_scan_completed() Abnormal case (late event work): mac80211 event work event BH ------------- ---------- -------- scan req #1 ---->o | <----o <...........................o o #1 scan cancel #2 ->o | <----o <...........................o o #2 | (patch to avoid this) scan req #3 ---->o | | | <----o <..........|................o | o #3 <--------------------------+ ieee80211_scan_completed() Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 31 ++++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/fw.h | 3 +++ drivers/net/wireless/realtek/rtw89/mac.c | 8 ++++++ drivers/net/wireless/realtek/rtw89/mac.h | 25 ++++++++++++++++++ drivers/net/wireless/realtek/rtw89/wow.c | 2 +- 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a99a0dc710d8..43e10278e14d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5574,6 +5574,7 @@ struct rtw89_hw_scan_info { bool connected; bool abort; u16 delay; /* in unit of ms */ + u8 seq: 2; }; enum rtw89_phy_bb_gain_band { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 8230115c29b4..d26626bed960 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -6759,6 +6759,34 @@ void rtw89_fw_c2h_work(struct wiphy *wiphy, struct wiphy_work *work) } } +void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev) +{ + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct sk_buff *skb, *tmp; + int limit; + + lockdep_assert_wiphy(rtwdev->hw->wiphy); + + limit = skb_queue_len(&rtwdev->c2h_queue); + + skb_queue_walk_safe(&rtwdev->c2h_queue, skb, tmp) { + struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb); + + if (--limit < 0) + return; + + if (!attr->is_scan_event || attr->scan_seq == scan_info->seq) + continue; + + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "purge obsoleted scan event with seq=%d (cur=%d)\n", + attr->scan_seq, scan_info->seq); + + skb_unlink(skb, &rtwdev->c2h_queue); + dev_kfree_skb_any(skb); + } +} + static int rtw89_fw_write_h2c_reg(struct rtw89_dev *rtwdev, struct rtw89_mac_h2c_info *info) { @@ -8052,7 +8080,8 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID; } - ret = mac->scan_offload(rtwdev, &opt, rtwvif_link, false); + ret = rtw89_mac_scan_offload(rtwdev, &opt, rtwvif_link, false); + out: return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b64edc9e8abe..7a4ad7a416b8 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3570,6 +3570,8 @@ struct rtw89_fw_c2h_attr { u8 class; u8 func; u16 len; + u8 is_scan_event: 1; + u8 scan_seq: 2; }; static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb) @@ -4755,6 +4757,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); void rtw89_fw_c2h_work(struct wiphy *wiphy, struct wiphy_work *work); +void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 3de3ea1e13ad..65d36fcad8b2 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5165,6 +5165,7 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le { /* N.B. This will run in interrupt context. */ struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *ps_wait = &rtwdev->mac.ps_wait; const struct rtw89_c2h_done_ack *c2h = (const struct rtw89_c2h_done_ack *)skb_c2h->data; @@ -5207,9 +5208,11 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN; break; case H2C_FUNC_SCANOFLD: + scan_info->seq++; cond = RTW89_SCANOFLD_WAIT_COND_START; break; case H2C_FUNC_SCANOFLD_BE: + scan_info->seq++; cond = RTW89_SCANOFLD_BE_WAIT_COND_START; h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN; break; @@ -5706,10 +5709,15 @@ static void rtw89_mac_c2h_scanofld_rsp_atomic(struct rtw89_dev *rtwdev, const struct rtw89_c2h_scanofld *c2h = (const struct rtw89_c2h_scanofld *)skb->data; struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb); struct rtw89_completion_data data = {}; unsigned int cond; u8 status, reason; + attr->is_scan_event = 1; + attr->scan_seq = scan_info->seq; + status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS); reason = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_RSN); data.err = status != RTW89_SCAN_STATUS_SUCCESS; diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 9f596a06b3d0..241e89983c4a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -6,6 +6,7 @@ #define __RTW89_MAC_H__ #include "core.h" +#include "fw.h" #include "reg.h" #define MAC_MEM_DUMP_PAGE_SIZE_AX 0x40000 @@ -1583,4 +1584,28 @@ void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode) return mac->fwdl_secure_idmem_share_mode(rtwdev, mode); } + +static inline +int rtw89_mac_scan_offload(struct rtw89_dev *rtwdev, + struct rtw89_scan_option *option, + struct rtw89_vif_link *rtwvif_link, + bool wowlan) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + int ret; + + ret = mac->scan_offload(rtwdev, option, rtwvif_link, wowlan); + + if (option->enable) { + /* + * At this point, new scan request is acknowledged by firmware, + * so scan events of previous scan request become obsoleted. + * Purge the queued scan events to prevent interference to + * current new request. + */ + rtw89_fw_c2h_purge_obsoleted_scan_events(rtwdev); + } + + return ret; +} #endif diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 4f759c75389e..4dd471b6dd30 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -1489,7 +1489,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) opt.opch_end = RTW89_CHAN_INVALID; } - mac->scan_offload(rtwdev, &opt, rtwvif_link, true); + rtw89_mac_scan_offload(rtwdev, &opt, rtwvif_link, true); return 0; } From 8b4a0277388137ac31728ee69d9e388a0fa52287 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 15 Jul 2025 11:52:59 +0800 Subject: [PATCH 54/58] wifi: rtw89: check path range before using in rtw89_fw_h2c_rf_ps_info() The variable 'path' from rtw89_phy_get_syn_sel() as index of array could be 3, but array size is 2. Fortunately, current chip->rf_path_num is smaller or equal to 2, so it is safe. To prevent mistakes in the future, add a checking and avoid Coverity warnings. Addresses-Coverity-ID: linux-next: 1644716 ("Out-of-bounds write") Addresses-Coverity-ID: linux-next: 1644717 ("Out-of-bounds write") Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715035259.45061-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d26626bed960..a26465ff6a68 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -6153,7 +6153,7 @@ int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) path = rtw89_phy_get_syn_sel(rtwdev, rtwvif_link->phy_idx); val = rtw89_chip_chan_to_rf18_val(rtwdev, chan); - if (path >= chip->rf_path_num) { + if (path >= chip->rf_path_num || path >= NUM_OF_RTW89_FW_RFK_PATH) { rtw89_err(rtwdev, "unsupported rf path (%d)\n", path); ret = -ENOENT; goto fail; From 671be46afd1f03de9dc6e4679c88e1a7a81cdff6 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 15 Jul 2025 22:44:47 +0300 Subject: [PATCH 55/58] wifi: rtw89: Lower the timeout in rtw89_fw_read_c2h_reg() for USB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This read_poll_timeout_atomic() with a delay of 1 µs and a timeout of 1000000 µs can take ~250 seconds in the worst case because sending a USB control message takes ~250 µs. Lower the timeout to 4000 for USB in order to reduce the maximum polling time to ~1 second. This problem was observed with RTL8851BU while suspending to RAM with WOWLAN enabled. The computer sat for 4 minutes with a black screen before suspending. Signed-off-by: Bitterblue Smith Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/09313da6-c865-4e91-b758-4cb38a878796@gmail.com --- drivers/net/wireless/realtek/rtw89/fw.c | 9 +++++++-- drivers/net/wireless/realtek/rtw89/fw.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index a26465ff6a68..16e59a4a486e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -6826,13 +6826,18 @@ static int rtw89_fw_read_c2h_reg(struct rtw89_dev *rtwdev, const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_fw_info *fw_info = &rtwdev->fw; const u32 *c2h_reg = chip->c2h_regs; - u32 ret; + u32 ret, timeout; u8 i, val; info->id = RTW89_FWCMD_C2HREG_FUNC_NULL; + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + timeout = RTW89_C2H_TIMEOUT_USB; + else + timeout = RTW89_C2H_TIMEOUT; + ret = read_poll_timeout_atomic(rtw89_read8, val, val, 1, - RTW89_C2H_TIMEOUT, false, rtwdev, + timeout, false, rtwdev, chip->c2h_ctrl_reg); if (ret) { rtw89_warn(rtwdev, "c2h reg timeout\n"); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 7a4ad7a416b8..7865930299c8 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -115,6 +115,8 @@ struct rtw89_h2creg_sch_tx_en { #define RTW89_C2HREG_HDR_LEN 2 #define RTW89_H2CREG_HDR_LEN 2 #define RTW89_C2H_TIMEOUT 1000000 +#define RTW89_C2H_TIMEOUT_USB 4000 + struct rtw89_mac_c2h_info { u8 id; u8 content_len; From 12322a02603071d09df652bbc11864e23de0b83e Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 15 Jul 2025 22:46:20 +0300 Subject: [PATCH 56/58] wifi: rtw89: Lower the timeout in rtw89_fwdl_check_path_ready_ax() for USB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the chip is not powered on correctly (like during driver development) rtw89_fwdl_check_path_ready_ax() can fail. read_poll_timeout_atomic() with a delay of 1 µs and a timeout of 400000 µs can take 50 seconds with USB because of the time it takes to send a USB control message. The firmware upload is tried 5 times, so in total it takes 250 seconds. Lower the timeout to 3200 for USB in order to reduce the time rtw89_fwdl_check_path_ready_ax() takes from 50 seconds to less than 1 second. Signed-off-by: Bitterblue Smith Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/af0b25d0-ea67-455e-91f2-8e4c18ae4328@gmail.com --- drivers/net/wireless/realtek/rtw89/fw.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 7865930299c8..3de29137b113 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4699,6 +4699,7 @@ struct rtw89_c2h_rf_tas_info { #define RTW89_FW_BACKTRACE_KEY 0xBACEBACE #define FWDL_WAIT_CNT 400000 +#define FWDL_WAIT_CNT_USB 3200 int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type); int rtw89_fw_recognize(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 65d36fcad8b2..5a5da9d9c0c5 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -6940,10 +6940,16 @@ int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev, bool h2c_or_fwdl) { u8 check = h2c_or_fwdl ? B_AX_H2C_PATH_RDY : B_AX_FWDL_PATH_RDY; + u32 timeout; u8 val; + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + timeout = FWDL_WAIT_CNT_USB; + else + timeout = FWDL_WAIT_CNT; + return read_poll_timeout_atomic(rtw89_read8, val, val & check, - 1, FWDL_WAIT_CNT, false, + 1, timeout, false, rtwdev, R_AX_WCPU_FW_CTRL); } From 37c23874d13eb369d8b384a1ce5992ff6c23d56f Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Wed, 16 Jul 2025 20:29:26 +0800 Subject: [PATCH 57/58] wifi: rtw89: wow: Add Basic Rate IE to probe request in scheduled scan mode In scheduled scan mode, the current probe request only includes the SSID IE, but omits the Basic Rate IE. Some APs do not respond to such incomplete probe requests, causing net-detect failures. To improve interoperability and ensure APs respond correctly, add the Basic Rate IE to the probe request in driver. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250716122926.6709-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/wow.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 4dd471b6dd30..071c7577df52 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -1412,6 +1412,8 @@ static void rtw89_fw_release_pno_pkt_list(struct rtw89_dev *rtwdev, static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { + static const u8 basic_rate_ie[] = {WLAN_EID_SUPP_RATES, 0x08, + 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c}; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; u8 num = nd_config->n_match_sets, i; @@ -1423,10 +1425,11 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr, nd_config->match_sets[i].ssid.ssid, nd_config->match_sets[i].ssid.ssid_len, - nd_config->ie_len); + nd_config->ie_len + sizeof(basic_rate_ie)); if (!skb) return -ENOMEM; + skb_put_data(skb, basic_rate_ie, sizeof(basic_rate_ie)); skb_put_data(skb, nd_config->ie, nd_config->ie_len); info = kzalloc(sizeof(*info), GFP_KERNEL); From 94cd0ba1842ece06acc15bba5f2bff6b6043eb1d Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 15 Jul 2025 20:16:53 +0800 Subject: [PATCH 58/58] wifi: rtlwifi: Use min()/max() to improve code Use min()/max() to reduce the code and improve its readability. Acked-by: Ping-Ke Shih Signed-off-by: Qianfeng Rong Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250715121721.266713-8-rongqianfeng@vivo.com --- .../wireless/realtek/rtlwifi/rtl8192ce/hw.c | 19 +++---------------- .../wireless/realtek/rtlwifi/rtl8192cu/hw.c | 17 +++-------------- .../wireless/realtek/rtlwifi/rtl8192ee/dm.c | 5 +---- .../wireless/realtek/rtlwifi/rtl8723ae/hw.c | 15 +++------------ .../wireless/realtek/rtlwifi/rtl8723be/dm.c | 5 +---- .../wireless/realtek/rtlwifi/rtl8821ae/dm.c | 5 +---- 6 files changed, 12 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c index 5ca6b49e73c7..4354ae67a379 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c @@ -1487,22 +1487,9 @@ _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = rtlefuse-> eeprom_chnlarea_txpwr_ht40_1s[rf_path][index]; - - if ((rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path][index]) - > 0) { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = - rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path] - [index] - - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path] - [index]; - } else { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; - } + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + max(rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][index], 0); } for (i = 0; i < 14; i++) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index ec5d558609fe..989e7cff8e20 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -163,20 +163,9 @@ _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = rtlefuse-> eeprom_chnlarea_txpwr_ht40_1s[rf_path][index]; - if ((rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path][index]) - > 0) { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = - rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path] - [index] - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path] - [index]; - } else { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; - } + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + max(rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][index], 0); } for (i = 0; i < 14; i++) { RTPRINT(rtlpriv, FINIT, INIT_TXPOWER, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c index 17486e3f322c..0108850bb9e5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c @@ -223,10 +223,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) if (mac->link_state >= MAC80211_LINKED) { if (bfirstconnect) { - if (dm_dig->rssi_val_min <= dig_maxofmin) - current_igi = dm_dig->rssi_val_min; - else - current_igi = dig_maxofmin; + current_igi = min(dm_dig->rssi_val_min, dig_maxofmin); dm_dig->large_fa_hit = 0; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index 21b827f519b6..bd45d9bd40bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -1449,18 +1449,9 @@ _rtl8723e_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, rtlefuse->eeprom_chnlarea_txpwr_ht40_1s [rf_path][index]; - if ((rtlefuse->eeprom_chnlarea_txpwr_ht40_1s - [rf_path][index] - - rtlefuse->eprom_chnl_txpwr_ht40_2sdf - [rf_path][index]) > 0) { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = - rtlefuse->eeprom_chnlarea_txpwr_ht40_1s - [rf_path][index] - - rtlefuse->eprom_chnl_txpwr_ht40_2sdf - [rf_path][index]; - } else { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; - } + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + max(rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][index], 0); } for (i = 0; i < 14; i++) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c index c53f95144812..c65d14fb914f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c @@ -468,10 +468,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) if (mac->link_state >= MAC80211_LINKED) { if (bfirstconnect) { - if (dm_digtable->rssi_val_min <= dig_maxofmin) - current_igi = dm_digtable->rssi_val_min; - else - current_igi = dig_maxofmin; + current_igi = min(dm_digtable->rssi_val_min, dig_maxofmin); dm_digtable->large_fa_hit = 0; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c index 76b5395539d0..f8b159c74658 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c @@ -756,10 +756,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) rtl_dbg(rtlpriv, COMP_DIG, DBG_LOUD, "DIG AfterLink\n"); if (first_connect) { - if (dm_digtable->rssi_val_min <= dig_max_of_min) - current_igi = dm_digtable->rssi_val_min; - else - current_igi = dig_max_of_min; + current_igi = min(dm_digtable->rssi_val_min, dig_max_of_min); rtl_dbg(rtlpriv, COMP_DIG, DBG_LOUD, "First Connect\n"); } else {