From 4c95423b6f01a50505308d2eaec2da2a2bcd3139 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 17 May 2025 18:46:14 +0200 Subject: [PATCH 01/63] wifi: rtlwifi: Constify struct rtl_hal_ops and rtl_hal_cfg 'struct rtl_hal_ops' and 'struct rtl_hal_cfg' are not modified in these drivers. Constifying this structure moves some data to a read-only section, so increase overall security, especially when the structure holds some function pointers. Constification of rtl_hal_cfg is only needed in rtl8192cu/sw.c On a x86_64, with allmodconfig, as an example: Before: ====== text data bss dec hex filename 10167 5512 128 15807 3dbf drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.o After: ===== text data bss dec hex filename 10743 4936 128 15807 3dbf drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.o Signed-off-by: Christophe JAILLET Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/2c3f3d8d8b2f7dcb8cc64cebe89e55720d1d733d.1747500351.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 2ad4523d1bef..79c6e0901e57 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -190,7 +190,7 @@ static bool rtl88e_get_btc_status(void) return false; } -static struct rtl_hal_ops rtl8188ee_hal_ops = { +static const struct rtl_hal_ops rtl8188ee_hal_ops = { .init_sw_vars = rtl88e_init_sw_vars, .deinit_sw_vars = rtl88e_deinit_sw_vars, .read_eeprom_info = rtl88ee_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index ce7c28d9c874..f06b159f975d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -167,7 +167,7 @@ static void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw) } } -static struct rtl_hal_ops rtl8192ce_hal_ops = { +static const struct rtl_hal_ops rtl8192ce_hal_ops = { .init_sw_vars = rtl92c_init_sw_vars, .deinit_sw_vars = rtl92c_deinit_sw_vars, .read_eeprom_info = rtl92ce_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index c9b9e2bc90cc..00a6778df704 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -81,7 +81,7 @@ static bool rtl92cu_get_btc_status(void) return false; } -static struct rtl_hal_ops rtl8192cu_hal_ops = { +static const struct rtl_hal_ops rtl8192cu_hal_ops = { .init_sw_vars = rtl92cu_init_sw_vars, .deinit_sw_vars = rtl92cu_deinit_sw_vars, .read_chip_version = rtl92c_read_chip_version, @@ -156,7 +156,7 @@ static struct rtl_hal_usbint_cfg rtl92cu_interface_cfg = { .usb_mq_to_hwq = rtl8192cu_mq_to_hwq, }; -static struct rtl_hal_cfg rtl92cu_hal_cfg = { +static const struct rtl_hal_cfg rtl92cu_hal_cfg = { .name = "rtl92c_usb", .alt_fw_name = "rtlwifi/rtl8192cufw.bin", .ops = &rtl8192cu_hal_ops, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index e36e4aeb9a95..7612c22a9842 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -184,7 +184,7 @@ static void rtl92d_deinit_sw_vars(struct ieee80211_hw *hw) skb_queue_purge(&rtlpriv->mac80211.skb_waitq[tid]); } -static struct rtl_hal_ops rtl8192de_hal_ops = { +static const struct rtl_hal_ops rtl8192de_hal_ops = { .init_sw_vars = rtl92d_init_sw_vars, .deinit_sw_vars = rtl92d_deinit_sw_vars, .read_eeprom_info = rtl92d_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 162e734d5b08..181dd7823b26 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -176,7 +176,7 @@ static bool rtl92ee_get_btc_status(void) return true; } -static struct rtl_hal_ops rtl8192ee_hal_ops = { +static const struct rtl_hal_ops rtl8192ee_hal_ops = { .init_sw_vars = rtl92ee_init_sw_vars, .deinit_sw_vars = rtl92ee_deinit_sw_vars, .read_eeprom_info = rtl92ee_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index e63c67b1861b..1cf801feb45e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -221,7 +221,7 @@ static bool rtl92se_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, return true; } -static struct rtl_hal_ops rtl8192se_hal_ops = { +static const struct rtl_hal_ops rtl8192se_hal_ops = { .init_sw_vars = rtl92s_init_sw_vars, .deinit_sw_vars = rtl92s_deinit_sw_vars, .read_eeprom_info = rtl92se_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index 048744166a92..dcd7cdb96aa4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -183,7 +183,7 @@ static bool is_fw_header(struct rtlwifi_firmware_header *hdr) return (le16_to_cpu(hdr->signature) & 0xfff0) == 0x2300; } -static struct rtl_hal_ops rtl8723e_hal_ops = { +static const struct rtl_hal_ops rtl8723e_hal_ops = { .init_sw_vars = rtl8723e_init_sw_vars, .deinit_sw_vars = rtl8723e_deinit_sw_vars, .read_eeprom_info = rtl8723e_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 0a92d0325098..5967df08e34e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -187,7 +187,7 @@ static bool is_fw_header(struct rtlwifi_firmware_header *hdr) return (le16_to_cpu(hdr->signature) & 0xfff0) == 0x5300; } -static struct rtl_hal_ops rtl8723be_hal_ops = { +static const struct rtl_hal_ops rtl8723be_hal_ops = { .init_sw_vars = rtl8723be_init_sw_vars, .deinit_sw_vars = rtl8723be_deinit_sw_vars, .read_eeprom_info = rtl8723be_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index b5266e560416..1557d32efdd2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -229,7 +229,7 @@ static bool rtl8821ae_get_btc_status(void) return true; } -static struct rtl_hal_ops rtl8821ae_hal_ops = { +static const struct rtl_hal_ops rtl8821ae_hal_ops = { .init_sw_vars = rtl8821ae_init_sw_vars, .deinit_sw_vars = rtl8821ae_deinit_sw_vars, .read_eeprom_info = rtl8821ae_read_eeprom_info, From cdb82c80b9349ed1d9ce6b49856128e04f4effc9 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 23 May 2025 14:27:10 +0800 Subject: [PATCH 02/63] wifi: rtw88: pci: add PCI Express error handling Sometimes PCIe Advanced Error Reporting(AER), like bad TLP or Data link protocol error, happens due to unstable pci signal or no response from PCI host. pcieport 0000:00:00.0: AER: Multiple Corrected error message received from 0000:00:00.0 pcieport 0000:00:00.0: AER: PCIe Bus Error: severity=Corrected, type=Physical Layer, (Receiver ID) pcieport 0000:00:00.0: AER: device [14c3:6786] error status/mask=000000c1/00006000 pcieport 0000:00:00.0: AER: [ 0] RxErr (First) pcieport 0000:00:00.0: AER: [ 6] BadTLP pcieport 0000:00:00.0: AER: [ 7] BadDLLP pcieport 0000:00:00.0: AER: Corrected error message received from 0000:00:00.0 pcieport 0000:00:00.0: AER: found no error details for 0000:00:00.0 pcieport 0000:00:00.0: AER: Multiple Corrected error message received from 0000:00:00.0 pcieport 0000:00:00.0: AER: found no error details for 0000:00:00.0 pcieport 0000:00:00.0: AER: Multiple Corrected error message received from 0000:00:00.0 pcieport 0000:00:00.0: AER: found no error details for 0000:00:00.0 Setup callback function to call SER function to reset driver to recover from these states Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250523062711.27213-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/main.c | 1 + drivers/net/wireless/realtek/rtw88/pci.c | 37 +++++++++++++++++++ drivers/net/wireless/realtek/rtw88/pci.h | 1 + .../net/wireless/realtek/rtw88/rtw8723de.c | 1 + .../net/wireless/realtek/rtw88/rtw8821ce.c | 1 + .../net/wireless/realtek/rtw88/rtw8822be.c | 1 + .../net/wireless/realtek/rtw88/rtw8822ce.c | 1 + 7 files changed, 43 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index c4de5d114eda..26b1479d3521 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -636,6 +636,7 @@ void rtw_fw_recovery(struct rtw_dev *rtwdev) if (!test_bit(RTW_FLAG_RESTARTING, rtwdev->flags)) ieee80211_queue_work(rtwdev->hw, &rtwdev->fw_recovery_work); } +EXPORT_SYMBOL(rtw_fw_recovery); static void __fw_recovery_work(struct rtw_dev *rtwdev) { diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 7f2b6dc21f56..6655de2b9726 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1707,6 +1707,43 @@ static void rtw_pci_napi_deinit(struct rtw_dev *rtwdev) free_netdev(rtwpci->netdev); } +static pci_ers_result_t rtw_pci_io_err_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + netif_device_detach(netdev); + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t rtw_pci_io_slot_reset(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtw_dev *rtwdev = hw->priv; + + rtw_fw_recovery(rtwdev); + + return PCI_ERS_RESULT_RECOVERED; +} + +static void rtw_pci_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, PCI_D0, 0); + + netif_device_attach(netdev); +} + +const struct pci_error_handlers rtw_pci_err_handler = { + .error_detected = rtw_pci_io_err_detected, + .slot_reset = rtw_pci_io_slot_reset, + .resume = rtw_pci_io_resume, +}; +EXPORT_SYMBOL(rtw_pci_err_handler); + int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h index 13988db1cb4c..8ffdea11378f 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.h +++ b/drivers/net/wireless/realtek/rtw88/pci.h @@ -231,6 +231,7 @@ struct rtw_pci { }; extern const struct dev_pm_ops rtw_pm_ops; +extern const struct pci_error_handlers rtw_pci_err_handler; int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtw_pci_remove(struct pci_dev *pdev); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723de.c b/drivers/net/wireless/realtek/rtw88/rtw8723de.c index 87c8bc9d18a9..c6d0c88e5d81 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723de.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723de.c @@ -23,6 +23,7 @@ static struct pci_driver rtw_8723de_driver = { .remove = rtw_pci_remove, .driver.pm = &rtw_pm_ops, .shutdown = rtw_pci_shutdown, + .err_handler = &rtw_pci_err_handler, }; module_pci_driver(rtw_8723de_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821ce.c b/drivers/net/wireless/realtek/rtw88/rtw8821ce.c index 40637c079d99..52a19cb17daa 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821ce.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821ce.c @@ -27,6 +27,7 @@ static struct pci_driver rtw_8821ce_driver = { .remove = rtw_pci_remove, .driver.pm = &rtw_pm_ops, .shutdown = rtw_pci_shutdown, + .err_handler = &rtw_pci_err_handler, }; module_pci_driver(rtw_8821ce_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822be.c b/drivers/net/wireless/realtek/rtw88/rtw8822be.c index 0bb9f70e7920..dda597d73219 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822be.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822be.c @@ -23,6 +23,7 @@ static struct pci_driver rtw_8822be_driver = { .remove = rtw_pci_remove, .driver.pm = &rtw_pm_ops, .shutdown = rtw_pci_shutdown, + .err_handler = &rtw_pci_err_handler, }; module_pci_driver(rtw_8822be_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822ce.c b/drivers/net/wireless/realtek/rtw88/rtw8822ce.c index 9def732480af..7ae95415c224 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822ce.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822ce.c @@ -27,6 +27,7 @@ static struct pci_driver rtw_8822ce_driver = { .remove = rtw_pci_remove, .driver.pm = &rtw_pm_ops, .shutdown = rtw_pci_shutdown, + .err_handler = &rtw_pci_err_handler, }; module_pci_driver(rtw_8822ce_driver); From 16e3d93c6183649a3b210f82b83c1cb12aa5e8a3 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 23 May 2025 14:27:11 +0800 Subject: [PATCH 03/63] wifi: rtw89: pci: add PCI Express error handling Sometimes PCIe Advanced Error Reporting(AER), like bad TLP or Data link protocol error, happens due to unstable pci signal or no response from PCI host. pcieport 0000:00:1c.0: AER: Uncorrected (Non-Fatal) error message received from 0000:01:00.0 rtw89_8852be 0000:01:00.0: PCIe Bus Error: severity=Uncorrected (Non-Fatal), type=Transaction Layer, (Requester ID) rtw89_8852be 0000:01:00.0: device [10ec:b852] error status/mask=00004000/00400000 rtw89_8852be 0000:01:00.0: [14] CmpltTO (First) rtw89_8852be 0000:01:00.0: SER catches error: 0x4000 pcieport 0000:00:1c.0: AER: device recovery successful rtw89_8852be 0000:01:00.0: FW backtrace invalid key: 0xbb6c3214 ieee80211 phy0: Hardware restart was requested Setup callback function to call SER function to reset driver to recover from these states. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250523062711.27213-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 37 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/pci.h | 1 + .../net/wireless/realtek/rtw89/rtw8851be.c | 1 + .../net/wireless/realtek/rtw89/rtw8852ae.c | 1 + .../net/wireless/realtek/rtw89/rtw8852be.c | 1 + .../net/wireless/realtek/rtw89/rtw8852bte.c | 1 + .../net/wireless/realtek/rtw89/rtw8852ce.c | 1 + .../net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 8 files changed, 44 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 064f6a940107..204a3748d913 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -4353,6 +4353,43 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev) SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume); EXPORT_SYMBOL(rtw89_pm_ops); +static pci_ers_result_t rtw89_pci_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + netif_device_detach(netdev); + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t rtw89_pci_io_slot_reset(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtw89_dev *rtwdev = hw->priv; + + rtw89_ser_notify(rtwdev, MAC_AX_ERR_ASSERTION); + + return PCI_ERS_RESULT_RECOVERED; +} + +static void rtw89_pci_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, PCI_D0, 0); + + netif_device_attach(netdev); +} + +const struct pci_error_handlers rtw89_pci_err_handler = { + .error_detected = rtw89_pci_io_error_detected, + .slot_reset = rtw89_pci_io_slot_reset, + .resume = rtw89_pci_io_resume, +}; +EXPORT_SYMBOL(rtw89_pci_err_handler); + const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .isr_rdu = B_AX_RDU_INT, .isr_halt_c2h = B_AX_HALT_C2H_INT_EN, diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 79fef5f90140..52f527069da6 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -1622,6 +1622,7 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val) extern const struct dev_pm_ops rtw89_pm_ops; extern const struct dev_pm_ops rtw89_pm_ops_be; +extern const struct pci_error_handlers rtw89_pci_err_handler; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index 5810af825242..598730831707 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -89,6 +89,7 @@ static struct pci_driver rtw89_8851be_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8851be_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index 2037713e3952..90ffaf9f4f6a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -91,6 +91,7 @@ static struct pci_driver rtw89_8852ae_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8852ae_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index abdeafc14b0b..b0726f590ca2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -93,6 +93,7 @@ static struct pci_driver rtw89_8852be_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8852be_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c index b69fa17beb33..a584c75b801d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c @@ -95,6 +95,7 @@ static struct pci_driver rtw89_8852bte_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8852bte_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 5d864fd5974e..db01d3966c27 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -118,6 +118,7 @@ static struct pci_driver rtw89_8852ce_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8852ce_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 0ea8d5281c10..b730d79edd10 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -106,6 +106,7 @@ static struct pci_driver rtw89_8922ae_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops_be, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8922ae_driver); From 53cf488927a0f79968f9c03c4d1e00d2a79731c3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 28 May 2025 11:11:02 +0300 Subject: [PATCH 04/63] wifi: rtw89: mcc: prevent shift wrapping in rtw89_core_mlsr_switch() The "link_id" value comes from the user via debugfs. If it's larger than BITS_PER_LONG then that would result in shift wrapping and potentially an out of bounds access later. In fact, we can limit it to IEEE80211_MLD_MAX_NUM_LINKS (15). Fortunately, only root can write to debugfs files so the security impact is minimal. Fixes: 9dd85e739ce0 ("wifi: rtw89: debug: add mlo_mode dbgfs") Signed-off-by: Dan Carpenter Reviewed-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/aDbFFkX09K7FrL9h@stanley.mountain --- drivers/net/wireless/realtek/rtw89/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 49447668cbf3..3604a8e15df0 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -5239,7 +5239,8 @@ int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, if (unlikely(!ieee80211_vif_is_mld(vif))) return -EOPNOTSUPP; - if (unlikely(!(usable_links & BIT(link_id)))) { + if (unlikely(link_id >= IEEE80211_MLD_MAX_NUM_LINKS || + !(usable_links & BIT(link_id)))) { rtw89_warn(rtwdev, "%s: link id %u is not usable\n", __func__, link_id); return -ENOLINK; From 74f3516f94f404d2c91ec886fbb35cc6eddaa055 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Tue, 3 Jun 2025 18:31:23 +0300 Subject: [PATCH 05/63] wifi: rtw89: fix spelling mistake of RTW89_FLAG_FORBIDDEN_TRACK_WORK Rename RTW89_FLAG_FORBIDDEN_TRACK_WROK -> RTW89_FLAG_FORBIDDEN_TRACK_WORK. Found by Linux Verification Center (linuxtesting.org). Signed-off-by: Fedor Pchelkin Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250603153124.188755-1-pchelkin@ispras.ru --- drivers/net/wireless/realtek/rtw89/core.c | 2 +- drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 3604a8e15df0..d45a0b813416 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3742,7 +3742,7 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work) lockdep_assert_wiphy(wiphy); - if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags)) + if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags)) return; if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 1c8f3b9b7c4c..a081fce1466f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4912,7 +4912,7 @@ enum rtw89_flags { RTW89_FLAG_CRASH_SIMULATING, RTW89_FLAG_SER_HANDLING, RTW89_FLAG_WOWLAN, - RTW89_FLAG_FORBIDDEN_TRACK_WROK, + RTW89_FLAG_FORBIDDEN_TRACK_WORK, RTW89_FLAG_CHANGING_INTERFACE, RTW89_FLAG_HW_RFKILL_STATE, diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index a47971003bd4..a8e8b098cc9c 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -1698,13 +1698,13 @@ static int rtw89_ops_suspend(struct ieee80211_hw *hw, lockdep_assert_wiphy(hw->wiphy); - set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); + set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_work); ret = rtw89_wow_suspend(rtwdev, wowlan); if (ret) { rtw89_warn(rtwdev, "failed to suspend for wow %d\n", ret); - clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); + clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); return 1; } @@ -1722,7 +1722,7 @@ static int rtw89_ops_resume(struct ieee80211_hw *hw) if (ret) rtw89_warn(rtwdev, "failed to resume for wow %d\n", ret); - clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); + clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); From 6fe21445f7e801de5527d420f8e25e97b0cdd7e2 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Wed, 4 Jun 2025 19:13:32 +0300 Subject: [PATCH 06/63] wifi: rtw89: sar: drop lockdep assertion in rtw89_set_sar_from_acpi The following assertion is triggered on the rtw89 driver startup. It looks meaningless to hold wiphy lock on the early init stage so drop the assertion. WARNING: CPU: 7 PID: 629 at drivers/net/wireless/realtek/rtw89/sar.c:502 rtw89_set_sar_from_acpi+0x365/0x4d0 [rtw89_core] CPU: 7 UID: 0 PID: 629 Comm: (udev-worker) Not tainted 6.15.0+ #29 PREEMPT(lazy) Hardware name: LENOVO 21D0/LNVNB161216, BIOS J6CN50WW 09/27/2024 RIP: 0010:rtw89_set_sar_from_acpi+0x365/0x4d0 [rtw89_core] Call Trace: rtw89_sar_init+0x68/0x2c0 [rtw89_core] rtw89_core_init+0x188e/0x1e50 [rtw89_core] rtw89_pci_probe+0x530/0xb50 [rtw89_pci] local_pci_probe+0xd9/0x190 pci_call_probe+0x183/0x540 pci_device_probe+0x171/0x2c0 really_probe+0x1e1/0x890 __driver_probe_device+0x18c/0x390 driver_probe_device+0x4a/0x120 __driver_attach+0x1a0/0x530 bus_for_each_dev+0x10b/0x190 bus_add_driver+0x2eb/0x540 driver_register+0x1a3/0x3a0 do_one_initcall+0xd5/0x450 do_init_module+0x2cc/0x8f0 init_module_from_file+0xe1/0x150 idempotent_init_module+0x226/0x760 __x64_sys_finit_module+0xcd/0x150 do_syscall_64+0x94/0x380 entry_SYSCALL_64_after_hwframe+0x76/0x7e Found by Linux Verification Center (linuxtesting.org). Fixes: 88ca3107d2ce ("wifi: rtw89: sar: add skeleton for SAR configuration via ACPI") Signed-off-by: Fedor Pchelkin Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250604161339.119954-1-pchelkin@ispras.ru --- drivers/net/wireless/realtek/rtw89/sar.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c index 517b66022f18..33a4b5c23fe7 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.c +++ b/drivers/net/wireless/realtek/rtw89/sar.c @@ -499,8 +499,6 @@ static void rtw89_set_sar_from_acpi(struct rtw89_dev *rtwdev) struct rtw89_sar_cfg_acpi *cfg; int ret; - lockdep_assert_wiphy(rtwdev->hw->wiphy); - cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) return; From dad7aafa5216e307b357b801668451a3b8945810 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Wed, 4 Jun 2025 19:13:33 +0300 Subject: [PATCH 07/63] wifi: rtw89: sar: do not assert wiphy lock held until probing is done rtw89_sar_set_src() may be called at driver early init phase when applying SAR configuration via ACPI. wiphy lock is not held there. Since the assertion was initially added for rtw89_apply_sar_common() call path and may be helpful for other places in future changes, keep it but move it under RTW89_FLAG_PROBE_DONE test. Found by Linux Verification Center (linuxtesting.org). Fixes: 88ca3107d2ce ("wifi: rtw89: sar: add skeleton for SAR configuration via ACPI") Signed-off-by: Fedor Pchelkin Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250604161339.119954-2-pchelkin@ispras.ru --- drivers/net/wireless/realtek/rtw89/sar.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c index 33a4b5c23fe7..7f568ffb3766 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.c +++ b/drivers/net/wireless/realtek/rtw89/sar.c @@ -199,7 +199,8 @@ struct rtw89_sar_handler rtw89_sar_handlers[RTW89_SAR_SOURCE_NR] = { typeof(_dev) _d = (_dev); \ BUILD_BUG_ON(!rtw89_sar_handlers[_s].descr_sar_source); \ BUILD_BUG_ON(!rtw89_sar_handlers[_s].query_sar_config); \ - lockdep_assert_wiphy(_d->hw->wiphy); \ + if (test_bit(RTW89_FLAG_PROBE_DONE, _d->flags)) \ + lockdep_assert_wiphy(_d->hw->wiphy); \ _d->sar._cfg_name = *(_cfg_data); \ _d->sar.src = _s; \ } while (0) From 6cd93f85af7a1573c2fdb1da8977cd200a1c157e Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 5 Jun 2025 19:42:03 +0800 Subject: [PATCH 08/63] wifi: rtw89: chan: concentrate the logic of setting/clearing chanctx bitmap Originally, the logic for setting bits was wrapped inside the configuring function. However, raw clearing bits, clear_bit, was called directly. To be more paired and more understandable. Concentrate the logic of them into the same function. (don't change logic at all) Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250605114207.12381-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 806f42429a29..5e7f3c3bf1a6 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -170,22 +170,26 @@ int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev, static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, - const struct cfg80211_chan_def *chandef, - bool from_stack) + const struct cfg80211_chan_def *chandef) { struct rtw89_hal *hal = &rtwdev->hal; hal->chanctx[idx].chandef = *chandef; - - if (from_stack) - set_bit(idx, hal->entity_map); } void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, const struct cfg80211_chan_def *chandef) { - __rtw89_config_entity_chandef(rtwdev, idx, chandef, true); + struct rtw89_hal *hal = &rtwdev->hal; + + if (!chandef) { + clear_bit(idx, hal->entity_map); + return; + } + + __rtw89_config_entity_chandef(rtwdev, idx, chandef); + set_bit(idx, hal->entity_map); } void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev, @@ -227,7 +231,7 @@ static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev) struct cfg80211_chan_def chandef = {0}; rtw89_get_default_chandef(&chandef); - __rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef, false); + __rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef); } void rtw89_entity_init(struct rtw89_dev *rtwdev) @@ -2782,10 +2786,9 @@ int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx) { - struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; - clear_bit(cfg->idx, hal->entity_map); + rtw89_config_entity_chandef(rtwdev, cfg->idx, NULL); } void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, From 6c661eec292cd62a7c7abced8e91fc1b6ebf7f3a Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 5 Jun 2025 19:42:04 +0800 Subject: [PATCH 09/63] wifi: rtw89: chan: re-config default chandef only when none is registered Previously, default chandef is configured if no chanctx is active, i.e. no chanctx is assigned to some vif. For normal cases, it's fine. However, for impending CSA support, need to consider that one chanctx may be added, or called registered, ahead without being assigned immediately. Then, it will keep inactive, and might be covered by the default one when re-calculating chanctxs happens in certain sequences. So now, don't re-config the default chandef unless no chanctx is registered. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250605114207.12381-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 5 ++++- drivers/net/wireless/realtek/rtw89/chan.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 5e7f3c3bf1a6..31e15f472740 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -269,6 +269,8 @@ static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif; int idx; + w->registered_chanctxs = bitmap_weight(hal->entity_map, NUM_OF_RTW89_CHANCTX); + for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_CHANCTX) { cfg = hal->chanctx[idx].cfg; if (!cfg) { @@ -477,7 +479,8 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) bitmap_zero(recalc_map, NUM_OF_RTW89_CHANCTX); fallthrough; case 0: - rtw89_config_default_chandef(rtwdev); + if (!w.registered_chanctxs) + rtw89_config_default_chandef(rtwdev); set_bit(RTW89_CHANCTX_0, recalc_map); fallthrough; case 1: diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 2a25563593af..c75260eca71d 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -58,6 +58,7 @@ struct rtw89_chanctx_cb_parm { }; struct rtw89_entity_weight { + unsigned int registered_chanctxs; unsigned int active_chanctxs; unsigned int active_roles; }; From edba3f107844bbf91b7b89272d3d26c5c0d19a37 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 5 Jun 2025 19:42:05 +0800 Subject: [PATCH 10/63] wifi: rtw89: implement channel switch support To support channel switch on STA mode, declare IEEE80211_HW_CHANCTX_STA_CSA and implement ieee80211_ops::switch_vif_chanctx. Handling of CSA procedure still relies on mac80211 SW flow, since FW doesn't support chanctx offload. To support channel switch on AP mode, declare WIPHY_FLAG_HAS_CHANNEL_SWITCH and implement ieee80211_ops::channel_switch_beacon additionally. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250605114207.12381-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 32 +++++++++ drivers/net/wireless/realtek/rtw89/chan.h | 5 ++ drivers/net/wireless/realtek/rtw89/core.c | 40 +++++++++++ drivers/net/wireless/realtek/rtw89/core.h | 2 + drivers/net/wireless/realtek/rtw89/mac80211.c | 72 +++++++++++++++++++ 5 files changed, 151 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 31e15f472740..b2bc650a911b 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -2912,3 +2912,35 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, break; } } + +int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_chanctx_conf *old_ctx, + struct ieee80211_chanctx_conf *new_ctx, + bool replace) +{ + int ret; + + rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, old_ctx); + + if (!replace) + goto assign; + + rtw89_chanctx_ops_remove(rtwdev, old_ctx); + ret = rtw89_chanctx_ops_add(rtwdev, new_ctx); + if (ret) { + rtw89_err(rtwdev, "%s: failed to add chanctx: %d\n", + __func__, ret); + return ret; + } + +assign: + ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, new_ctx); + if (ret) { + rtw89_err(rtwdev, "%s: failed to assign chanctx: %d\n", + __func__, ret); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index c75260eca71d..9c5e61ccab88 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -143,5 +143,10 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx); +int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_chanctx_conf *old_ctx, + struct ieee80211_chanctx_conf *new_ctx, + bool replace); #endif diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index d45a0b813416..0a4c420000b8 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -204,6 +204,7 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = { }; static const u8 rtw89_ext_capa_sta[] = { + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, }; @@ -4655,6 +4656,43 @@ void rtw89_core_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); } +void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_vif_link *rtwvif_link = + container_of(work, struct rtw89_vif_link, csa_beacon_work.work); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct ieee80211_bss_conf *bss_conf; + unsigned int delay; + + lockdep_assert_wiphy(wiphy); + + if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE) + return; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->csa_active) { + rcu_read_unlock(); + return; + } + + delay = ieee80211_tu_to_usec(bss_conf->beacon_int); + + rcu_read_unlock(); + + if (!ieee80211_beacon_cntdwn_is_complete(vif, rtwvif_link->link_id)) { + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); + + wiphy_delayed_work_queue(wiphy, &rtwvif_link->csa_beacon_work, + usecs_to_jiffies(delay)); + } else { + ieee80211_csa_finish(vif, rtwvif_link->link_id); + } +} + int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond) { struct completion *cmpl = &wait->completion; @@ -5505,6 +5543,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ieee80211_hw_set(hw, WANT_MONITOR_VIF); + ieee80211_hw_set(hw, CHANCTX_STA_CSA); if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); @@ -5531,6 +5570,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP | WIPHY_FLAG_AP_UAPSD | + WIPHY_FLAG_HAS_CHANNEL_SWITCH | WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK; if (!chip->support_rnr) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a081fce1466f..ddd207326503 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3533,6 +3533,7 @@ struct rtw89_vif_link { bool pwr_diff_en; u8 def_tri_idx; struct wiphy_work update_beacon_work; + struct wiphy_delayed_work csa_beacon_work; struct rtw89_addr_cam_entry addr_cam; struct rtw89_bssid_cam_entry bssid_cam; struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS]; @@ -7317,6 +7318,7 @@ void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond, int rtw89_core_start(struct rtw89_dev *rtwdev); void rtw89_core_stop(struct rtw89_dev *rtwdev); void rtw89_core_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); +void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw89_roc_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index a8e8b098cc9c..7dc91c063979 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -112,6 +112,8 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, rtw89_vif_type_mapping(rtwvif_link, false); 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); + INIT_LIST_HEAD(&rtwvif_link->general_pkt_list); rtw89_p2p_noa_once_init(rtwvif_link); @@ -144,6 +146,7 @@ static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev, lockdep_assert_wiphy(rtwdev->hw->wiphy); wiphy_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->update_beacon_work); + wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->csa_beacon_work); rtw89_p2p_noa_once_deinit(rtwvif_link); @@ -1354,6 +1357,73 @@ static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw, rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, ctx); } +static +int rtw89_ops_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + struct rtw89_dev *rtwdev = hw->priv; + bool replace; + int ret; + int i; + + lockdep_assert_wiphy(hw->wiphy); + + switch (mode) { + case CHANCTX_SWMODE_REASSIGN_VIF: + replace = false; + break; + case CHANCTX_SWMODE_SWAP_CONTEXTS: + replace = true; + break; + default: + return -EOPNOTSUPP; + } + + for (i = 0; i < n_vifs; i++) { + struct ieee80211_vif_chanctx_switch *p = &vifs[i]; + struct ieee80211_bss_conf *link_conf = p->link_conf; + struct rtw89_vif *rtwvif = vif_to_rtwvif(p->vif); + struct rtw89_vif_link *rtwvif_link; + + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + return -ENOLINK; + } + + ret = rtw89_chanctx_ops_reassign_vif(rtwdev, rtwvif_link, + p->old_ctx, p->new_ctx, + replace); + if (ret) + return ret; + } + + return 0; +} + +static void rtw89_ops_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif_link *rtwvif_link; + + BUILD_BUG_ON(RTW89_MLD_NON_STA_LINK_NUM != 1); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "chsw bcn: find no link on HW-0\n"); + return; + } + + wiphy_delayed_work_queue(hw->wiphy, &rtwvif_link->csa_beacon_work, 0); +} + static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, @@ -1805,6 +1875,8 @@ const struct ieee80211_ops rtw89_ops = { .change_chanctx = rtw89_ops_change_chanctx, .assign_vif_chanctx = rtw89_ops_assign_vif_chanctx, .unassign_vif_chanctx = rtw89_ops_unassign_vif_chanctx, + .switch_vif_chanctx = rtw89_ops_switch_vif_chanctx, + .channel_switch_beacon = rtw89_ops_channel_switch_beacon, .remain_on_channel = rtw89_ops_remain_on_channel, .cancel_remain_on_channel = rtw89_ops_cancel_remain_on_channel, .set_sar_specs = rtw89_ops_set_sar_specs, From 28bb3d842e8f1ef0fb83257334e9d5cb1cff3d70 Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Thu, 5 Jun 2025 19:42:06 +0800 Subject: [PATCH 11/63] wifi: rtw89: add EHT physts and adjust init flow accordingly Adding EHT physts and adjust IE bitmap initialization. This setting is for PHY statistic gathering, won't effect functionality. Signed-off-by: Eric Huang Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250605114207.12381-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 73 ++++++++++++------------ drivers/net/wireless/realtek/rtw89/phy.h | 1 + drivers/net/wireless/realtek/rtw89/reg.h | 1 + 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 76a2e26d4a10..158550485797 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -5828,14 +5828,20 @@ void rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev) __rtw89_phy_env_monitor_track(rtwdev, bb); } -static bool rtw89_physts_ie_page_valid(enum rtw89_phy_status_bitmap *ie_page) +static bool rtw89_physts_ie_page_valid(struct rtw89_dev *rtwdev, + enum rtw89_phy_status_bitmap *ie_page) { + const struct rtw89_chip_info *chip = rtwdev->chip; + if (*ie_page >= RTW89_PHYSTS_BITMAP_NUM || *ie_page == RTW89_RSVD_9) return false; - else if (*ie_page > RTW89_RSVD_9) + else if (*ie_page > RTW89_RSVD_9 && *ie_page < RTW89_EHT_PKT) *ie_page -= 1; + if (*ie_page == RTW89_EHT_PKT && chip->chip_gen == RTW89_CHIP_AX) + return false; + return true; } @@ -5843,6 +5849,9 @@ static u32 rtw89_phy_get_ie_bitmap_addr(enum rtw89_phy_status_bitmap ie_page) { static const u8 ie_page_shift = 2; + if (ie_page == RTW89_EHT_PKT) + return R_PHY_STS_BITMAP_EHT; + return R_PHY_STS_BITMAP_ADDR_START + (ie_page << ie_page_shift); } @@ -5852,7 +5861,7 @@ static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev, { u32 addr; - if (!rtw89_physts_ie_page_valid(&ie_page)) + if (!rtw89_physts_ie_page_valid(rtwdev, &ie_page)) return 0; addr = rtw89_phy_get_ie_bitmap_addr(ie_page); @@ -5867,7 +5876,7 @@ static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev, const struct rtw89_chip_info *chip = rtwdev->chip; u32 addr; - if (!rtw89_physts_ie_page_valid(&ie_page)) + if (!rtw89_physts_ie_page_valid(rtwdev, &ie_page)) return; if (chip->chip_id == RTL8852A) @@ -5877,21 +5886,6 @@ static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev, rtw89_phy_write32_idx(rtwdev, addr, MASKDWORD, val, phy_idx); } -static void rtw89_physts_enable_ie_bitmap(struct rtw89_dev *rtwdev, - enum rtw89_phy_status_bitmap bitmap, - enum rtw89_phy_status_ie_type ie, - bool enable, enum rtw89_phy_idx phy_idx) -{ - u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap, phy_idx); - - if (enable) - val |= BIT(ie); - else - val &= ~BIT(ie); - - rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val, phy_idx); -} - static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev, bool enable, enum rtw89_phy_idx phy_idx) @@ -5915,30 +5909,37 @@ static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev, static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 val; u8 i; rtw89_physts_enable_fail_report(rtwdev, false, phy_idx); for (i = 0; i < RTW89_PHYSTS_BITMAP_NUM; i++) { - if (i >= RTW89_CCK_PKT) - rtw89_physts_enable_ie_bitmap(rtwdev, i, - RTW89_PHYSTS_IE09_FTR_0, - true, phy_idx); - if ((i >= RTW89_CCK_BRK && i <= RTW89_VHT_MU) || - (i >= RTW89_RSVD_9 && i <= RTW89_CCK_PKT)) + if (i == RTW89_RSVD_9 || + (i == RTW89_EHT_PKT && chip->chip_gen == RTW89_CHIP_AX)) continue; - rtw89_physts_enable_ie_bitmap(rtwdev, i, - RTW89_PHYSTS_IE24_OFDM_TD_PATH_A, - true, phy_idx); - } - rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_VHT_PKT, - RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx); - rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_HE_PKT, - RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx); - /* force IE01 for channel index, only channel field is valid */ - rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_CCK_PKT, - RTW89_PHYSTS_IE01_CMN_OFDM, true, phy_idx); + val = rtw89_physts_get_ie_bitmap(rtwdev, i, phy_idx); + if (i == RTW89_HE_MU || i == RTW89_VHT_MU) { + val |= BIT(RTW89_PHYSTS_IE13_DL_MU_DEF); + } else if (i == RTW89_TRIG_BASE_PPDU) { + val |= BIT(RTW89_PHYSTS_IE13_DL_MU_DEF) | + BIT(RTW89_PHYSTS_IE01_CMN_OFDM); + } else if (i >= RTW89_CCK_PKT) { + val |= BIT(RTW89_PHYSTS_IE09_FTR_0); + + val &= ~(GENMASK(RTW89_PHYSTS_IE07_CMN_EXT_PATH_D, + RTW89_PHYSTS_IE04_CMN_EXT_PATH_A)); + + if (i == RTW89_CCK_PKT) + val |= BIT(RTW89_PHYSTS_IE01_CMN_OFDM); + else if (i >= RTW89_HT_PKT) + val |= BIT(RTW89_PHYSTS_IE20_DBG_OFDM_FD_USER_SEG_0); + } + + rtw89_physts_set_ie_bitmap(rtwdev, i, val, phy_idx); + } } static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 5b451f1cfaac..63cc33c16c9a 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -252,6 +252,7 @@ enum rtw89_phy_status_bitmap { RTW89_HT_PKT = 13, RTW89_VHT_PKT = 14, RTW89_HE_PKT = 15, + RTW89_EHT_PKT = 16, RTW89_PHYSTS_BITMAP_NUM }; diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index f05c81ae5869..255a8635b195 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -8024,6 +8024,7 @@ #define R_PHY_STS_BITMAP_HT 0x076C #define R_PHY_STS_BITMAP_VHT 0x0770 #define R_PHY_STS_BITMAP_HE 0x0774 +#define R_PHY_STS_BITMAP_EHT 0x0788 #define R_EDCCA_RPTREG_SEL_BE 0x078C #define B_EDCCA_RPTREG_SEL_BE_MSK GENMASK(22, 20) #define R_PMAC_GNT 0x0980 From fe30a8ae853bade282fce63e740b5f34bdc55f6e Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Thu, 5 Jun 2025 19:42:07 +0800 Subject: [PATCH 12/63] wifi: rtw89: fix EHT 20MHz TX rate for non-AP STA The 4-octet EHT MCS/NSS subfield is only used for 20 MHz-only non-AP STA. Correct the interpretation of this subfield to prevent improper rate limitations. Fixes: f1dfcee2eae9 ("wifi: rtw89: Correct EHT TX rate on 20MHz connection") Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250605114207.12381-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 158550485797..a05841304e0e 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -119,10 +119,12 @@ static u64 get_eht_mcs_ra_mask(u8 *max_nss, u8 start_mcs, u8 n_nss) return mask; } -static u64 get_eht_ra_mask(struct ieee80211_link_sta *link_sta) +static u64 get_eht_ra_mask(struct rtw89_vif_link *rtwvif_link, + struct ieee80211_link_sta *link_sta) { - struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct ieee80211_eht_mcs_nss_supp_20mhz_only *mcs_nss_20mhz; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; struct ieee80211_eht_mcs_nss_supp_bw *mcs_nss; u8 *he_phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info; @@ -136,8 +138,8 @@ static u64 get_eht_ra_mask(struct ieee80211_link_sta *link_sta) /* MCS 9, 11, 13 */ return get_eht_mcs_ra_mask(mcs_nss->rx_tx_max_nss, 9, 3); case IEEE80211_STA_RX_BW_20: - if (!(he_phy_cap[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) { + if (vif->type == NL80211_IFTYPE_AP && + !(he_phy_cap[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) { mcs_nss_20mhz = &eht_cap->eht_mcs_nss_supp.only_20mhz; /* MCS 7, 9, 11, 13 */ return get_eht_mcs_ra_mask(mcs_nss_20mhz->rx_tx_max_nss, 7, 4); @@ -332,7 +334,7 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, /* Set the ra mask from sta's capability */ if (link_sta->eht_cap.has_eht) { mode |= RTW89_RA_MODE_EHT; - ra_mask |= get_eht_ra_mask(link_sta); + ra_mask |= get_eht_ra_mask(rtwvif_link, link_sta); if (rtwdev->hal.no_mcs_12_13) high_rate_masks = rtw89_ra_mask_eht_mcs0_11; From 4bcef86b13316511bb336a26140fc4130c3a65a2 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Fri, 6 Jun 2025 10:02:57 +0800 Subject: [PATCH 13/63] wifi: rtw89: 8852c: increase beacon loss to 6 seconds Intermittent beacon loss from a specific AP causes the connection to be lost. Increasing the beacon loss count can make the connection more stable. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250606020302.16873-2-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 00b65b2995cf..36147040c35b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -838,6 +838,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), __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, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), From 29dc4c560219ef0b2fa667d5f1f1e8df11e38f5a Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 6 Jun 2025 10:02:58 +0800 Subject: [PATCH 14/63] wifi: rtw89: fw: add RFE type to RF TSSI H2C command Append a new field for RFE (RF Front End) type to RF TSSI H2C command. FW has forward compatibility when handling this H2C command, so just need to consider backward cases in FW point of view. | old FW | new FW ------------------------------ old driver | O | X ------------------------------ new driver | O | O Currently only RTL8922A uses this RF TSSI H2C command. Increase its FW format max and will let new FW binary align with it. Then, old driver won't load new FW. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250606020302.16873-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 2 ++ drivers/net/wireless/realtek/rtw89/fw.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 36147040c35b..1d37ea7f1391 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -6032,6 +6032,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, 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) { + struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_h2c_rf_tssi *h2c; u32 len = sizeof(*h2c); @@ -6054,6 +6055,7 @@ int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, h2c->hwtx_en = true; h2c->cv = hal->cv; h2c->tssi_mode = tssi_mode; + h2c->rfe_type = efuse->rfe_type; rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(rtwdev, phy_idx, chan, h2c); rtw89_phy_rfk_tssi_fill_fwcmd_tmeter_tbl(rtwdev, phy_idx, chan, h2c); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 0fcc824e41be..2fc2d1d61e29 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4435,6 +4435,7 @@ struct rtw89_h2c_rf_tssi { u8 pg_thermal[2]; u8 ftable[2][128]; u8 tssi_mode; + u8 rfe_type; } __packed; struct rtw89_h2c_rf_iqk { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 1d0f6e7df497..680168f31466 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -15,7 +15,7 @@ #include "sar.h" #include "util.h" -#define RTW8922A_FW_FORMAT_MAX 3 +#define RTW8922A_FW_FORMAT_MAX 4 #define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw" #define RTW8922A_MODULE_FIRMWARE \ RTW8922A_FW_BASENAME "-" __stringify(RTW8922A_FW_FORMAT_MAX) ".bin" From b9b8828fdf8c5871ee2e7e701c907547285ff311 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 6 Jun 2025 10:02:59 +0800 Subject: [PATCH 15/63] wifi: rtw89: rfk: support IQK firmware command v1 Add new IQK firmware command format v1 (with suffix), and rename original command format to v0 for older firmware. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250606020302.16873-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 30 +++++++++++++++++++++-- drivers/net/wireless/realtek/rtw89/fw.h | 13 +++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index ddd207326503..c79164757bd9 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4514,6 +4514,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V1, RTW89_FW_FEATURE_RFK_RXDCK_V0, + RTW89_FW_FEATURE_RFK_IQK_V0, RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX, RTW89_FW_FEATURE_NOTIFY_AP_INFO, RTW89_FW_FEATURE_CH_INFO_BE_V0, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 1d37ea7f1391..0547eb11d378 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -845,6 +845,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 21, 0, SCAN_OFFLOAD_BE_V0), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 12, 0, BEACON_FILTER), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 22, 0, WOW_REASON_V1), + __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 28, 0, RFK_IQK_V0), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, RFK_PRE_NOTIFY_V0), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, LPS_CH_INFO), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 42, 0, RFK_RXDCK_V0), @@ -6080,22 +6081,47 @@ int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan) { + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_h2c_rf_iqk_v0 *h2c_v0; struct rtw89_h2c_rf_iqk *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; + u8 ver = U8_MAX; int ret; + if (RTW89_CHK_FW_FEATURE(RFK_IQK_V0, &rtwdev->fw)) { + len = sizeof(*h2c_v0); + ver = 0; + } + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c RF IQK\n"); return -ENOMEM; } skb_put(skb, len); + + if (ver == 0) { + h2c_v0 = (struct rtw89_h2c_rf_iqk_v0 *)skb->data; + + h2c_v0->phy_idx = cpu_to_le32(phy_idx); + h2c_v0->dbcc = cpu_to_le32(rtwdev->dbcc_en); + + goto done; + } + h2c = (struct rtw89_h2c_rf_iqk *)skb->data; - h2c->phy_idx = cpu_to_le32(phy_idx); - h2c->dbcc = cpu_to_le32(rtwdev->dbcc_en); + h2c->len = sizeof(*h2c); + h2c->ktype = 0; + h2c->phy = phy_idx; + h2c->kpath = rtw89_phy_get_kpath(rtwdev, phy_idx); + h2c->band = chan->band_type; + h2c->bw = chan->band_width; + h2c->ch = chan->channel; + h2c->cv = hal->cv; +done: rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, H2C_FUNC_RFK_IQK_OFFLOAD, 0, 0, len); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 2fc2d1d61e29..d4815bcce91b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4438,11 +4438,22 @@ struct rtw89_h2c_rf_tssi { u8 rfe_type; } __packed; -struct rtw89_h2c_rf_iqk { +struct rtw89_h2c_rf_iqk_v0 { __le32 phy_idx; __le32 dbcc; } __packed; +struct rtw89_h2c_rf_iqk { + u8 len; + u8 ktype; + u8 phy; + u8 kpath; + u8 band; + u8 bw; + u8 ch; + u8 cv; +} __packed; + struct rtw89_h2c_rf_dpk { u8 len; u8 phy; From b0efb82651afce32999ebeba1f48ad2c5f53a356 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 6 Jun 2025 10:03:00 +0800 Subject: [PATCH 16/63] wifi: rtw89: mac: add dummy handler of MAC C2H event class 27 The newer firmware add new C2H event class 27, which is to report WiFi role status. Since rtw89 doesn't use the status yet, add a dummy handler to avoid warning: rtw89_8922ae 0000:03:00.0: MAC c2h class 27 func 0 not support Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250606020302.16873-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 1 + drivers/net/wireless/realtek/rtw89/mac.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 9f0e30e75009..4bd5e2728ce5 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5717,6 +5717,7 @@ void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, handler = rtw89_mac_c2h_ap_handler[func]; break; case RTW89_MAC_C2H_CLASS_FWDBG: + case RTW89_MAC_C2H_CLASS_ROLE: return; default: rtw89_info(rtwdev, "MAC c2h class %d not support\n", class); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 8013c852d5be..c1cbc53b16a7 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -469,6 +469,7 @@ enum rtw89_mac_c2h_class { RTW89_MAC_C2H_CLASS_MLO = 0xc, RTW89_MAC_C2H_CLASS_MRC = 0xe, RTW89_MAC_C2H_CLASS_AP = 0x18, + RTW89_MAC_C2H_CLASS_ROLE = 0x1b, RTW89_MAC_C2H_CLASS_MAX, }; From d310eaf4ad51ad738c31848483abb2f45834819a Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Fri, 6 Jun 2025 10:04:08 +0800 Subject: [PATCH 17/63] wifi: rtw89: add chip_ops::chan_to_rf18_val to get code of RF register value The RF 0x18 register stores radio frequency domain parameters, including band, center channel and bandwidth. This information is used in RF domain. Add a chip_ops to retrieve the RF 0x18 value, which allows driver to query for a specific channel. No logic is changed. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250606020408.17035-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 13 +++++ 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 | 43 +++++++++++++++ .../net/wireless/realtek/rtw89/rtw8922a_rfk.c | 52 ++----------------- 8 files changed, 66 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c79164757bd9..c93d3ea2b0a4 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3646,6 +3646,8 @@ struct rtw89_chip_ops { enum rtw89_phy_idx phy_idx); int (*init_txpwr_unit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); u8 (*get_thermal)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path); + u32 (*chan_to_rf18_val)(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan); void (*ctrl_btg_bt_rx)(struct rtw89_dev *rtwdev, bool en, enum rtw89_phy_idx phy_idx); void (*query_ppdu)(struct rtw89_dev *rtwdev, @@ -6882,6 +6884,17 @@ static inline u8 rtw89_chip_get_thermal(struct rtw89_dev *rtwdev, return chip->ops->get_thermal(rtwdev, rf_path); } +static inline u32 rtw89_chip_chan_to_rf18_val(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (!chip->ops->chan_to_rf18_val) + return 0; + + return chip->ops->chan_to_rf18_val(rtwdev, chan); +} + static inline void rtw89_chip_query_ppdu(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct ieee80211_rx_status *status) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index fafa200a9c8d..39df1a255095 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2402,6 +2402,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .set_txpwr_ctrl = rtw8851b_set_txpwr_ctrl, .init_txpwr_unit = rtw8851b_init_txpwr_unit, .get_thermal = rtw8851b_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8851b_ctrl_btg_bt_rx, .query_ppdu = rtw8851b_query_ppdu, .convert_rpl_to_rssi = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index cd5987fc52d7..dc4eab2e7919 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2128,6 +2128,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .set_txpwr_ctrl = rtw8852a_set_txpwr_ctrl, .init_txpwr_unit = rtw8852a_init_txpwr_unit, .get_thermal = rtw8852a_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8852a_ctrl_btg_bt_rx, .query_ppdu = rtw8852a_query_ppdu, .convert_rpl_to_rssi = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index dacdb384de2c..1f1e10f2b39d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -755,6 +755,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .set_txpwr_ctrl = rtw8852bx_set_txpwr_ctrl, .init_txpwr_unit = rtw8852bx_init_txpwr_unit, .get_thermal = rtw8852bx_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8852bx_ctrl_btg_bt_rx, .query_ppdu = rtw8852bx_query_ppdu, .convert_rpl_to_rssi = rtw8852bx_convert_rpl_to_rssi, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 289dce688d72..4c34f5037908 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -689,6 +689,7 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .set_txpwr_ctrl = rtw8852bx_set_txpwr_ctrl, .init_txpwr_unit = rtw8852bx_init_txpwr_unit, .get_thermal = rtw8852bx_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8852bx_ctrl_btg_bt_rx, .query_ppdu = rtw8852bx_query_ppdu, .convert_rpl_to_rssi = rtw8852bx_convert_rpl_to_rssi, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 2a6143a8d256..b39add1b798c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2948,6 +2948,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .set_txpwr_ctrl = rtw8852c_set_txpwr_ctrl, .init_txpwr_unit = rtw8852c_init_txpwr_unit, .get_thermal = rtw8852c_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8852c_ctrl_btg_bt_rx, .query_ppdu = rtw8852c_query_ppdu, .convert_rpl_to_rssi = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 680168f31466..ca32ccb00107 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2390,6 +2390,48 @@ static u8 rtw8922a_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p return clamp_t(int, th, 0, U8_MAX); } +static u32 rtw8922a_chan_to_rf18_val(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + u32 val = u32_encode_bits(chan->channel, RR_CFGCH_CH); + + switch (chan->band_type) { + case RTW89_BAND_2G: + default: + break; + case RTW89_BAND_5G: + val |= u32_encode_bits(CFGCH_BAND1_5G, RR_CFGCH_BAND1) | + u32_encode_bits(CFGCH_BAND0_5G, RR_CFGCH_BAND0); + break; + case RTW89_BAND_6G: + val |= u32_encode_bits(CFGCH_BAND1_6G, RR_CFGCH_BAND1) | + u32_encode_bits(CFGCH_BAND0_6G, RR_CFGCH_BAND0); + break; + } + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_5: + case RTW89_CHANNEL_WIDTH_10: + case RTW89_CHANNEL_WIDTH_20: + default: + break; + case RTW89_CHANNEL_WIDTH_40: + val |= u32_encode_bits(CFGCH_BW_V2_40M, RR_CFGCH_BW_V2); + break; + case RTW89_CHANNEL_WIDTH_80: + val |= u32_encode_bits(CFGCH_BW_V2_80M, RR_CFGCH_BW_V2); + break; + case RTW89_CHANNEL_WIDTH_160: + val |= u32_encode_bits(CFGCH_BW_V2_160M, RR_CFGCH_BW_V2); + break; + case RTW89_CHANNEL_WIDTH_320: + val |= u32_encode_bits(CFGCH_BW_V2_320M, RR_CFGCH_BW_V2); + break; + } + + return val; +} + static void rtw8922a_btc_set_rfe(struct rtw89_dev *rtwdev) { union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo; @@ -2761,6 +2803,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .set_txpwr_ctrl = rtw8922a_set_txpwr_ctrl, .init_txpwr_unit = NULL, .get_thermal = rtw8922a_get_thermal, + .chan_to_rf18_val = rtw8922a_chan_to_rf18_val, .ctrl_btg_bt_rx = rtw8922a_ctrl_btg_bt_rx, .query_ppdu = rtw8922a_query_ppdu, .convert_rpl_to_rssi = rtw8922a_convert_rpl_to_rssi, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index 1659ea64ade1..fce094c7ce93 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -36,8 +36,7 @@ void rtw8922a_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx) static void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, - u8 central_ch, enum rtw89_band band, - enum rtw89_bandwidth bw) + const struct rtw89_chan *chan) { const u32 rf_addr[2] = {RR_CFGCH, RR_CFGCH_V1}; struct rtw89_hal *hal = &rtwdev->hal; @@ -73,49 +72,9 @@ void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, return; } - rf_reg[path][i] &= ~(RR_CFGCH_BAND1 | RR_CFGCH_BW | + rf_reg[path][i] &= ~(RR_CFGCH_BAND1 | RR_CFGCH_BW_V2 | RR_CFGCH_BAND0 | RR_CFGCH_CH); - rf_reg[path][i] |= u32_encode_bits(central_ch, RR_CFGCH_CH); - - switch (band) { - case RTW89_BAND_2G: - default: - break; - case RTW89_BAND_5G: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BAND1_5G, RR_CFGCH_BAND1) | - u32_encode_bits(CFGCH_BAND0_5G, RR_CFGCH_BAND0); - break; - case RTW89_BAND_6G: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BAND1_6G, RR_CFGCH_BAND1) | - u32_encode_bits(CFGCH_BAND0_6G, RR_CFGCH_BAND0); - break; - } - - switch (bw) { - case RTW89_CHANNEL_WIDTH_5: - case RTW89_CHANNEL_WIDTH_10: - case RTW89_CHANNEL_WIDTH_20: - default: - break; - case RTW89_CHANNEL_WIDTH_40: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BW_V2_40M, RR_CFGCH_BW_V2); - break; - case RTW89_CHANNEL_WIDTH_80: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BW_V2_80M, RR_CFGCH_BW_V2); - break; - case RTW89_CHANNEL_WIDTH_160: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BW_V2_160M, RR_CFGCH_BW_V2); - break; - case RTW89_CHANNEL_WIDTH_320: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BW_V2_320M, RR_CFGCH_BW_V2); - break; - } + rf_reg[path][i] |= rtw89_chip_chan_to_rf18_val(rtwdev, chan); rtw89_write_rf(rtwdev, path, rf_addr[i], RFREG_MASK, rf_reg[path][i]); @@ -126,7 +85,7 @@ void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, if (hal->cv != CHIP_CAV) return; - if (band == RTW89_BAND_2G) { + if (chan->band_type == RTW89_BAND_2G) { rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x80000); rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x00003); rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD1, RFREG_MASK, 0x0c990); @@ -145,8 +104,7 @@ void rtw8922a_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) { - rtw8922a_ctl_band_ch_bw(rtwdev, phy_idx, chan->channel, chan->band_type, - chan->band_width); + rtw8922a_ctl_band_ch_bw(rtwdev, phy_idx, chan); } enum _rf_syn_pow { From 389e578dd2803099f78d2ec1fe680d0fb0f3f66c Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Fri, 6 Jun 2025 10:04:37 +0800 Subject: [PATCH 18/63] wifi: rtw89: 8922a: pass channel information when enter LPS Newer firmware requires the driver to pass channel information when switching from normal mode to low power mode; otherwise it will result in poor RX beacon performance. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250606020437.17160-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 59 +++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 8 ++++ drivers/net/wireless/realtek/rtw89/ps.c | 2 + 3 files changed, 69 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 0547eb11d378..95865eafb2cd 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5919,6 +5919,65 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_fw_h2c_rf_ntfy_mcc); +int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_h2c_rf_ps_info *h2c; + const struct rtw89_chan *chan; + u32 len = sizeof(*h2c); + unsigned int link_id; + struct sk_buff *skb; + int ret; + u8 path; + u32 val; + + if (chip->chip_gen != RTW89_CHIP_BE) + return 0; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c rf ps info\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_rf_ps_info *)skb->data; + h2c->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + 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) { + rtw89_err(rtwdev, "unsupported rf path (%d)\n", path); + ret = -ENOENT; + goto fail; + } + + h2c->rf18[path] = cpu_to_le32(val); + h2c->pri_ch[path] = chan->primary_channel; + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY, + H2C_FUNC_OUTSRC_RF_PS_INFO, 0, 0, + sizeof(*h2c)); + + 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_rf_ps_info); + int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index d4815bcce91b..14f55b10be2e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4337,6 +4337,7 @@ enum rtw89_mrc_h2c_func { #define H2C_CL_OUTSRC_RF_REG_B 0x9 #define H2C_CL_OUTSRC_RF_FW_NOTIFY 0xa #define H2C_FUNC_OUTSRC_RF_GET_MCCCH 0x2 +#define H2C_FUNC_OUTSRC_RF_PS_INFO 0x10 #define H2C_CL_OUTSRC_RF_FW_RFK 0xb enum rtw89_rfk_offload_h2c_func { @@ -4361,6 +4362,12 @@ struct rtw89_fw_h2c_rf_get_mccch { #define NUM_OF_RTW89_FW_RFK_PATH 2 #define NUM_OF_RTW89_FW_RFK_TBL 3 +struct rtw89_h2c_rf_ps_info { + __le32 rf18[NUM_OF_RTW89_FW_RFK_PATH]; + __le32 mlo_mode; + u8 pri_ch[NUM_OF_RTW89_FW_RFK_PATH]; +} __packed; + struct rtw89_fw_h2c_rfk_pre_info_common { struct { __le32 ch[NUM_OF_RTW89_FW_RFK_PATH][NUM_OF_RTW89_FW_RFK_TBL]; @@ -4744,6 +4751,7 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info, u16 len, u8 page); 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_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index 8e4fe73e7d77..c255c2f9b945 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -137,6 +137,8 @@ void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, can_ps_mode = false; } + rtw89_fw_h2c_rf_ps_info(rtwdev, rtwvif); + if (RTW89_CHK_FW_FEATURE(LPS_CH_INFO, &rtwdev->fw)) rtw89_fw_h2c_lps_ch_info(rtwdev, rtwvif); else From 57d6be36cf422e259955d72d994fd1fb668104f8 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 7 Jun 2025 20:59:53 +0300 Subject: [PATCH 19/63] wifi: rtw88: Rename the RTW_WCPU_11{AC,N} enums The RTW_WCPU_11AC and RTW_WCPU_11N enums are used to identify two types of microcontrollers used in Realtek chips, but these names are misleading. The "11AC" type was also used in 11n devices (e.g. RTL8733BU, not supported by rtw88), and the "11N" type was also used in 11ac devices (RTL8821AU, RTL8812AU). Rename RTW_WCPU_11AC to RTW_WCPU_3081 and RTW_WCPU_11N to RTW_WCPU_8051. (8051 is well known. It's less clear what 3081 is, but the out of tree drivers use this name.) Signed-off-by: Bitterblue Smith Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/bfb1099c-db52-4b25-b111-17ab712e9404@gmail.com --- drivers/net/wireless/realtek/rtw88/fw.c | 8 +++---- drivers/net/wireless/realtek/rtw88/mac.c | 22 +++++++++---------- drivers/net/wireless/realtek/rtw88/main.c | 2 +- drivers/net/wireless/realtek/rtw88/main.h | 12 +++++----- drivers/net/wireless/realtek/rtw88/pci.c | 12 +++++----- drivers/net/wireless/realtek/rtw88/rtw8703b.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8723d.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8812a.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8814a.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8821a.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8821c.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8822b.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 2 +- drivers/net/wireless/realtek/rtw88/sdio.c | 8 +++---- 14 files changed, 40 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 4fc78b882080..c68a9fff6808 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -521,7 +521,7 @@ rtw_fw_send_general_info(struct rtw_dev *rtwdev) u8 h2c_pkt[H2C_PKT_SIZE] = {0}; u16 total_size = H2C_PKT_HDR_SIZE + 4; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return; rtw_h2c_pkt_set_header(h2c_pkt, H2C_PKT_GENERAL_INFO); @@ -544,7 +544,7 @@ rtw_fw_send_phydm_info(struct rtw_dev *rtwdev) u16 total_size = H2C_PKT_HDR_SIZE + 8; u8 fw_rf_type = 0; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return; if (hal->rf_type == RF_1T1R) @@ -1480,7 +1480,7 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, bckp[2] = rtw_read8(rtwdev, REG_BCN_CTRL); - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { rtw_write32_set(rtwdev, REG_DWBCN0_CTRL, BIT_BCN_VALID); } else { pg_addr &= BIT_MASK_BCN_HEAD_1_V1; @@ -1509,7 +1509,7 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, goto restore; } - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { bcn_valid_addr = REG_DWBCN0_CTRL; bcn_valid_mask = BIT_BCN_VALID; } else { diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index f66d1b302dc5..011b81c82f3b 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -41,7 +41,7 @@ void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, } rtw_write32(rtwdev, REG_WMAC_TRXPTCL_CTL, value32); - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return; value32 = rtw_read32(rtwdev, REG_AFE_CTRL1) & ~(BIT_MAC_CLK_SEL); @@ -67,7 +67,7 @@ static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev) rtw_write8(rtwdev, REG_RSV_CTRL, 0); - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { if (rtw_read32(rtwdev, REG_SYS_CFG1) & BIT_LDO) rtw_write8(rtwdev, REG_LDO_SWR_CTRL, LDO_SEL); else @@ -278,7 +278,7 @@ static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) bool cur_pwr; int ret; - if (rtw_chip_wcpu_11ac(rtwdev)) { + if (rtw_chip_wcpu_3081(rtwdev)) { rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); /* Check FW still exist or not */ @@ -369,7 +369,7 @@ static int __rtw_mac_init_system_cfg_legacy(struct rtw_dev *rtwdev) static int rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) { - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return __rtw_mac_init_system_cfg_legacy(rtwdev); return __rtw_mac_init_system_cfg(rtwdev); @@ -981,7 +981,7 @@ static int __rtw_download_firmware_legacy(struct rtw_dev *rtwdev, static int _rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) { - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return __rtw_download_firmware_legacy(rtwdev, fw); return __rtw_download_firmware(rtwdev, fw); @@ -1122,7 +1122,7 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev) rtw_write8(rtwdev, REG_CR, 0); rtw_write8(rtwdev, REG_CR, MAC_TRX_ENABLE); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) { @@ -1145,7 +1145,7 @@ int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev) /* config rsvd page num */ fifo->rsvd_drv_pg_num = chip->rsvd_drv_pg_num; fifo->txff_pg_num = chip->txff_size / chip->page_size; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num; else fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num + @@ -1163,7 +1163,7 @@ int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev) fifo->rsvd_boundary = fifo->txff_pg_num - fifo->rsvd_pg_num; cur_pg_addr = fifo->txff_pg_num; - if (rtw_chip_wcpu_11ac(rtwdev)) { + if (rtw_chip_wcpu_3081(rtwdev)) { cur_pg_addr -= csi_buf_pg_num; fifo->rsvd_csibuf_addr = cur_pg_addr; cur_pg_addr -= RSVD_PG_FW_TXBUF_NUM; @@ -1292,7 +1292,7 @@ static int priority_queue_cfg(struct rtw_dev *rtwdev) pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return __priority_queue_cfg_legacy(rtwdev, pg_tbl, pubq_num); else return __priority_queue_cfg(rtwdev, pg_tbl, pubq_num); @@ -1308,7 +1308,7 @@ static int init_h2c(struct rtw_dev *rtwdev) u32 h2cq_free; u32 wp, rp; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return 0; h2cq_addr = fifo->rsvd_h2cq_addr << TX_PAGE_SIZE_SHIFT; @@ -1375,7 +1375,7 @@ static int rtw_drv_info_cfg(struct rtw_dev *rtwdev) u8 value8; rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE); - if (rtw_chip_wcpu_11ac(rtwdev)) { + if (rtw_chip_wcpu_3081(rtwdev)) { value8 = rtw_read8(rtwdev, REG_TRXFF_BNDY + 1); value8 &= 0xF0; /* For rxdesc len = 0 issue */ diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 26b1479d3521..3ec3689fae3d 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1766,7 +1766,7 @@ static void __update_firmware_info_legacy(struct rtw_dev *rtwdev, static void update_firmware_info(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) { - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) __update_firmware_info_legacy(rtwdev, fw); else __update_firmware_info(rtwdev, fw); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index b0f1fabe9554..89b72d2a9f99 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1173,8 +1173,8 @@ struct rtw_pwr_track_tbl { }; enum rtw_wlan_cpu { - RTW_WCPU_11AC, - RTW_WCPU_11N, + RTW_WCPU_3081, + RTW_WCPU_8051, }; enum rtw_fw_fifo_sel { @@ -2166,14 +2166,14 @@ static inline void rtw_chip_efuse_grant_off(struct rtw_dev *rtwdev) rtwdev->chip->ops->efuse_grant(rtwdev, false); } -static inline bool rtw_chip_wcpu_11n(struct rtw_dev *rtwdev) +static inline bool rtw_chip_wcpu_8051(struct rtw_dev *rtwdev) { - return rtwdev->chip->wlan_cpu == RTW_WCPU_11N; + return rtwdev->chip->wlan_cpu == RTW_WCPU_8051; } -static inline bool rtw_chip_wcpu_11ac(struct rtw_dev *rtwdev) +static inline bool rtw_chip_wcpu_3081(struct rtw_dev *rtwdev) { - return rtwdev->chip->wlan_cpu == RTW_WCPU_11AC; + return rtwdev->chip->wlan_cpu == RTW_WCPU_3081; } static inline bool rtw_chip_has_rx_ldpc(struct rtw_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 6655de2b9726..56b16186d3aa 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -405,7 +405,7 @@ static void rtw_pci_reset_buf_desc(struct rtw_dev *rtwdev) dma = rtwpci->tx_rings[RTW_TX_QUEUE_BCN].r.dma; rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_BCNQ, dma); - if (!rtw_chip_wcpu_11n(rtwdev)) { + if (!rtw_chip_wcpu_8051(rtwdev)) { len = rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.len; dma = rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.dma; rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.rp = 0; @@ -467,7 +467,7 @@ static void rtw_pci_reset_buf_desc(struct rtw_dev *rtwdev) rtw_write32(rtwdev, RTK_PCI_TXBD_RWPTR_CLR, 0xffffffff); /* reset H2C Queue index in a single write */ - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR, BIT_CLR_H2CQ_HOST_IDX | BIT_CLR_H2CQ_HW_IDX); } @@ -487,7 +487,7 @@ static void rtw_pci_enable_interrupt(struct rtw_dev *rtwdev, rtw_write32(rtwdev, RTK_PCI_HIMR0, rtwpci->irq_mask[0] & ~imr0_unmask); rtw_write32(rtwdev, RTK_PCI_HIMR1, rtwpci->irq_mask[1]); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32(rtwdev, RTK_PCI_HIMR3, rtwpci->irq_mask[3]); rtwpci->irq_enabled = true; @@ -507,7 +507,7 @@ static void rtw_pci_disable_interrupt(struct rtw_dev *rtwdev, rtw_write32(rtwdev, RTK_PCI_HIMR0, 0); rtw_write32(rtwdev, RTK_PCI_HIMR1, 0); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32(rtwdev, RTK_PCI_HIMR3, 0); rtwpci->irq_enabled = false; @@ -1125,7 +1125,7 @@ static void rtw_pci_irq_recognized(struct rtw_dev *rtwdev, irq_status[0] = rtw_read32(rtwdev, RTK_PCI_HISR0); irq_status[1] = rtw_read32(rtwdev, RTK_PCI_HISR1); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) irq_status[3] = rtw_read32(rtwdev, RTK_PCI_HISR3); else irq_status[3] = 0; @@ -1134,7 +1134,7 @@ static void rtw_pci_irq_recognized(struct rtw_dev *rtwdev, irq_status[3] &= rtwpci->irq_mask[3]; rtw_write32(rtwdev, RTK_PCI_HISR0, irq_status[0]); rtw_write32(rtwdev, RTK_PCI_HISR1, irq_status[1]); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32(rtwdev, RTK_PCI_HISR3, irq_status[3]); spin_unlock_irqrestore(&rtwpci->hwirq_lock, flags); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c index 9e6700c43a63..03475af973b5 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c @@ -1882,7 +1882,7 @@ const struct rtw_chip_info rtw8703b_hw_spec = { .id = RTW_CHIP_TYPE_8703B, .fw_name = "rtw88/rtw8703b_fw.bin", - .wlan_cpu = RTW_WCPU_11N, + .wlan_cpu = RTW_WCPU_8051, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 31876e708f9e..bf69f5b06ce2 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -2116,7 +2116,7 @@ const struct rtw_chip_info rtw8723d_hw_spec = { .ops = &rtw8723d_ops, .id = RTW_CHIP_TYPE_8723D, .fw_name = "rtw88/rtw8723d_fw.bin", - .wlan_cpu = RTW_WCPU_11N, + .wlan_cpu = RTW_WCPU_8051, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c index c2ef41767ff9..03b441639611 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -1038,7 +1038,7 @@ const struct rtw_chip_info rtw8812a_hw_spec = { .ops = &rtw8812a_ops, .id = RTW_CHIP_TYPE_8812A, .fw_name = "rtw88/rtw8812a_fw.bin", - .wlan_cpu = RTW_WCPU_11N, + .wlan_cpu = RTW_WCPU_8051, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c index 44dd3090484b..4a1f850d05c8 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c @@ -2180,7 +2180,7 @@ const struct rtw_chip_info rtw8814a_hw_spec = { .ops = &rtw8814a_ops, .id = RTW_CHIP_TYPE_8814A, .fw_name = "rtw88/rtw8814a_fw.bin", - .wlan_cpu = RTW_WCPU_11AC, + .wlan_cpu = RTW_WCPU_3081, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c index 413aec694c33..1d02ea400b2e 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c @@ -1138,7 +1138,7 @@ const struct rtw_chip_info rtw8821a_hw_spec = { .ops = &rtw8821a_ops, .id = RTW_CHIP_TYPE_8821A, .fw_name = "rtw88/rtw8821a_fw.bin", - .wlan_cpu = RTW_WCPU_11N, + .wlan_cpu = RTW_WCPU_8051, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index 413130a30ca9..a2a358d6033f 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -1973,7 +1973,7 @@ const struct rtw_chip_info rtw8821c_hw_spec = { .ops = &rtw8821c_ops, .id = RTW_CHIP_TYPE_8821C, .fw_name = "rtw88/rtw8821c_fw.bin", - .wlan_cpu = RTW_WCPU_11AC, + .wlan_cpu = RTW_WCPU_3081, .tx_pkt_desc_sz = 48, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index ab199eaea3c7..9c31c859ccba 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -2513,7 +2513,7 @@ const struct rtw_chip_info rtw8822b_hw_spec = { .ops = &rtw8822b_ops, .id = RTW_CHIP_TYPE_8822B, .fw_name = "rtw88/rtw8822b_fw.bin", - .wlan_cpu = RTW_WCPU_11AC, + .wlan_cpu = RTW_WCPU_3081, .tx_pkt_desc_sz = 48, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 017d959de3ce..f813ce10172d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -5332,7 +5332,7 @@ const struct rtw_chip_info rtw8822c_hw_spec = { .ops = &rtw8822c_ops, .id = RTW_CHIP_TYPE_8822C, .fw_name = "rtw88/rtw8822c_fw.bin", - .wlan_cpu = RTW_WCPU_11AC, + .wlan_cpu = RTW_WCPU_3081, .tx_pkt_desc_sz = 48, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index e733ed846123..cc2d4fef3587 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -547,7 +547,7 @@ static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue, { unsigned int pages_free, pages_needed; - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { u32 free_txpg; free_txpg = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG); @@ -1030,7 +1030,7 @@ static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) u32 rx_len, hisr, total_rx_bytes = 0; do { - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) rx_len = rtw_read16(rtwdev, REG_SDIO_RX0_REQ_LEN); else rx_len = rtw_read32(rtwdev, REG_SDIO_RX0_REQ_LEN); @@ -1042,7 +1042,7 @@ static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) total_rx_bytes += rx_len; - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { /* Stop if no more RX requests are pending, even if * rx_len could be greater than zero in the next * iteration. This is needed because the RX buffer may @@ -1054,7 +1054,7 @@ static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) */ hisr = rtw_read32(rtwdev, REG_SDIO_HISR); } else { - /* RTW_WCPU_11AC chips have improved hardware or + /* RTW_WCPU_3081 chips have improved hardware or * firmware and can use rx_len unconditionally. */ hisr = REG_SDIO_HISR_RX_REQUEST; From 793905c70a56255b04e7cff82b01a300fff822be Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 7 Jun 2025 21:01:38 +0300 Subject: [PATCH 20/63] wifi: rtw88: Enable AP and adhoc modes for SDIO again AP mode can be enabled again for SDIO now that the problem was fixed in commit b2effcdc2379 ("wifi: rtw88: sdio: map mgmt frames to queue TX_DESC_QSEL_MGMT") and commit fc5f5a0ec463 ("wifi: rtw88: sdio: call rtw_sdio_indicate_tx_status unconditionally"). Signed-off-by: Bitterblue Smith Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/5ac60c1c-9cc8-41b8-871c-a067e74f70ea@gmail.com --- drivers/net/wireless/realtek/rtw88/main.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 3ec3689fae3d..97756bdf57b2 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -2219,7 +2219,6 @@ EXPORT_SYMBOL(rtw_core_deinit); int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) { - bool sta_mode_only = rtwdev->hci.type == RTW_HCI_TYPE_SDIO; struct rtw_hal *hal = &rtwdev->hal; int max_tx_headroom = 0; int ret; @@ -2249,12 +2248,9 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) ieee80211_hw_set(hw, TX_AMSDU); ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); - if (sta_mode_only) - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - else - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_ADHOC); + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->available_antennas_tx = hal->antenna_tx; hw->wiphy->available_antennas_rx = hal->antenna_rx; @@ -2265,7 +2261,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) hw->wiphy->max_scan_ssids = RTW_SCAN_MAX_SSIDS; hw->wiphy->max_scan_ie_len = rtw_get_max_scan_ie_len(rtwdev); - if (!sta_mode_only && rtwdev->chip->id == RTW_CHIP_TYPE_8822C) { + if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C) { hw->wiphy->iface_combinations = rtw_iface_combs; hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw_iface_combs); } From 2baacfe833460fee2f54b2c7270d632c98052cdc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 10 Jun 2025 11:22:23 +0200 Subject: [PATCH 21/63] wifi: rtlwifi: avoid stack size warning for _read_eeprom_info txpower_info_{2g,5g} are too big to fit on the stack, but in most of the rtlwifi variants this stays below the warning limit for stack frames. In rtl8192ee and a few others, I see a case where clang decides to fully inline this into rtl92ee_read_eeprom_info, triggering this warning: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c:2178:6: error: stack frame size (1312) exceeds limit (1280) in 'rtl92ee_read_eeprom_info' [-Werror,-Wframe-larger-than] Mark _rtl92ee_read_txpower_info_from_hwpg() as noinline_for_stack to and mark _rtl92ee_get_chnl_group() as __always_inline to make clang behave the same way as gcc. Inlining _rtl92ee_get_chnl_group helps let the compiler see that the index is always in range. The same change appears to be necessary in all rtlwifi variants. A more thorough approach would be to avoid the use of the two structures on the stack entirely and combine them with the struct rtl_efuse data that is dynamically allocated and holds the same information. Signed-off-by: Arnd Bergmann Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610092240.2639751-1-arnd@kernel.org --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c | 6 +++--- drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c | 6 +++--- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c | 6 +++--- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c | 7 ++++--- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c | 6 +++--- drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c | 6 +++--- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c | 6 +++--- 7 files changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c index 27f6c35ba0f9..4092018452cb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c @@ -1738,9 +1738,9 @@ static void read_power_value_fromprom(struct ieee80211_hw *hw, } } -static void _rtl88ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl88ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c index 0bc915723b93..5ca6b49e73c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c @@ -1412,9 +1412,9 @@ void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, rtl92ce_enable_interrupt(hw); } -static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index 0195c9a3e9e8..ec5d558609fe 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -95,9 +95,9 @@ static void _rtl92cu_phy_param_tab_init(struct ieee80211_hw *hw) } } -static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index d4da5cdc8414..48a3c94606be 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -1731,7 +1731,7 @@ void rtl92ee_update_interrupt_mask(struct ieee80211_hw *hw, rtl92ee_enable_interrupt(hw); } -static u8 _rtl92ee_get_chnl_group(u8 chnl) +static __always_inline u8 _rtl92ee_get_chnl_group(u8 chnl) { u8 group = 0; @@ -2009,8 +2009,9 @@ static void _rtl8192ee_read_power_value_fromprom(struct ieee80211_hw *hw, } } -static void _rtl92ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, u8 *hwinfo) +static noinline_for_stack void +_rtl92ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *efu = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index 6991713a66d0..21b827f519b6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -1381,9 +1381,9 @@ static u8 _rtl8723e_get_chnl_group(u8 chnl) return group; } -static void _rtl8723e_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl8723e_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index bcfc53af4c1a..e1f811218894 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -1935,9 +1935,9 @@ static void _rtl8723be_read_power_value_fromprom(struct ieee80211_hw *hw, } } -static void _rtl8723be_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl8723be_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index f4b232f038a9..8c51f4d36820 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -2782,9 +2782,9 @@ static void _rtl8812ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory); } #endif -static void _rtl8821ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl8821ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); From 9b550b98f0da3ba80e63c431e0cf4d7ae32c865b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 11 Jun 2025 14:55:21 +0100 Subject: [PATCH 22/63] wifi: rtlwifi: rtl8821ae: make the read-only array params static const Don't populate the read-only array params on the stack at run time, instead make it static const. Signed-off-by: Colin Ian King Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611135521.172521-1-colin.i.king@gmail.com --- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 8c51f4d36820..a5a34b5edcfd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -3064,10 +3064,12 @@ static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_ struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - int params[] = {RTL_EEPROM_ID, EEPROM_VID, EEPROM_DID, - EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, - EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, - COUNTRY_CODE_WORLD_WIDE_13}; + static const int params[] = { + RTL_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13 + }; u8 *hwinfo; if (b_pseudo_test) { From 76b3e5078d76f0eeadb7aacf9845399f8473da0d Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Fri, 13 Jun 2025 09:38:36 +0200 Subject: [PATCH 23/63] wifi: rtlwifi: fix possible skb memory leak in _rtl_pci_init_one_rxdesc() When `dma_mapping_error()` is true, if a new `skb` has been allocated, then it must be de-allocated. Compile tested only Signed-off-by: Thomas Fourier Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250613074014.69856-2-fourier.thomas@gmail.com --- drivers/net/wireless/realtek/rtlwifi/pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 898f597f70a9..472072630f8d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -572,8 +572,11 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, dma_map_single(&rtlpci->pdev->dev, skb_tail_pointer(skb), rtlpci->rxbuffersize, DMA_FROM_DEVICE); bufferaddress = *((dma_addr_t *)skb->cb); - if (dma_mapping_error(&rtlpci->pdev->dev, bufferaddress)) + if (dma_mapping_error(&rtlpci->pdev->dev, bufferaddress)) { + if (!new_skb) + kfree_skb(skb); return 0; + } rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb; if (rtlpriv->use_new_trx_flow) { /* skb->cb may be 64 bit address */ From dbaf5c3aa952ad0dcf5c21431bd534cff1cfad1f Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 10 Jun 2025 21:00:23 +0800 Subject: [PATCH 24/63] wifi: rtw89: extend HW scan of WiFi 6 chips for extra OP chan when concurrency HW scan flow has considered the timing when to get back op for the scanning interface. But, when concurrency, there are two interfaces with connection. The OP channel of another one was not back originally. It then easily lead to connection loss when scanning during concurrency. So, HW scan flow is extended to deal with second OP channel. And, H2C command is also extended to fill second MAC ID. The changes mentioned above are done for WiFi 6 chips first. HW scan has different handling architectures including FW and driver on WiFi 7 chips. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 8 ++ drivers/net/wireless/realtek/rtw89/fw.c | 136 +++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/fw.h | 7 +- drivers/net/wireless/realtek/rtw89/mac.c | 66 +++++++++-- 4 files changed, 191 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c93d3ea2b0a4..dca76b1c1029 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4524,6 +4524,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_NO_PHYCAP_P1, RTW89_FW_FEATURE_NO_POWER_DIFFERENCE, RTW89_FW_FEATURE_BEACON_LOSS_COUNT_V1, + RTW89_FW_FEATURE_SCAN_OFFLOAD_EXTRA_OP, }; struct rtw89_fw_suit { @@ -5451,11 +5452,18 @@ struct rtw89_early_h2c { u16 h2c_len; }; +struct rtw89_hw_scan_extra_op { + bool set; + u8 macid; + struct rtw89_chan chan; +}; + struct rtw89_hw_scan_info { struct rtw89_vif_link *scanning_vif; struct list_head pkt_list[NUM_NL80211_BANDS]; struct list_head chan_list; struct rtw89_chan op_chan; + struct rtw89_hw_scan_extra_op extra_op; bool connected; bool abort; }; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 95865eafb2cd..06fb97a05a89 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5363,6 +5363,7 @@ static int rtw89_fw_h2c_scan_list_offload_ax(struct rtw89_dev *rtwdev, int ch_num, struct list_head *chan_list) { + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_h2c_chinfo_elem *elem; struct rtw89_mac_chinfo_ax *ch_info; @@ -5405,6 +5406,10 @@ int rtw89_fw_h2c_scan_list_offload_ax(struct rtw89_dev *rtwdev, int ch_num, le32_encode_bits(ch_info->tx_null, RTW89_H2C_CHINFO_W1_TX_NULL) | le32_encode_bits(ch_info->rand_seq_num, RTW89_H2C_CHINFO_W1_RANDOM); + if (scan_info->extra_op.set) + elem->w1 |= le32_encode_bits(ch_info->macid_tx, + RTW89_H2C_CHINFO_W1_MACID_TX); + elem->w2 = le32_encode_bits(ch_info->pkt_id[0], RTW89_H2C_CHINFO_W2_PKT0) | le32_encode_bits(ch_info->pkt_id[1], RTW89_H2C_CHINFO_W2_PKT1) | le32_encode_bits(ch_info->pkt_id[2], RTW89_H2C_CHINFO_W2_PKT2) | @@ -5545,6 +5550,7 @@ int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool wowlan) { + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_chan *op = &rtwdev->scan_info.op_chan; enum rtw89_scan_mode scan_mode = RTW89_SCAN_IMMEDIATE; @@ -5604,6 +5610,10 @@ int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, h2c->tsf_low = le32_encode_bits(lower_32_bits(tsf), RTW89_H2C_SCANOFLD_W4_TSF_LOW); + if (scan_info->extra_op.set) + h2c->w6 = le32_encode_bits(scan_info->extra_op.macid, + RTW89_H2C_SCANOFLD_W6_SECOND_MACID); + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, H2C_FUNC_SCANOFLD, 1, 1, @@ -6933,6 +6943,7 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct ieee80211_scan_ies *ies = rtwvif->scan_ies; struct cfg80211_scan_request *req = rtwvif->scan_req; @@ -7003,6 +7014,15 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, case RTW89_CHAN_ACTIVE: ch_info->pause_data = true; break; + case RTW89_CHAN_EXTRA_OP: + ch_info->central_ch = ext->chan.channel; + ch_info->pri_ch = ext->chan.primary_channel; + ch_info->ch_band = ext->chan.band_type; + ch_info->bw = ext->chan.band_width; + ch_info->tx_null = true; + ch_info->num_pkt = 0; + ch_info->macid_tx = true; + break; default: rtw89_err(rtwdev, "Channel type out of bound\n"); } @@ -7161,10 +7181,45 @@ int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, return ret; } +static int rtw89_hw_scan_add_op_types_ax(struct rtw89_dev *rtwdev, + enum rtw89_chan_type type, + struct list_head *chan_list, + struct cfg80211_scan_request *req, + int *off_chan_time) +{ + struct rtw89_mac_chinfo_ax *tmp; + + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + switch (type) { + case RTW89_CHAN_OPERATE: + tmp->period = req->duration_mandatory ? + req->duration : RTW89_CHANNEL_TIME; + *off_chan_time = 0; + break; + case RTW89_CHAN_EXTRA_OP: + tmp->period = RTW89_CHANNEL_TIME_EXTRA_OP; + /* still calc @off_chan_time for scan op */ + *off_chan_time += tmp->period; + break; + default: + kfree(tmp); + return -EINVAL; + } + + rtw89_hw_scan_add_chan_ax(rtwdev, type, 0, tmp); + list_add_tail(&tmp->list, chan_list); + + return 0; +} + int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_mac_chinfo_ax *ch_info, *tmp; @@ -7207,22 +7262,28 @@ int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev, type = RTW89_CHAN_ACTIVE; rtw89_hw_scan_add_chan_ax(rtwdev, type, req->n_ssids, ch_info); - if (scan_info->connected && - off_chan_time + ch_info->period > RTW89_OFF_CHAN_TIME) { - tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); - if (!tmp) { - ret = -ENOMEM; - kfree(ch_info); - goto out; - } + if (!(scan_info->connected && + off_chan_time + ch_info->period > RTW89_OFF_CHAN_TIME)) + goto next; - type = RTW89_CHAN_OPERATE; - tmp->period = req->duration_mandatory ? - req->duration : RTW89_CHANNEL_TIME; - rtw89_hw_scan_add_chan_ax(rtwdev, type, 0, tmp); - list_add_tail(&tmp->list, &chan_list); - off_chan_time = 0; + ret = rtw89_hw_scan_add_op_types_ax(rtwdev, RTW89_CHAN_OPERATE, + &chan_list, req, &off_chan_time); + if (ret) { + kfree(ch_info); + goto out; } + + if (!ext->set) + goto next; + + ret = rtw89_hw_scan_add_op_types_ax(rtwdev, RTW89_CHAN_EXTRA_OP, + &chan_list, req, &off_chan_time); + if (ret) { + kfree(ch_info); + goto out; + } + +next: list_add_tail(&ch_info->list, &chan_list); off_chan_time += ch_info->period; } @@ -7524,6 +7585,47 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, } } +static void rtw89_hw_scan_set_extra_op_info(struct rtw89_dev *rtwdev, + struct rtw89_vif *scan_rtwvif, + const struct rtw89_chan *scan_op) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; + struct rtw89_vif *tmp; + + ext->set = false; + if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_EXTRA_OP, &rtwdev->fw)) + return; + + list_for_each_entry(tmp, &mgnt->active_list, mgnt_entry) { + const struct rtw89_chan *tmp_chan; + struct rtw89_vif_link *tmp_link; + + if (tmp == scan_rtwvif) + continue; + + tmp_link = rtw89_vif_get_link_inst(tmp, 0); + if (unlikely(!tmp_link)) { + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "hw scan: no HW-0 link for extra op\n"); + continue; + } + + tmp_chan = rtw89_chan_get(rtwdev, tmp_link->chanctx_idx); + *ext = (struct rtw89_hw_scan_extra_op){ + .set = true, + .macid = tmp_link->mac_id, + .chan = *tmp_chan, + }; + + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "hw scan: extra op: center %d primary %d\n", + ext->chan.channel, ext->chan.primary_channel); + break; + } +} + int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct ieee80211_scan_request *scan_req) @@ -7546,6 +7648,12 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, /* clone op and keep it during scan */ rtwdev->scan_info.op_chan = *chan; + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "hw scan: op: center %d primary %d\n", + chan->channel, chan->primary_channel); + + rtw89_hw_scan_set_extra_op_info(rtwdev, rtwvif, chan); + rtwdev->scan_info.connected = rtw89_is_any_vif_connected_or_connecting(rtwdev); rtwdev->scan_info.scanning_vif = rtwvif_link; rtwdev->scan_info.abort = false; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 14f55b10be2e..36abf1b59240 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -237,6 +237,7 @@ enum rtw89_chan_type { RTW89_CHAN_OPERATE = 0, RTW89_CHAN_ACTIVE, RTW89_CHAN_DFS, + RTW89_CHAN_EXTRA_OP, }; enum rtw89_p2pps_action { @@ -316,6 +317,7 @@ struct rtw89_fw_macid_pause_sleep_grp { #define RTW89_H2C_MAX_SIZE 2048 #define RTW89_CHANNEL_TIME 45 #define RTW89_CHANNEL_TIME_6G 20 +#define RTW89_CHANNEL_TIME_EXTRA_OP 30 #define RTW89_DFS_CHAN_TIME 105 #define RTW89_OFF_CHAN_TIME 100 #define RTW89_DWELL_TIME 20 @@ -352,7 +354,8 @@ struct rtw89_mac_chinfo_ax { u8 tx_null:1; u8 rand_seq_num:1; u8 cfg_tx_pwr:1; - u8 rsvd0: 4; + u8 macid_tx: 1; + u8 rsvd0: 3; u8 pkt_id[RTW89_SCANOFLD_MAX_SSID]; u16 tx_pwr_idx; u8 rsvd1; @@ -2674,6 +2677,7 @@ struct rtw89_h2c_chinfo_elem { #define RTW89_H2C_CHINFO_W1_TX_NULL BIT(25) #define RTW89_H2C_CHINFO_W1_RANDOM BIT(26) #define RTW89_H2C_CHINFO_W1_CFG_TX BIT(27) +#define RTW89_H2C_CHINFO_W1_MACID_TX BIT(29) #define RTW89_H2C_CHINFO_W2_PKT0 GENMASK(7, 0) #define RTW89_H2C_CHINFO_W2_PKT1 GENMASK(15, 8) #define RTW89_H2C_CHINFO_W2_PKT2 GENMASK(23, 16) @@ -2773,6 +2777,7 @@ struct rtw89_h2c_scanofld { #define RTW89_H2C_SCANOFLD_W2_SLOW_PD GENMASK(23, 16) #define RTW89_H2C_SCANOFLD_W3_TSF_HIGH GENMASK(31, 0) #define RTW89_H2C_SCANOFLD_W4_TSF_LOW GENMASK(31, 0) +#define RTW89_H2C_SCANOFLD_W6_SECOND_MACID GENMASK(31, 24) struct rtw89_h2c_scanofld_be_macc_role { __le32 w0; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 4bd5e2728ce5..8ec86e1fa9d6 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4388,7 +4388,33 @@ static void rtw89_mac_port_cfg_tx_sw_by_nettype(struct rtw89_dev *rtwdev, rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); } -void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en) +static void rtw89_mac_enable_ap_bcn_by_chan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + const struct rtw89_chan *to_match, + bool en) +{ + const struct rtw89_chan *chan; + + if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE) + return; + + if (!to_match) + goto doit; + + /* @to_match may not be in the same domain as return of calling + * rtw89_chan_get(). So, cannot compare their addresses directly. + */ + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + if (chan->channel != to_match->channel) + return; + +doit: + rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); +} + +static void rtw89_mac_enable_aps_bcn_by_chan(struct rtw89_dev *rtwdev, + const struct rtw89_chan *to_match, + bool en) { struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; @@ -4396,8 +4422,13 @@ void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en) rtw89_for_each_rtwvif(rtwdev, rtwvif) rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) - if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) - rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); + rtw89_mac_enable_ap_bcn_by_chan(rtwdev, rtwvif_link, + to_match, en); +} + +void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en) +{ + rtw89_mac_enable_aps_bcn_by_chan(rtwdev, NULL, en); } static void rtw89_mac_port_cfg_bcn_intv(struct rtw89_dev *rtwdev, @@ -4891,11 +4922,22 @@ rtw89_mac_c2h_macid_pause(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len { } -static bool rtw89_is_op_chan(struct rtw89_dev *rtwdev, u8 band, u8 channel) +static const struct rtw89_chan * +rtw89_hw_scan_search_op_chan(struct rtw89_dev *rtwdev, u8 band, u8 channel) { + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; const struct rtw89_chan *op = &rtwdev->scan_info.op_chan; - return band == op->band_type && channel == op->primary_channel; + if (band == op->band_type && channel == op->primary_channel) + return op; + + if (scan_info->extra_op.set) { + op = &scan_info->extra_op.chan; + if (band == op->band_type && channel == op->primary_channel) + return op; + } + + return NULL; } static void @@ -4905,6 +4947,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, const struct rtw89_c2h_scanofld *c2h = (const struct rtw89_c2h_scanofld *)skb->data; struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + const struct rtw89_chan *op_chan; struct rtw89_vif *rtwvif; struct rtw89_chan new; u16 actual_period, expect_period; @@ -4960,8 +5003,9 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, switch (reason) { case RTW89_SCAN_LEAVE_OP_NOTIFY: case RTW89_SCAN_LEAVE_CH_NOTIFY: - if (rtw89_is_op_chan(rtwdev, band, chan)) { - rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, false); + op_chan = rtw89_hw_scan_search_op_chan(rtwdev, band, chan); + if (op_chan) { + rtw89_mac_enable_aps_bcn_by_chan(rtwdev, op_chan, false); ieee80211_stop_queues(rtwdev->hw); } return; @@ -4982,10 +5026,10 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, break; case RTW89_SCAN_ENTER_OP_NOTIFY: case RTW89_SCAN_ENTER_CH_NOTIFY: - if (rtw89_is_op_chan(rtwdev, band, chan)) { - rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx, - &rtwdev->scan_info.op_chan); - rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); + op_chan = rtw89_hw_scan_search_op_chan(rtwdev, band, chan); + if (op_chan) { + rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx, op_chan); + rtw89_mac_enable_aps_bcn_by_chan(rtwdev, op_chan, true); ieee80211_wake_queues(rtwdev->hw); } else { rtw89_chan_create(&new, chan, chan, band, From 519defe4e8c83a418649c367158f6f8c38439d0a Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:24 +0800 Subject: [PATCH 25/63] wifi: rtw89: mcc: update format of RF notify MCC H2C command The RF notify MCC H2C command format of 8852C different from other chip, therefore add v0 format to update it. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 38 +++++++++++++++++------ drivers/net/wireless/realtek/rtw89/fw.h | 8 +++++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index dca76b1c1029..8c2a71ecfc0d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4525,6 +4525,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_NO_POWER_DIFFERENCE, RTW89_FW_FEATURE_BEACON_LOSS_COUNT_V1, RTW89_FW_FEATURE_SCAN_OFFLOAD_EXTRA_OP, + RTW89_FW_FEATURE_RFK_NTFY_MCC_V0, }; struct rtw89_fw_suit { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 06fb97a05a89..cde22f692dc2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -833,6 +833,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __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(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), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), @@ -5889,31 +5890,48 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev) { struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_fw_h2c_rf_get_mccch_v0 *mccch_v0; struct rtw89_fw_h2c_rf_get_mccch *mccch; + u32 len = sizeof(*mccch); struct sk_buff *skb; + u8 ver = U8_MAX; int ret; u8 idx; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, sizeof(*mccch)); + if (RTW89_CHK_FW_FEATURE(RFK_NTFY_MCC_V0, &rtwdev->fw)) { + len = sizeof(*mccch_v0); + ver = 0; + } + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n"); return -ENOMEM; } - skb_put(skb, sizeof(*mccch)); - mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data; + skb_put(skb, len); idx = rfk_mcc->table_idx; - mccch->ch_0 = cpu_to_le32(rfk_mcc->ch[0]); - mccch->ch_1 = cpu_to_le32(rfk_mcc->ch[1]); - mccch->band_0 = cpu_to_le32(rfk_mcc->band[0]); - mccch->band_1 = cpu_to_le32(rfk_mcc->band[1]); - mccch->current_channel = cpu_to_le32(rfk_mcc->ch[idx]); - mccch->current_band_type = cpu_to_le32(rfk_mcc->band[idx]); + if (ver == 0) { + mccch_v0 = (struct rtw89_fw_h2c_rf_get_mccch_v0 *)skb->data; + mccch_v0->ch_0 = cpu_to_le32(rfk_mcc->ch[0]); + mccch_v0->ch_1 = cpu_to_le32(rfk_mcc->ch[1]); + mccch_v0->band_0 = cpu_to_le32(rfk_mcc->band[0]); + mccch_v0->band_1 = cpu_to_le32(rfk_mcc->band[1]); + mccch_v0->current_band_type = cpu_to_le32(rfk_mcc->band[idx]); + mccch_v0->current_channel = cpu_to_le32(rfk_mcc->ch[idx]); + } else { + mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data; + mccch->ch_0_0 = cpu_to_le32(rfk_mcc->ch[0]); + mccch->ch_0_1 = cpu_to_le32(rfk_mcc->ch[0]); + mccch->ch_1_0 = cpu_to_le32(rfk_mcc->ch[1]); + mccch->ch_1_1 = cpu_to_le32(rfk_mcc->ch[1]); + mccch->current_channel = cpu_to_le32(rfk_mcc->ch[idx]); + } rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY, H2C_FUNC_OUTSRC_RF_GET_MCCCH, 0, 0, - sizeof(*mccch)); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 36abf1b59240..f9d5bcbc7c7e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4356,6 +4356,14 @@ enum rtw89_rfk_offload_h2c_func { }; struct rtw89_fw_h2c_rf_get_mccch { + __le32 ch_0_0; + __le32 ch_0_1; + __le32 ch_1_0; + __le32 ch_1_1; + __le32 current_channel; +} __packed; + +struct rtw89_fw_h2c_rf_get_mccch_v0 { __le32 ch_0; __le32 ch_1; __le32 band_0; From f70fe6eab088bb431d75cc411e7ac0f98c2bd734 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:25 +0800 Subject: [PATCH 26/63] wifi: rtw89: mcc: correct frequency when MCC The frequency get from PPDU status set as center channel during MCC, but we need to report to mac80211 as primary channel. Therefore, we use the chanctx information in software to instead it. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 0a4c420000b8..4252717b1584 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2478,6 +2478,41 @@ static void rtw89_core_update_rx_freq_from_ie(struct rtw89_dev *rtwdev, rx_status->freq = ieee80211_channel_to_frequency(chan, rx_status->band); } +static void rtw89_core_correct_mcc_chan(struct rtw89_dev *rtwdev, + struct rtw89_rx_desc_info *desc_info, + struct ieee80211_rx_status *rx_status, + struct rtw89_rx_phy_ppdu *phy_ppdu) +{ + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + const struct rtw89_chan *chan; + u8 mac_id = desc_info->mac_id; + enum rtw89_entity_mode mode; + enum nl80211_band band; + + mode = rtw89_get_entity_mode(rtwdev); + if (likely(mode != RTW89_ENTITY_MODE_MCC)) + return; + + if (chip_gen == RTW89_CHIP_BE && phy_ppdu) + mac_id = phy_ppdu->mac_id; + + rcu_read_lock(); + + rtwsta_link = rtw89_assoc_link_rcu_dereference(rtwdev, mac_id); + if (!rtwsta_link) + goto out; + + rtwvif_link = rtwsta_link->rtwvif_link; + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + band = rtw89_hw_to_nl80211_band(chan->band_type); + rx_status->freq = ieee80211_channel_to_frequency(chan->primary_channel, band); + +out: + rcu_read_unlock(); +} + static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct rtw89_rx_desc_info *desc_info, @@ -2496,6 +2531,7 @@ static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev, rtw89_core_update_radiotap(rtwdev, skb_ppdu, rx_status); rtw89_core_validate_rx_signal(rx_status); rtw89_core_update_rx_freq_from_ie(rtwdev, skb_ppdu, rx_status); + rtw89_core_correct_mcc_chan(rtwdev, desc_info, rx_status, phy_ppdu); /* In low power mode, it does RX in thread context. */ local_bh_disable(); From 95ee7464d374343115b5e7ec226f2bab2e4012f2 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:26 +0800 Subject: [PATCH 27/63] wifi: rtw89: mcc: adjust beacon filter when MCC and detect connection MCC needs to wait at most 300ms to start. Additionally, if scanning happens before MCC starts, it will miss some beacons, which might cause beacon loss. Therefore, we reset beacon filter when MCC start to let hardware reset beacon loss counter. Additionally, GO is forbid to enter courtesy mode might cause STA beacon loss. Therefore, disable beacon filter when GO+STA. However, In WiFi 7 chip, even when GC+STA enable courtesy mode, the beacon might loss because switching to courtesy timeslot will disable TX/RX. If the TOB(time offset behind) or TOA(time offset ahead) is too close to the edge of timeslot, the beacon might not be received. Therefore, disable beacon filter when GC+STA in WiFi 7 chip. Because disabling the beacon filter might prevent disconnection when the AP power-off without sending a deauth. Therefore, driver TX QOS nulldata periodically to detect the AP status, and the connection is terminated if no ACK is received for 6 seconds. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 50 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/chan.h | 3 ++ drivers/net/wireless/realtek/rtw89/core.c | 12 +++--- drivers/net/wireless/realtek/rtw89/core.h | 3 ++ 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index b2bc650a911b..2575aa174b05 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -2184,6 +2184,18 @@ static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev) rtw89_mcc_handle_beacon_noa(rtwdev, false); } +static bool rtw89_mcc_ignore_bcn(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role) +{ + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + + if (role->is_go) + return true; + else if (chip_gen == RTW89_CHIP_BE && role->is_gc) + return true; + else + return false; +} + static int rtw89_mcc_start(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -2207,6 +2219,15 @@ 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; @@ -2369,15 +2390,44 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) return 0; } +static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *role) +{ + struct ieee80211_vif *vif; + int ret; + + ret = rtw89_core_send_nullfunc(rtwdev, role->rtwvif_link, true, false, + RTW89_MCC_PROBE_TIMEOUT); + if (ret) + role->probe_count++; + else + role->probe_count = 0; + + if (role->probe_count < RTW89_MCC_PROBE_MAX_TRIES) + return; + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC can not detect AP\n", role->rtwvif_link->mac_id); + vif = rtwvif_link_to_vif(role->rtwvif_link); + ieee80211_connection_loss(vif); +} + static void rtw89_mcc_track(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; struct rtw89_mcc_config *config = &mcc->config; struct rtw89_mcc_pattern *pattern = &config->pattern; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; u16 tolerance; u16 bcn_ofst; u16 diff; + if (rtw89_mcc_ignore_bcn(rtwdev, ref)) + rtw89_mcc_detect_connection(rtwdev, aux); + else if (rtw89_mcc_ignore_bcn(rtwdev, aux)) + rtw89_mcc_detect_connection(rtwdev, ref); + if (mcc->mode != RTW89_MCC_MODE_GC_STA) return; diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 9c5e61ccab88..6036f3ca6f67 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -19,6 +19,9 @@ #define RTW89_MCC_MIN_RX_BCN_TIME 10 #define RTW89_MCC_DFLT_BCN_OFST_TIME 40 +#define RTW89_MCC_PROBE_TIMEOUT 100 +#define RTW89_MCC_PROBE_MAX_TRIES 3 + #define RTW89_MCC_MIN_GO_DURATION \ (RTW89_MCC_EARLY_TX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 4252717b1584..e7e2315d1867 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3367,8 +3367,8 @@ static void rtw89_core_handle_sta_pending_tx(struct rtw89_dev *rtwdev, rtwvif_link); } -static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, - struct rtw89_vif_link *rtwvif_link, bool qos, bool ps) +int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + bool qos, bool ps, int timeout) { struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); int link_id = ieee80211_vif_is_mld(vif) ? rtwvif_link->link_id : -1; @@ -3416,7 +3416,7 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, rcu_read_unlock(); return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel, - RTW89_ROC_TX_TIMEOUT); + timeout); out: rcu_read_unlock(); @@ -3453,7 +3453,8 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) pause_parm.trigger = rtwvif_link; rtw89_chanctx_pause(rtwdev, &pause_parm); - ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true); + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true, + RTW89_ROC_TX_TIMEOUT); if (ret) rtw89_debug(rtwdev, RTW89_DBG_TXRX, "roc send null-1 failed: %d\n", ret); @@ -3513,7 +3514,8 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) roc->state = RTW89_ROC_IDLE; rtw89_config_roc_chandef(rtwdev, rtwvif_link, NULL); rtw89_chanctx_proceed(rtwdev, NULL); - ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false); + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false, + RTW89_ROC_TX_TIMEOUT); if (ret) rtw89_debug(rtwdev, RTW89_DBG_TXRX, "roc send null-0 failed: %d\n", ret); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 8c2a71ecfc0d..84c0d5814747 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5685,6 +5685,7 @@ struct rtw89_mcc_role { /* byte-array in LE order for FW */ u8 macid_bitmap[BITS_TO_BYTES(RTW89_MAX_MAC_ID_NUM)]; + u8 probe_count; u16 duration; /* TU */ u16 beacon_interval; /* TU */ @@ -7342,6 +7343,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev); void rtw89_core_stop(struct rtw89_dev *rtwdev); void rtw89_core_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); +int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + bool qos, bool ps, int timeout); void rtw89_roc_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); From 182c7ff8b87e4edbb2227ede39ae0952da7a0f4a Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:27 +0800 Subject: [PATCH 28/63] wifi: rtw89: mcc: stop TX during MCC prepare Stop TX during the MCC configuration period to prevent packet leakage. The stop time is defined as 'start_tsf - tsf', which means the duration from when MCC configuration begins until MCC starts. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 35 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/chan.h | 2 ++ drivers/net/wireless/realtek/rtw89/core.c | 2 ++ drivers/net/wireless/realtek/rtw89/core.h | 2 ++ 4 files changed, 41 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 2575aa174b05..7539bba2e094 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1602,6 +1602,35 @@ static bool rtw89_mcc_duration_decision_on_bt(struct rtw89_dev *rtwdev) return false; } +void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + mcc_prepare_done_work.work); + + lockdep_assert_wiphy(wiphy); + + ieee80211_wake_queues(rtwdev->hw); +} + +static void rtw89_mcc_prepare(struct rtw89_dev *rtwdev, bool start) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_config *config = &mcc->config; + + if (start) { + ieee80211_stop_queues(rtwdev->hw); + + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwdev->mcc_prepare_done_work, + usecs_to_jiffies(config->prepare_delay)); + } else { + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwdev->mcc_prepare_done_work, 0); + wiphy_delayed_work_flush(rtwdev->hw->wiphy, + &rtwdev->mcc_prepare_done_work); + } +} + static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -1637,6 +1666,8 @@ static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev) config->start_tsf = start_tsf; config->start_tsf_in_aux_domain = tsf_aux + start_tsf - tsf; + config->prepare_delay = start_tsf - tsf; + return 0; } @@ -2247,6 +2278,8 @@ 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_mcc_prepare(rtwdev, true); return 0; } @@ -2335,6 +2368,8 @@ 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_mcc_prepare(rtwdev, false); } static int rtw89_mcc_update(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 6036f3ca6f67..5f10f3955e5c 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -133,6 +133,8 @@ 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) +void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work); + int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx); void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index e7e2315d1867..130e89743991 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4884,6 +4884,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_bt_devinfo_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_rfk_chk_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->cfo_track_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->mcc_prepare_done_work); cancel_delayed_work_sync(&rtwdev->forbid_ba_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->antdiv_work); @@ -5110,6 +5111,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) wiphy_delayed_work_init(&rtwdev->coex_bt_devinfo_work, rtw89_coex_bt_devinfo_work); wiphy_delayed_work_init(&rtwdev->coex_rfk_chk_work, rtw89_coex_rfk_chk_work); wiphy_delayed_work_init(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work); + wiphy_delayed_work_init(&rtwdev->mcc_prepare_done_work, rtw89_mcc_prepare_done_work); INIT_DELAYED_WORK(&rtwdev->forbid_ba_work, rtw89_forbid_ba_work); wiphy_delayed_work_init(&rtwdev->antdiv_work, rtw89_phy_antdiv_work); rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 84c0d5814747..ce2f13313826 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5742,6 +5742,7 @@ struct rtw89_mcc_config { struct rtw89_mcc_sync sync; u64 start_tsf; u64 start_tsf_in_aux_domain; + u64 prepare_delay; u16 mcc_interval; /* TU */ u16 beacon_offset; /* TU */ }; @@ -5872,6 +5873,7 @@ struct rtw89_dev { struct wiphy_delayed_work coex_bt_devinfo_work; struct wiphy_delayed_work coex_rfk_chk_work; struct wiphy_delayed_work cfo_track_work; + struct wiphy_delayed_work mcc_prepare_done_work; struct delayed_work forbid_ba_work; struct wiphy_delayed_work antdiv_work; struct rtw89_ppdu_sts_info ppdu_sts; From 47a498b84f0108669622940f7910e941cd6db856 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:28 +0800 Subject: [PATCH 29/63] wifi: rtw89: TX nulldata 0 after scan complete HW scan leak to TX nulldata 0 to AP after scan completed, which allowed AP start to TX packet to us. Therefore, driver TX nulldata 0 after scan completed. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 9 +++++++++ drivers/net/wireless/realtek/rtw89/core.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 130e89743991..9c4360df77f1 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -5205,6 +5205,7 @@ void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, { struct ieee80211_bss_conf *bss_conf; struct rtw89_bb_ctx *bb; + int ret; if (!rtwvif_link) return; @@ -5224,6 +5225,14 @@ void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, rtw89_phy_config_edcca(rtwdev, bb, false); rtw89_tas_scan(rtwdev, false); + if (hw_scan) { + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, false, false, + RTW89_SCAN_NULL_TIMEOUT); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_TXRX, + "scan send null-0 failed: %d\n", ret); + } + rtwdev->scanning = false; rtw89_for_each_active_bb(rtwdev, bb) bb->dig.bypass_dig = true; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index ce2f13313826..c017bdaf0500 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3440,6 +3440,8 @@ struct rtw89_tx_skb_data { u8 hci_priv[]; }; +#define RTW89_SCAN_NULL_TIMEOUT 30 + #define RTW89_ROC_IDLE_TIMEOUT 500 #define RTW89_ROC_TX_TIMEOUT 30 enum rtw89_roc_state { From 62784eae87849282e7e3aa40a044b947bfff2377 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:29 +0800 Subject: [PATCH 30/63] wifi: rtw89: mcc: adjust TX nulldata early time from 3ms to 7ms Adjust TX nulldata early time to let nulldata have more contention time to TX. Otherwise, AP is hard to receive nulldata 1, which causes the throughput test failed due to packet drops. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 5f10f3955e5c..e0e1fb844304 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -31,7 +31,7 @@ #define RTW89_MCC_DFLT_GROUP 0 #define RTW89_MCC_NEXT_GROUP(cur) (((cur) + 1) % 4) -#define RTW89_MCC_DFLT_TX_NULL_EARLY 3 +#define RTW89_MCC_DFLT_TX_NULL_EARLY 7 #define RTW89_MCC_DFLT_COURTESY_SLOT 3 #define RTW89_MCC_REQ_COURTESY_TIME 5 From 8bb1c30769b26843715ba84539b4592721f0add1 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:30 +0800 Subject: [PATCH 31/63] wifi: rtw89: mcc: enlarge scan time of GC when GO in MCC In original scan, the scan time only 45ms. The GO in MCC mode only stay 50ms and switch to STA role 50ms, which might cause GC can't scan GO. Therefore, enlarge scan time to 105ms to ensure GC have time overlapping with GO. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 4 ++++ drivers/net/wireless/realtek/rtw89/fw.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index cde22f692dc2..608159d31e08 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -7264,6 +7264,8 @@ int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev, else if (channel->band == NL80211_BAND_6GHZ) ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G; + else if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) + ch_info->period = RTW89_P2P_CHAN_TIME; else ch_info->period = RTW89_CHANNEL_TIME; @@ -7440,6 +7442,8 @@ int rtw89_hw_scan_prep_chan_list_be(struct rtw89_dev *rtwdev, ch_info->period = req->duration; else if (channel->band == NL80211_BAND_6GHZ) ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G; + else if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) + ch_info->period = RTW89_P2P_CHAN_TIME; else ch_info->period = RTW89_CHANNEL_TIME; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index f9d5bcbc7c7e..d66333321de2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -320,6 +320,7 @@ struct rtw89_fw_macid_pause_sleep_grp { #define RTW89_CHANNEL_TIME_EXTRA_OP 30 #define RTW89_DFS_CHAN_TIME 105 #define RTW89_OFF_CHAN_TIME 100 +#define RTW89_P2P_CHAN_TIME 105 #define RTW89_DWELL_TIME 20 #define RTW89_DWELL_TIME_6G 10 #define RTW89_SCAN_WIDTH 0 From 12af7fcea83729425e50f0598b04b2c1fe7dccb5 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:31 +0800 Subject: [PATCH 32/63] wifi: rtw89: mcc: clear normal flow NoA when MCC start Clear NoA setting before MCC starts. Otherwise, nulldata will be blocked to TX because firmware use the normal flow NoA to calculate timing. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 4 +--- drivers/net/wireless/realtek/rtw89/fw.h | 3 +-- drivers/net/wireless/realtek/rtw89/ps.c | 24 ++++++++++++++++------- drivers/net/wireless/realtek/rtw89/ps.h | 3 +++ 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 7539bba2e094..c83c4036151d 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -960,6 +960,7 @@ static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev) } sel.bind_vif[i] = rtwvif_link; + rtw89_p2p_disable_all_noa(rtwdev, rtwvif_link, NULL); } ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 608159d31e08..2d649186b700 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3033,12 +3033,10 @@ int rtw89_fw_h2c_lps_ml_cmn_info(struct rtw89_dev *rtwdev, #define H2C_P2P_ACT_LEN 20 int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, - struct ieee80211_bss_conf *bss_conf, struct ieee80211_p2p_noa_desc *desc, - u8 act, u8 noa_id) + u8 act, u8 noa_id, u8 ctwindow_oppps) { bool p2p_type_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; - u8 ctwindow_oppps = bss_conf->p2p_noa_attr.oppps_ctwindow; struct sk_buff *skb; u8 *cmd; int ret; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index d66333321de2..116a17f7dfc6 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4849,9 +4849,8 @@ int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev, const struct rtw89_pkt_drop_params *params); int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, - struct ieee80211_bss_conf *bss_conf, struct ieee80211_p2p_noa_desc *desc, - u8 act, u8 noa_id); + u8 act, u8 noa_id, u8 ctwindow_oppps); int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool en); diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index c255c2f9b945..3411d642c84a 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -238,13 +238,23 @@ static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif_link, false); } -static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, - struct rtw89_vif_link *rtwvif_link, - struct ieee80211_bss_conf *bss_conf) +void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { enum rtw89_p2pps_action act; + u8 oppps_ctwindow; u8 noa_id; + rcu_read_lock(); + + if (!bss_conf) + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + + oppps_ctwindow = bss_conf->p2p_noa_attr.oppps_ctwindow; + + rcu_read_unlock(); + if (rtwvif_link->last_noa_nr == 0) return; @@ -254,8 +264,8 @@ static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, else act = RTW89_P2P_ACT_REMOVE; rtw89_tsf32_toggle(rtwdev, rtwvif_link, act); - rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf, - NULL, act, noa_id); + rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, NULL, + act, noa_id, oppps_ctwindow); } } @@ -277,8 +287,8 @@ static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev, else act = RTW89_P2P_ACT_UPDATE; rtw89_tsf32_toggle(rtwdev, rtwvif_link, act); - rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf, - desc, act, noa_id); + rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, desc, act, noa_id, + bss_conf->p2p_noa_attr.oppps_ctwindow); } rtwvif_link->last_noa_nr = noa_id; } diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h index b2c43d44820d..729477153de6 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.h +++ b/drivers/net/wireless/realtek/rtw89/ps.h @@ -25,6 +25,9 @@ u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data); void rtw89_p2p_noa_once_init(struct rtw89_vif_link *rtwvif_link); void rtw89_p2p_noa_once_deinit(struct rtw89_vif_link *rtwvif_link); void rtw89_p2p_noa_once_recalc(struct rtw89_vif_link *rtwvif_link); +void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf); static inline void rtw89_leave_ips_by_hwflags(struct rtw89_dev *rtwdev) { From b3cf6f392dc9c5a836d06854b0282f4dfa918e61 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:32 +0800 Subject: [PATCH 33/63] wifi: rtw89: mcc: use anchor pattern when bcn offset less than min of tob When the beacon offset is less than minimum of auxiliary tob (aux->duration - aux->limit.max_toa), the upper bound of the reference toa might be negative and lower than the lower bound, which causes the auxiliary result to exceed the NoA limit. Therefore, in this case, the anchor pattern is used for calculation. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index c83c4036151d..2a77b1978c38 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1273,6 +1273,8 @@ static int __rtw89_mcc_calc_pattern_anchor(struct rtw89_dev *rtwdev, if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_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) small_bcn_ofst = false; else From b470b8951983cf726844c2287947ff2550fd4f67 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:33 +0800 Subject: [PATCH 34/63] wifi: rtw89: mcc: enlarge TX retry count when GC auth The auth retry only continue 40ms, but the GO might switch to STA role 50ms when MCC. Therefore, enlarge the TX retry count from 32 to 60 to let GC TX time overlapping with GO timeslot. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 14 ++++++++++++++ drivers/net/wireless/realtek/rtw89/core.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 9c4360df77f1..4026cda04ef6 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4006,6 +4006,12 @@ int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev, rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_CONN_START); rtw89_chip_rfk_channel(rtwdev, rtwvif_link); + + if (vif->p2p) { + rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta_link, + &rtwsta_link->tx_retry); + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, 60); + } } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta_link->mac_id, false); if (ret) { @@ -4190,6 +4196,10 @@ int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, } rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); + + if (vif->p2p) + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, + rtwsta_link->tx_retry); } rtw89_assoc_link_set(rtwsta_link); @@ -4208,6 +4218,10 @@ int rtw89_core_sta_link_remove(struct rtw89_dev *rtwdev, rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, false); rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_DIS_CONN); + + if (vif->p2p) + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, + rtwsta_link->tx_retry); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link, RTW89_ROLE_REMOVE); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c017bdaf0500..342f6b379f86 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3385,6 +3385,7 @@ struct rtw89_sta_link { unsigned int link_id; u8 mac_id; + u8 tx_retry; bool er_cap; struct rtw89_vif_link *rtwvif_link; struct rtw89_ra_info ra; From 3db8563bac6c34018cbb96b14549a95c368b0304 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 10 Jun 2025 21:00:34 +0800 Subject: [PATCH 35/63] wifi: rtw89: scan abort when assign/unassign_vif If scan happen during start_ap, the register which control TX might be turned off during scan. Additionally, if set_channel occurs during scan will backup this register and set to firmware after set_channel done. When scan complete, firmware will also set TX by this register, causing TX to be disabled and beacon can't be TX. Therefore, in assign/unassign_vif call scan abort before set_channel to avoid scan racing with set_channel. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250610130034.14692-13-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 2a77b1978c38..2d4d730c8195 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -2910,6 +2910,9 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_assigned = true; cfg->ref_count++; + if (rtwdev->scanning) + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); + if (list_empty(&rtwvif->mgnt_entry)) list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list); @@ -2949,6 +2952,9 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_assigned = false; cfg->ref_count--; + if (rtwdev->scanning) + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); + if (!rtw89_vif_is_active_role(rtwvif)) list_del_init(&rtwvif->mgnt_entry); From cbaf1110af41994776909dee9e4490edfb80014e Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 11 Jun 2025 11:55:14 +0800 Subject: [PATCH 36/63] wifi: rtw89: introduce rtw89_query_mr_chanctx_info() for multi-role chanctx info Add Wi-Fi 7 MLO related multi-role (MR) chanctx descriptors and query function. They are designed for other components, e.g. coex, which are interested in the following info. * whether a MLD exists and how many active link * the number of AP mode and station mode respectively * how many chanctx and the number of 2/5/6 GHz respectively Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 195 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/chan.h | 45 +++++ 2 files changed, 240 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 2d4d730c8195..6f10235647a1 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -2714,6 +2714,201 @@ void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev) rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_CHANGE_DFLT); } +static enum rtw89_mr_wtype __rtw89_query_mr_wtype(struct rtw89_dev *rtwdev) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + enum rtw89_chanctx_idx chanctx_idx; + struct ieee80211_vif *vif; + struct rtw89_vif *rtwvif; + unsigned int num_mld = 0; + unsigned int num_ml = 0; + unsigned int cnt = 0; + u8 role_idx; + u8 idx; + + for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { + rtwvif = mgnt->active_roles[role_idx]; + if (!rtwvif) + continue; + + cnt++; + + vif = rtwvif_to_vif(rtwvif); + if (!ieee80211_vif_is_mld(vif)) + continue; + + num_mld++; + + for (idx = 0; idx < __RTW89_MLD_MAX_LINK_NUM; idx++) { + chanctx_idx = mgnt->chanctx_tbl[role_idx][idx]; + if (chanctx_idx != RTW89_CHANCTX_IDLE) + num_ml++; + } + } + + if (num_mld > 1) + goto err; + + switch (cnt) { + case 0: + return RTW89_MR_WTYPE_NONE; + case 1: + if (!num_mld) + return RTW89_MR_WTYPE_NONMLD; + switch (num_ml) { + case 1: + return RTW89_MR_WTYPE_MLD1L1R; + case 2: + return RTW89_MR_WTYPE_MLD2L1R; + default: + break; + } + break; + case 2: + if (!num_mld) + return RTW89_MR_WTYPE_NONMLD_NONMLD; + switch (num_ml) { + case 1: + return RTW89_MR_WTYPE_MLD1L1R_NONMLD; + case 2: + return RTW89_MR_WTYPE_MLD2L1R_NONMLD; + default: + break; + } + break; + default: + break; + } + +err: + rtw89_warn(rtwdev, "%s: unhandled cnt %u mld %u ml %u\n", __func__, + cnt, num_mld, num_ml); + return RTW89_MR_WTYPE_UNKNOWN; +} + +static enum rtw89_mr_wmode __rtw89_query_mr_wmode(struct rtw89_dev *rtwdev, + u8 inst_idx) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + unsigned int num[NUM_NL80211_IFTYPES] = {}; + enum rtw89_chanctx_idx chanctx_idx; + struct ieee80211_vif *vif; + struct rtw89_vif *rtwvif; + unsigned int cnt = 0; + u8 role_idx; + + if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM)) + return RTW89_MR_WMODE_UNKNOWN; + + for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { + chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx]; + if (chanctx_idx == RTW89_CHANCTX_IDLE) + continue; + + rtwvif = mgnt->active_roles[role_idx]; + if (unlikely(!rtwvif)) + continue; + + vif = rtwvif_to_vif(rtwvif); + num[vif->type]++; + cnt++; + } + + switch (cnt) { + case 0: + return RTW89_MR_WMODE_NONE; + case 1: + if (num[NL80211_IFTYPE_STATION]) + return RTW89_MR_WMODE_1CLIENT; + if (num[NL80211_IFTYPE_AP]) + return RTW89_MR_WMODE_1AP; + break; + case 2: + if (num[NL80211_IFTYPE_STATION] == 2) + return RTW89_MR_WMODE_2CLIENTS; + if (num[NL80211_IFTYPE_AP] == 2) + return RTW89_MR_WMODE_2APS; + if (num[NL80211_IFTYPE_STATION] && num[NL80211_IFTYPE_AP]) + return RTW89_MR_WMODE_1AP_1CLIENT; + break; + default: + break; + } + + rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt); + return RTW89_MR_WMODE_UNKNOWN; +} + +static enum rtw89_mr_ctxtype __rtw89_query_mr_ctxtype(struct rtw89_dev *rtwdev, + u8 inst_idx) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + DECLARE_BITMAP(map, NUM_OF_RTW89_CHANCTX) = {}; + unsigned int num[RTW89_BAND_NUM] = {}; + enum rtw89_chanctx_idx chanctx_idx; + const struct rtw89_chan *chan; + unsigned int cnt = 0; + u8 role_idx; + + if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM)) + return RTW89_MR_CTX_UNKNOWN; + + for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { + chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx]; + if (chanctx_idx == RTW89_CHANCTX_IDLE) + continue; + + if (__test_and_set_bit(chanctx_idx, map)) + continue; + + chan = rtw89_chan_get(rtwdev, chanctx_idx); + num[chan->band_type]++; + cnt++; + } + + switch (cnt) { + case 0: + return RTW89_MR_CTX_NONE; + case 1: + if (num[RTW89_BAND_2G]) + return RTW89_MR_CTX1_2GHZ; + if (num[RTW89_BAND_5G]) + return RTW89_MR_CTX1_5GHZ; + if (num[RTW89_BAND_6G]) + return RTW89_MR_CTX1_6GHZ; + break; + case 2: + if (num[RTW89_BAND_2G] == 2) + return RTW89_MR_CTX2_2GHZ; + if (num[RTW89_BAND_5G] == 2) + return RTW89_MR_CTX2_5GHZ; + if (num[RTW89_BAND_6G] == 2) + return RTW89_MR_CTX2_6GHZ; + if (num[RTW89_BAND_2G] && num[RTW89_BAND_5G]) + return RTW89_MR_CTX2_2GHZ_5GHZ; + if (num[RTW89_BAND_2G] && num[RTW89_BAND_6G]) + return RTW89_MR_CTX2_2GHZ_6GHZ; + if (num[RTW89_BAND_5G] && num[RTW89_BAND_6G]) + return RTW89_MR_CTX2_5GHZ_6GHZ; + break; + default: + break; + } + + rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt); + return RTW89_MR_CTX_UNKNOWN; +} + +void rtw89_query_mr_chanctx_info(struct rtw89_dev *rtwdev, u8 inst_idx, + struct rtw89_mr_chanctx_info *info) +{ + lockdep_assert_wiphy(rtwdev->hw->wiphy); + + info->wtype = __rtw89_query_mr_wtype(rtwdev); + info->wmode = __rtw89_query_mr_wmode(rtwdev, inst_idx); + info->ctxtype = __rtw89_query_mr_ctxtype(rtwdev, inst_idx); +} + void rtw89_chanctx_track(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index e0e1fb844304..57355cb3d765 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -44,6 +44,49 @@ #define NUM_OF_RTW89_MCC_ROLES 2 +enum rtw89_mr_wtype { + RTW89_MR_WTYPE_NONE, + RTW89_MR_WTYPE_NONMLD, + RTW89_MR_WTYPE_MLD1L1R, + RTW89_MR_WTYPE_MLD2L1R, + RTW89_MR_WTYPE_MLD2L2R, + RTW89_MR_WTYPE_NONMLD_NONMLD, + RTW89_MR_WTYPE_MLD1L1R_NONMLD, + RTW89_MR_WTYPE_MLD2L1R_NONMLD, + RTW89_MR_WTYPE_MLD2L2R_NONMLD, + RTW89_MR_WTYPE_UNKNOWN, +}; + +enum rtw89_mr_wmode { + RTW89_MR_WMODE_NONE, + RTW89_MR_WMODE_1CLIENT, + RTW89_MR_WMODE_1AP, + RTW89_MR_WMODE_1AP_1CLIENT, + RTW89_MR_WMODE_2CLIENTS, + RTW89_MR_WMODE_2APS, + RTW89_MR_WMODE_UNKNOWN, +}; + +enum rtw89_mr_ctxtype { + RTW89_MR_CTX_NONE, + RTW89_MR_CTX1_2GHZ, + RTW89_MR_CTX1_5GHZ, + RTW89_MR_CTX1_6GHZ, + RTW89_MR_CTX2_2GHZ, + RTW89_MR_CTX2_5GHZ, + RTW89_MR_CTX2_6GHZ, + RTW89_MR_CTX2_2GHZ_5GHZ, + RTW89_MR_CTX2_2GHZ_6GHZ, + RTW89_MR_CTX2_5GHZ_6GHZ, + RTW89_MR_CTX_UNKNOWN, +}; + +struct rtw89_mr_chanctx_info { + enum rtw89_mr_wtype wtype; + enum rtw89_mr_wmode wmode; + enum rtw89_mr_ctxtype ctxtype; +}; + enum rtw89_chanctx_pause_reasons { RTW89_CHANCTX_PAUSE_REASON_HW_SCAN, RTW89_CHANCTX_PAUSE_REASON_ROC, @@ -120,6 +163,8 @@ void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev); void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev, enum rtw89_chanctx_changes change); +void rtw89_query_mr_chanctx_info(struct rtw89_dev *rtwdev, u8 inst_idx, + struct rtw89_mr_chanctx_info *info); void rtw89_chanctx_track(struct rtw89_dev *rtwdev); void rtw89_chanctx_pause(struct rtw89_dev *rtwdev, const struct rtw89_chanctx_pause_parm *parm); From 1625d70f523bd8d647f22bf7c406f7e925094fab Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 11 Jun 2025 11:55:15 +0800 Subject: [PATCH 37/63] wifi: rtw89: coex: RTL8922A add Wi-Fi firmware support for v0.35.63.0 There were some driver API offloaded to firmware, and to recognize the feature add a version tag for it. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 34 ++++++++++++++--------- drivers/net/wireless/realtek/rtw89/core.h | 2 ++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 5ccf0cbaed2f..2b23febc6f26 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -138,7 +138,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, }, {RTL8852BT, RTW89_FW_VER_CODE(0, 29, 90, 0), .fcxbtcrpt = 7, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, @@ -146,7 +146,15 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, + }, + {RTL8922A, RTW89_FW_VER_CODE(0, 35, 63, 0), + .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, + .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, + .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, + .fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, + .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, + .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0), .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, @@ -154,7 +162,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 1, .drvinfo_type = 1, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, }, {RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, @@ -162,7 +170,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -170,7 +178,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -178,7 +186,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -186,7 +194,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, @@ -194,7 +202,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0), .fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4, @@ -202,7 +210,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, }, {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -210,7 +218,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -218,7 +226,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0), .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, @@ -226,7 +234,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1024, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, }, /* keep it to be the last as default entry */ @@ -236,7 +244,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1024, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, }, }; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 342f6b379f86..87c60ce84aad 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3167,6 +3167,8 @@ struct rtw89_btc_ver { u8 drvinfo_type; u16 info_buf; u8 max_role_num; + u8 fcxosi; + u8 fcxmlo; }; #define RTW89_BTC_POLICY_MAXLEN 512 From ccd57356f311013b77e4e377dd8aded93646f40e Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 11 Jun 2025 11:55:16 +0800 Subject: [PATCH 38/63] wifi: rtw89: coex: Implement Wi-Fi MLO related logic To make the logic can work well with WiFi 7 & before generations, extend & add logic for WiFi 7. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 641 +++++++++++++++------- drivers/net/wireless/realtek/rtw89/coex.h | 7 + drivers/net/wireless/realtek/rtw89/core.h | 30 + 3 files changed, 488 insertions(+), 190 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 2b23febc6f26..a7e785bb2733 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -2,6 +2,7 @@ /* Copyright(c) 2019-2020 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "fw.h" @@ -676,6 +677,27 @@ enum btc_wl_link_mode { BTC_WLINK_MAX }; +#define CASE_BTC_WL_LINK_MODE(e) case BTC_WLINK_## e: return #e + +static const char *id_to_linkmode(u8 id) +{ + switch (id) { + CASE_BTC_WL_LINK_MODE(NOLINK); + CASE_BTC_WL_LINK_MODE(2G_STA); + CASE_BTC_WL_LINK_MODE(2G_AP); + CASE_BTC_WL_LINK_MODE(2G_GO); + CASE_BTC_WL_LINK_MODE(2G_GC); + CASE_BTC_WL_LINK_MODE(2G_SCC); + CASE_BTC_WL_LINK_MODE(2G_MCC); + CASE_BTC_WL_LINK_MODE(25G_MCC); + CASE_BTC_WL_LINK_MODE(25G_DBCC); + CASE_BTC_WL_LINK_MODE(5G); + CASE_BTC_WL_LINK_MODE(OTHER); + default: + return "unknown"; + } +} + enum btc_wl_mrole_type { BTC_WLMROLE_NONE = 0x0, BTC_WLMROLE_STA_GC, @@ -6247,23 +6269,16 @@ static bool _chk_role_ch_group(const struct rtw89_btc_chdef *r1, } static u8 _chk_dbcc(struct rtw89_dev *rtwdev, struct rtw89_btc_chdef *ch, - u8 *phy, u8 *role, u8 *dbcc_2g_phy) + u8 *phy, u8 *role, u8 link_cnt) { struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; struct rtw89_btc_wl_role_info_v7 *rinfo_v7 = &wl->role_info_v7; struct rtw89_btc_wl_role_info_v8 *rinfo_v8 = &wl->role_info_v8; bool is_2g_ch_exist = false, is_multi_role_in_2g_phy = false; - u8 j, k, dbcc_2g_cid, dbcc_2g_cid2, connect_cnt; - - if (rtwdev->btc.ver->fwlrole == 7) - connect_cnt = rinfo_v7->connect_cnt; - else if (rtwdev->btc.ver->fwlrole == 8) - connect_cnt = rinfo_v8->connect_cnt; - else - return BTC_WLINK_NOLINK; + u8 j, k, dbcc_2g_cid, dbcc_2g_cid2, dbcc_2g_phy, pta_req_band; /* find out the 2G-PHY by connect-id ->ch */ - for (j = 0; j < connect_cnt; j++) { + for (j = 0; j < link_cnt; j++) { if (ch[j].center_ch <= 14) { is_2g_ch_exist = true; break; @@ -6272,21 +6287,33 @@ static u8 _chk_dbcc(struct rtw89_dev *rtwdev, struct rtw89_btc_chdef *ch, /* If no any 2G-port exist, it's impossible because 5G-exclude */ if (!is_2g_ch_exist) - return BTC_WLINK_OTHER; + return BTC_WLINK_5G; dbcc_2g_cid = j; - *dbcc_2g_phy = phy[dbcc_2g_cid]; + dbcc_2g_phy = phy[dbcc_2g_cid]; + + if (dbcc_2g_phy == RTW89_PHY_1) + pta_req_band = RTW89_PHY_1; + else + pta_req_band = RTW89_PHY_0; + + if (rtwdev->btc.ver->fwlrole == 7) { + rinfo_v7->dbcc_2g_phy = dbcc_2g_phy; + } else if (rtwdev->btc.ver->fwlrole == 8) { + rinfo_v8->dbcc_2g_phy = dbcc_2g_phy; + rinfo_v8->pta_req_band = pta_req_band; + } /* connect_cnt <= 2 */ - if (connect_cnt < BTC_TDMA_WLROLE_MAX) + if (link_cnt < BTC_TDMA_WLROLE_MAX) return (_get_role_link_mode((role[dbcc_2g_cid]))); /* find the other-port in the 2G-PHY, ex: PHY-0:6G, PHY1: mcc/scc */ - for (k = 0; k < connect_cnt; k++) { + for (k = 0; k < link_cnt; k++) { if (k == dbcc_2g_cid) continue; - if (phy[k] == *dbcc_2g_phy) { + if (phy[k] == dbcc_2g_phy) { is_multi_role_in_2g_phy = true; dbcc_2g_cid2 = k; break; @@ -6488,7 +6515,7 @@ static void _update_wl_info_v7(struct rtw89_dev *rtwdev, u8 rid) } else if (cnt > BTC_TDMA_WLROLE_MAX) { mode = BTC_WLINK_OTHER; } else if (rtwdev->dbcc_en) { - mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, &dbcc_2g_phy); + mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, cnt); /* correct 2G-located PHY band for gnt ctrl */ if (dbcc_2g_phy < RTW89_PHY_NUM) @@ -6533,26 +6560,336 @@ static void _update_wl_info_v7(struct rtw89_dev *rtwdev, u8 rid) _fw_set_drv_info(rtwdev, CXDRVINFO_ROLE); } +static u8 _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type) +{ + struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; + struct rtw89_btc_wl_mlo_info *mlo_info = &wl->mlo_info; + u8 mode = BTC_WLINK_NOLINK; + + switch (type) { + case RTW89_MR_WTYPE_NONE: /* no-link */ + mode = BTC_WLINK_NOLINK; + break; + case RTW89_MR_WTYPE_NONMLD: /* Non_MLO 1-role 2+0/0+2 */ + case RTW89_MR_WTYPE_MLD1L1R: /* MLO only-1 link 2+0/0+2 */ + if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) { + mode = BTC_WLINK_5G; + } else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1AP) { + mode = BTC_WLINK_2G_GO; + } else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1CLIENT) { + if (wl->role_info_v8.p2p_2g) + mode = BTC_WLINK_2G_GC; + else + mode = BTC_WLINK_2G_STA; + } + break; + case RTW89_MR_WTYPE_NONMLD_NONMLD: /* Non_MLO 2-role 2+0/0+2 */ + case RTW89_MR_WTYPE_MLD1L1R_NONMLD: /* MLO only-1 link + P2P 2+0/0+2 */ + if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) { + mode = BTC_WLINK_5G; + } else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ_5GHZ || + mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ_6GHZ) { + mode = BTC_WLINK_25G_MCC; + } else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ) { + mode = BTC_WLINK_2G_MCC; + } else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX1_2GHZ) { + mode = BTC_WLINK_2G_SCC; + } + break; + case RTW89_MR_WTYPE_MLD2L1R: /* MLO_MLSR 2+0/0+2 */ + if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) + mode = BTC_WLINK_5G; + else if (wl->role_info_v8.p2p_2g) + mode = BTC_WLINK_2G_GC; + else + mode = BTC_WLINK_2G_STA; + break; + case RTW89_MR_WTYPE_MLD2L1R_NONMLD: /* MLO_MLSR + P2P 2+0/0+2 */ + case RTW89_MR_WTYPE_MLD2L2R_NONMLD: /* MLO_MLMR + P2P 1+1/2+2 */ + /* driver may doze 1-link to + * 2G+5G -> TDMA slot switch by E2G/E5G + * 5G only -> TDMA slot switch by E5G + */ + mode = BTC_WLINK_25G_MCC; + break; + case RTW89_MR_WTYPE_MLD2L2R: /* MLO_MLMR 1+1/2+2 */ + if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) { + mode = BTC_WLINK_5G; + } else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1AP) { + mode = BTC_WLINK_2G_GO; + } else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1CLIENT) { + if (wl->role_info_v8.p2p_2g) + mode = BTC_WLINK_2G_GC; + else + mode = BTC_WLINK_2G_STA; + } + break; + } + return mode; +} + +static void _update_wl_mlo_info(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; + struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; + struct rtw89_btc_wl_mlo_info *mlo_info = &wl->mlo_info; + struct rtw89_mr_chanctx_info qinfo; + u8 track_band = RTW89_PHY_0; + u8 rf_band = RTW89_BAND_2G; + u8 i, type; + + /* parse MLO info form PHL API for each HW-band */ + for (i = RTW89_MAC_0; i <= RTW89_MAC_1; i++) { + memset(&qinfo, 0, sizeof(qinfo)); + + rtw89_query_mr_chanctx_info(rtwdev, i, &qinfo); + mlo_info->wmode[i] = qinfo.wmode; + mlo_info->ch_type[i] = qinfo.ctxtype; + mlo_info->wtype = qinfo.wtype; + + if (mlo_info->ch_type[i] == RTW89_MR_CTX1_5GHZ || + mlo_info->ch_type[i] == RTW89_MR_CTX2_5GHZ || + mlo_info->ch_type[i] == RTW89_MR_CTX2_5GHZ_6GHZ) + mlo_info->hwb_rf_band[i] = RTW89_BAND_5G; + else if (mlo_info->ch_type[i] == RTW89_MR_CTX1_6GHZ || + mlo_info->ch_type[i] == RTW89_MR_CTX2_6GHZ) + mlo_info->hwb_rf_band[i] = RTW89_BAND_6G; + else /* check if "2G-included" or unknown in each HW-band */ + mlo_info->hwb_rf_band[i] = RTW89_BAND_2G; + } + + mlo_info->link_status = rtwdev->mlo_dbcc_mode; + type = mlo_info->wtype; + + if (mlo_info->wtype == RTW89_MR_WTYPE_MLD1L1R || + mlo_info->wtype == RTW89_MR_WTYPE_MLD2L1R || + mlo_info->wtype == RTW89_MR_WTYPE_MLD2L2R || + mlo_info->wtype == RTW89_MR_WTYPE_MLD1L1R_NONMLD || + mlo_info->wtype == RTW89_MR_WTYPE_MLD2L1R_NONMLD || + mlo_info->wtype == RTW89_MR_WTYPE_MLD2L2R_NONMLD) + mlo_info->mlo_en = 1; + else + mlo_info->mlo_en = 0; + + if (mlo_info->ch_type[RTW89_MAC_0] != RTW89_MR_CTX_NONE && + mlo_info->ch_type[RTW89_MAC_0] != RTW89_MR_CTX_UNKNOWN && + mlo_info->ch_type[RTW89_MAC_1] != RTW89_MR_CTX_NONE && + mlo_info->ch_type[RTW89_MAC_1] != RTW89_MR_CTX_UNKNOWN) + mlo_info->dual_hw_band_en = 1; /* two HW-hand link exist */ + else + mlo_info->dual_hw_band_en = 0; + + if (mlo_info->link_status == MLO_2_PLUS_0_2RF || + mlo_info->link_status == MLO_0_PLUS_2_2RF || + mlo_info->link_status == MLO_2_PLUS_2_2RF) + mlo_info->mlo_adie = 2; + else + mlo_info->mlo_adie = 1; + + switch (mlo_info->link_status) { + default: + case MLO_2_PLUS_0_1RF: /* 2+0 */ + case MLO_2_PLUS_0_2RF: + mlo_info->rf_combination = BTC_MLO_RF_2_PLUS_0; + track_band = RTW89_MAC_0; + rf_band = mlo_info->hwb_rf_band[RTW89_MAC_0]; + mlo_info->path_rf_band[BTC_RF_S0] = rf_band; + mlo_info->path_rf_band[BTC_RF_S1] = rf_band; + + wl_rinfo->pta_req_band = RTW89_MAC_0; + wl_rinfo->dbcc_2g_phy = RTW89_PHY_0; + wl_rinfo->dbcc_en = 0; + break; + case MLO_0_PLUS_2_1RF: /* 0+2 */ + case MLO_0_PLUS_2_2RF: + mlo_info->rf_combination = BTC_MLO_RF_0_PLUS_2; + track_band = RTW89_MAC_1; + rf_band = mlo_info->hwb_rf_band[RTW89_MAC_1]; + mlo_info->path_rf_band[BTC_RF_S0] = rf_band; + mlo_info->path_rf_band[BTC_RF_S1] = rf_band; + + wl_rinfo->pta_req_band = RTW89_MAC_1; + wl_rinfo->dbcc_2g_phy = RTW89_PHY_1; + wl_rinfo->dbcc_en = 0; + break; + case MLO_1_PLUS_1_1RF: /* 1+1 */ + case MLO_1_PLUS_1_2RF: /* 1+1 */ + case MLO_2_PLUS_2_2RF: /* 2+2 */ + case DBCC_LEGACY: /* DBCC 1+1 */ + if (mlo_info->link_status == MLO_2_PLUS_2_2RF) + mlo_info->rf_combination = BTC_MLO_RF_2_PLUS_2; + else + mlo_info->rf_combination = BTC_MLO_RF_1_PLUS_1; + + if (mlo_info->hwb_rf_band[RTW89_MAC_0] == RTW89_BAND_2G) + track_band = RTW89_MAC_0; + else + track_band = RTW89_MAC_1; + + mlo_info->path_rf_band[BTC_RF_S0] = + mlo_info->hwb_rf_band[RTW89_MAC_0]; + mlo_info->path_rf_band[BTC_RF_S1] = + mlo_info->hwb_rf_band[RTW89_MAC_1]; + + /* Check ch count from ch_type @ 2.4G HW-band, and modify type */ + if (mlo_info->ch_type[track_band] == RTW89_MR_CTX1_2GHZ) + type = RTW89_MR_WTYPE_NONMLD; /* only 1-role at 2G */ + else + type = RTW89_MR_WTYPE_NONMLD_NONMLD; + + if (mlo_info->hwb_rf_band[RTW89_MAC_0] == RTW89_BAND_2G) { + wl_rinfo->pta_req_band = RTW89_MAC_0; + wl_rinfo->dbcc_2g_phy = RTW89_PHY_0; + } else { + wl_rinfo->pta_req_band = RTW89_MAC_1; + wl_rinfo->dbcc_2g_phy = RTW89_PHY_1; + } + + if (mlo_info->wmode[RTW89_MAC_0] == RTW89_MR_WMODE_NONE && + mlo_info->wmode[RTW89_MAC_1] == RTW89_MR_WMODE_NONE) + wl_rinfo->dbcc_en = 0; + else + wl_rinfo->dbcc_en = 1; + break; + } + + wl_rinfo->link_mode = _update_wl_link_mode(rtwdev, track_band, type); + + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(), mode=%s, pta_band=%d", + __func__, id_to_linkmode(wl_rinfo->link_mode), + wl_rinfo->pta_req_band); +} + +static void _update_wl_non_mlo_info(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; + struct rtw89_btc_wl_rlink *rlink = NULL; + struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; + struct rtw89_btc_chdef cid_ch[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; + u8 cid_role[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; + u8 cid_phy[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; + bool b2g = false, b5g = false, outloop = false; + u8 mode = BTC_WLINK_NOLINK; + u8 cnt_2g = 0, cnt_5g = 0; + u8 i, j, cnt = 0; + + for (j = RTW89_PHY_0; j < RTW89_PHY_NUM; j++) { + for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) { + rlink = &wl_rinfo->rlink[i][j]; + + if (!rlink->active || !rlink->connected) + continue; + + if (cnt >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER) { + outloop = true; + break; + } + + cid_ch[cnt] = wl->rlink_info[i][j].chdef; + cid_phy[cnt] = rlink->phy; + cid_role[cnt] = rlink->role; + cnt++; + + if (rlink->rf_band != RTW89_BAND_2G) { + cnt_5g++; + b5g = true; + } else { + cnt_2g++; + b2g = true; + } + } + if (outloop) + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): cnt_2g=%d, cnt_5g=%d\n", __func__, cnt_2g, cnt_5g); + + wl_rinfo->dbcc_en = rtwdev->dbcc_en; + /* Be careful to change the following sequence!! */ + if (cnt == 0) { + mode = BTC_WLINK_NOLINK; + } else if (!b2g && b5g) { + mode = BTC_WLINK_5G; + } else if (wl_rinfo->dbcc_en) { + mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, cnt); + } else if (b2g && b5g) { + mode = BTC_WLINK_25G_MCC; + } else if (!b5g && cnt >= 2) { + if (_chk_role_ch_group(&cid_ch[0], &cid_ch[1])) + mode = BTC_WLINK_2G_SCC; + else + mode = BTC_WLINK_2G_MCC; + } else if (!b5g) { /* cnt_connect = 1 */ + mode = _get_role_link_mode(cid_role[0]); + } + + wl_rinfo->link_mode = mode; +} + +static void _modify_role_link_mode(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; + struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; + u8 go_cleint_exist = wl->go_client_exist; + u8 link_mode = wl_rinfo->link_mode; + u32 role_map = wl_rinfo->role_map; + u8 noa_exist = wl->noa_exist; + u32 mrole = BTC_WLMROLE_NONE; + + /* if no client_joined, don't care P2P-GO/AP role */ + if (((role_map & BIT(RTW89_WIFI_ROLE_P2P_GO)) || + (role_map & BIT(RTW89_WIFI_ROLE_AP))) && !go_cleint_exist) { + if (link_mode == BTC_WLINK_2G_SCC) { + wl_rinfo->link_mode = BTC_WLINK_2G_STA; + } else if (link_mode == BTC_WLINK_2G_GO || + link_mode == BTC_WLINK_2G_AP) { + wl_rinfo->link_mode = BTC_WLINK_NOLINK; + } + } + + /* Identify 2-Role type */ + if (link_mode == BTC_WLINK_2G_SCC || + link_mode == BTC_WLINK_2G_MCC || + link_mode == BTC_WLINK_25G_MCC || + link_mode == BTC_WLINK_5G) { + if ((role_map & BIT(RTW89_WIFI_ROLE_P2P_GO)) || + (role_map & BIT(RTW89_WIFI_ROLE_AP))) { + if (noa_exist) + mrole = BTC_WLMROLE_STA_GO_NOA; + else + mrole = BTC_WLMROLE_STA_GO; + } else if (role_map & BIT(RTW89_WIFI_ROLE_P2P_CLIENT)) { + if (noa_exist) + mrole = BTC_WLMROLE_STA_GC_NOA; + else + mrole = BTC_WLMROLE_STA_GC; + } else { + mrole = BTC_WLMROLE_STA_STA; + } + } + + wl_rinfo->mrole_type = mrole; + + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): link_mode=%s, mrole_type=%d\n", __func__, + id_to_linkmode(wl_rinfo->link_mode), wl_rinfo->mrole_type); +} + static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id, enum btc_role_state state) { + struct rtw89_btc_wl_rlink *rlink = NULL; + struct rtw89_btc_wl_link_info *wl_linfo; struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_wl_info *wl = &btc->cx.wl; - struct rtw89_btc_chdef cid_ch[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER]; struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; - struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info; - bool client_joined = false, b2g = false, b5g = false; - u8 cid_role[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; - u8 cid_phy[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; - u8 dbcc_en = 0, pta_req_band = RTW89_MAC_0; - u8 i, j, cnt = 0, cnt_2g = 0, cnt_5g = 0; - struct rtw89_btc_wl_link_info *wl_linfo; - struct rtw89_btc_wl_rlink *rlink = NULL; - u8 dbcc_2g_phy = RTW89_PHY_0; - u8 mode = BTC_WLINK_NOLINK; - u32 noa_dur = 0; + bool client_joined = false, noa_exist = false, p2p_exist = false; + bool is_5g_hi_channel = false, bg_mode = false, dbcc_en_ori; + u8 i, j, link_mode_ori; + u32 role_map = 0; - if (role_id >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER || rlink_id > RTW89_MAC_1) + if (role_id >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER || rlink_id >= RTW89_MAC_NUM) return; /* Extract wl->link_info[role_id][rlink_id] to wl->role_info @@ -6562,10 +6899,8 @@ static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id */ wl_linfo = &wl->rlink_info[role_id][rlink_id]; - if (wl_linfo->connected == MLME_LINKING) - return; - rlink = &wl_rinfo->rlink[role_id][rlink_id]; + rlink->role = wl_linfo->role; rlink->active = wl_linfo->active; /* Doze or not */ rlink->pid = wl_linfo->pid; @@ -6581,8 +6916,6 @@ static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id switch (wl_linfo->connected) { case MLME_NO_LINK: rlink->connected = 0; - if (rlink->role == RTW89_WIFI_ROLE_STATION) - btc->dm.leak_ap = 0; break; case MLME_LINKED: rlink->connected = 1; @@ -6591,130 +6924,72 @@ static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id return; } - wl->is_5g_hi_channel = false; - wl->bg_mode = false; - wl_rinfo->role_map = 0; - wl_rinfo->p2p_2g = 0; - memset(cid_ch, 0, sizeof(cid_ch)); - - for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) { - for (j = RTW89_MAC_0; j <= RTW89_MAC_1; j++) { + for (j = RTW89_MAC_0; j <= RTW89_MAC_1; j++) { + for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) { rlink = &wl_rinfo->rlink[i][j]; if (!rlink->active || !rlink->connected) continue; - cnt++; - wl_rinfo->role_map |= BIT(rlink->role); + role_map |= BIT(rlink->role); + + /* only one noa-role exist */ + if (rlink->noa && rlink->noa_dur > 0) + noa_exist = true; + + /* for WL 5G-Rx interfered with BT issue */ + if (rlink->rf_band == RTW89_BAND_5G) { + if (rlink->ch >= 100) + is_5g_hi_channel = true; + + continue; + } /* only if client connect for p2p-Go/AP */ if ((rlink->role == RTW89_WIFI_ROLE_P2P_GO || rlink->role == RTW89_WIFI_ROLE_AP) && - rlink->client_cnt > 1) + rlink->client_cnt > 1) { + p2p_exist = true; client_joined = true; + } - /* Identufy if P2P-Go (GO/GC/AP) exist at 2G band*/ - if (rlink->rf_band == RTW89_BAND_2G && - (client_joined || rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT)) - wl_rinfo->p2p_2g = 1; - - /* only one noa-role exist */ - if (rlink->noa && rlink->noa_dur > 0) - noa_dur = rlink->noa_dur; - - /* for WL 5G-Rx interfered with BT issue */ - if (rlink->rf_band == RTW89_BAND_5G && rlink->ch >= 100) - wl->is_5g_hi_channel = 1; + /* Identify if P2P-Go (GO/GC/AP) exist at 2G band */ + if (rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT) + p2p_exist = true; if ((rlink->mode & BIT(BTC_WL_MODE_11B)) || (rlink->mode & BIT(BTC_WL_MODE_11G))) - wl->bg_mode = 1; - - if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT) - continue; - - cid_ch[cnt - 1] = wl_linfo->chdef; - cid_phy[cnt - 1] = rlink->phy; - cid_role[cnt - 1] = rlink->role; - - if (rlink->rf_band != RTW89_BAND_2G) { - cnt_5g++; - b5g = true; - } else { - cnt_2g++; - b2g = true; - } + bg_mode = true; } } + link_mode_ori = wl_rinfo->link_mode; + wl->is_5g_hi_channel = is_5g_hi_channel; + wl->bg_mode = bg_mode; + wl->go_client_exist = client_joined; + wl->noa_exist = noa_exist; + wl_rinfo->p2p_2g = p2p_exist; + wl_rinfo->role_map = role_map; + + dbcc_en_ori = wl_rinfo->dbcc_en; + if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC] rlink cnt_2g=%d cnt_5g=%d\n", cnt_2g, cnt_5g); - rtw89_warn(rtwdev, "not support MLO feature yet"); + /* for MLO-supported, link-mode from driver directly */ + _update_wl_mlo_info(rtwdev); } else { - dbcc_en = rtwdev->dbcc_en; - - /* Be careful to change the following sequence!! */ - if (cnt == 0) { - mode = BTC_WLINK_NOLINK; - } else if (!b2g && b5g) { - mode = BTC_WLINK_5G; - } else if (wl_rinfo->role_map & BIT(RTW89_WIFI_ROLE_NAN)) { - mode = BTC_WLINK_2G_NAN; - } else if (cnt > BTC_TDMA_WLROLE_MAX) { - mode = BTC_WLINK_OTHER; - } else if (dbcc_en) { - mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, - &dbcc_2g_phy); - } else if (b2g && b5g && cnt == 2) { - mode = BTC_WLINK_25G_MCC; - } else if (!b5g && cnt == 2) { /* cnt_connect = 2 */ - if (_chk_role_ch_group(&cid_ch[0], &cid_ch[cnt - 1])) - mode = BTC_WLINK_2G_SCC; - else - mode = BTC_WLINK_2G_MCC; - } else if (!b5g && cnt == 1) { /* cnt_connect = 1 */ - mode = _get_role_link_mode(cid_role[0]); - } + /* for non-MLO-supported, link-mode by BTC */ + _update_wl_non_mlo_info(rtwdev); } - wl_rinfo->link_mode = mode; - wl_rinfo->connect_cnt = cnt; - if (wl_rinfo->connect_cnt == 0) - wl_rinfo->role_map = BIT(RTW89_WIFI_ROLE_NONE); - _update_role_link_mode(rtwdev, client_joined, noa_dur); + _modify_role_link_mode(rtwdev); - wl_rinfo->dbcc_2g_phy = dbcc_2g_phy; - if (wl_rinfo->dbcc_en != dbcc_en) { - wl_rinfo->dbcc_en = dbcc_en; - wl_rinfo->dbcc_chg = 1; + if (link_mode_ori != wl_rinfo->link_mode) + wl->link_mode_chg = true; + + if (wl_rinfo->dbcc_en != dbcc_en_ori) { + wl->dbcc_chg = true; btc->cx.cnt_wl[BTC_WCNT_DBCC_CHG]++; - } else { - wl_rinfo->dbcc_chg = 0; } - - if (wl_rinfo->dbcc_en) { - memset(wl_dinfo, 0, sizeof(struct rtw89_btc_wl_dbcc_info)); - - if (mode == BTC_WLINK_5G) { - pta_req_band = RTW89_PHY_0; - wl_dinfo->op_band[RTW89_PHY_0] = RTW89_BAND_5G; - wl_dinfo->op_band[RTW89_PHY_1] = RTW89_BAND_2G; - } else if (wl_rinfo->dbcc_2g_phy == RTW89_PHY_1) { - pta_req_band = RTW89_PHY_1; - wl_dinfo->op_band[RTW89_PHY_0] = RTW89_BAND_5G; - wl_dinfo->op_band[RTW89_PHY_1] = RTW89_BAND_2G; - } else { - pta_req_band = RTW89_PHY_0; - wl_dinfo->op_band[RTW89_PHY_0] = RTW89_BAND_2G; - wl_dinfo->op_band[RTW89_PHY_1] = RTW89_BAND_5G; - } - _update_dbcc_band(rtwdev, RTW89_PHY_0); - _update_dbcc_band(rtwdev, RTW89_PHY_1); - } - - wl_rinfo->pta_req_band = pta_req_band; - _fw_set_drv_info(rtwdev, CXDRVINFO_ROLE); } void rtw89_coex_act1_work(struct wiphy *wiphy, struct wiphy_work *work) @@ -7626,7 +7901,6 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, wlinfo = &wl->link_info[r.pid]; - rlink_id = 0; /* to do */ if (ver->fwlrole == 0) { *wlinfo = r; _update_wl_info(rtwdev); @@ -7640,6 +7914,7 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, *wlinfo = r; _update_wl_info_v7(rtwdev, r.pid); } else if (ver->fwlrole == 8) { + rlink_id = rtwvif_link->mac_idx; wlinfo = &wl->rlink_info[r.pid][rlink_id]; *wlinfo = r; link_mode_ori = wl->role_info_v8.link_mode; @@ -8256,65 +8531,51 @@ static int _show_wl_role_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_wl_link_info *plink = NULL; - struct rtw89_btc_wl_info *wl = &btc->cx.wl; - struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info; struct rtw89_traffic_stats *t; char *p = buf, *end = buf + bufsz; - u8 i; + u8 i, j; - if (rtwdev->dbcc_en) { - p += scnprintf(p, end - p, - " %-15s : PHY0_band(op:%d/scan:%d/real:%d), ", - "[dbcc_info]", wl_dinfo->op_band[RTW89_PHY_0], - wl_dinfo->scan_band[RTW89_PHY_0], - wl_dinfo->real_band[RTW89_PHY_0]); - p += scnprintf(p, end - p, - "PHY1_band(op:%d/scan:%d/real:%d)\n", - wl_dinfo->op_band[RTW89_PHY_1], - wl_dinfo->scan_band[RTW89_PHY_1], - wl_dinfo->real_band[RTW89_PHY_1]); + for (i = 0; i < btc->ver->max_role_num; i++) { + for (j = 0; j < RTW89_MAC_NUM; j++) { + if (btc->ver->fwlrole == 8) + plink = &btc->cx.wl.rlink_info[i][j]; + else + plink = &btc->cx.wl.link_info[i]; + + if (!plink->active) + continue; + + p += scnprintf(p, end - p, + " [port_%d] : role=%d(phy-%d), connect=%d(client_cnt=%d), mode=%d, center_ch=%d, bw=%d", + plink->pid, plink->role, plink->phy, + plink->connected, plink->client_cnt - 1, + plink->mode, plink->ch, plink->bw); + + if (plink->connected == MLME_NO_LINK) + continue; + + p += scnprintf(p, end - p, + ", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n", + plink->mac_id, plink->tx_time, plink->tx_retry); + + p += scnprintf(p, end - p, + " [port_%d] : rssi=-%ddBm(%d), busy=%d, dir=%s, ", + plink->pid, 110 - plink->stat.rssi, + plink->stat.rssi, plink->busy, + plink->dir == RTW89_TFC_UL ? "UL" : "DL"); + + t = &plink->stat.traffic; + + p += scnprintf(p, end - p, + "tx[rate:%d/busy_level:%d], ", + t->tx_rate, t->tx_tfc_lv); + + p += scnprintf(p, end - p, + "rx[rate:%d/busy_level:%d/drop:%d]\n", + t->rx_rate, + t->rx_tfc_lv, plink->rx_rate_drop_cnt); + } } - - for (i = 0; i < RTW89_PORT_NUM; i++) { - if (btc->ver->fwlrole == 8) - plink = &btc->cx.wl.rlink_info[i][0]; - else - plink = &btc->cx.wl.link_info[i]; - - if (!plink->active) - continue; - - p += scnprintf(p, end - p, - " [port_%d] : role=%d(phy-%d), connect=%d(client_cnt=%d), mode=%d, center_ch=%d, bw=%d", - plink->pid, (u32)plink->role, plink->phy, - (u32)plink->connected, plink->client_cnt - 1, - (u32)plink->mode, plink->ch, (u32)plink->bw); - - if (plink->connected == MLME_NO_LINK) - continue; - - p += scnprintf(p, end - p, - ", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n", - plink->mac_id, plink->tx_time, plink->tx_retry); - - p += scnprintf(p, end - p, - " [port_%d] : rssi=-%ddBm(%d), busy=%d, dir=%s, ", - plink->pid, 110 - plink->stat.rssi, - plink->stat.rssi, plink->busy, - plink->dir == RTW89_TFC_UL ? "UL" : "DL"); - - t = &plink->stat.traffic; - - p += scnprintf(p, end - p, - "tx[rate:%d/busy_level:%d], ", - (u32)t->tx_rate, t->tx_tfc_lv); - - p += scnprintf(p, end - p, - "rx[rate:%d/busy_level:%d/drop:%d]\n", - (u32)t->rx_rate, - t->rx_tfc_lv, plink->rx_rate_drop_cnt); - } - return p - buf; } diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index e3a1fcd79620..ea2c1e5d70f5 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -224,6 +224,13 @@ enum btc_wl_mode { BTC_WL_MODE_NUM, }; +enum btc_mlo_rf_combin { + BTC_MLO_RF_2_PLUS_0 = 0, + BTC_MLO_RF_0_PLUS_2 = 1, + BTC_MLO_RF_1_PLUS_1 = 2, + BTC_MLO_RF_2_PLUS_2 = 3, +}; + enum btc_wl_gpio_debug { BTC_DBG_GNT_BT = 0, BTC_DBG_GNT_WL = 1, diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 87c60ce84aad..c910362851f1 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1557,6 +1557,25 @@ struct rtw89_btc_wl_dbcc_info { u8 role[RTW89_PHY_NUM]; /* role in each phy */ }; +struct rtw89_btc_wl_mlo_info { + u8 wmode[RTW89_PHY_NUM]; /* enum phl_mr_wmode */ + u8 ch_type[RTW89_PHY_NUM]; /* enum phl_mr_ch_type */ + u8 hwb_rf_band[RTW89_PHY_NUM]; /* enum band_type, RF-band for HW-band */ + u8 path_rf_band[RTW89_PHY_NUM]; /* enum band_type, RF-band for PHY0/1 */ + + u8 wtype; /* enum phl_mr_wtype */ + u8 mrcx_mode; + u8 mrcx_act_hwb_map; + u8 mrcx_bt_slot_rsp; + + u8 rf_combination; /* enum btc_mlo_rf_combin 0:2+0, 1:0+2, 2:1+1,3:2+2 */ + u8 mlo_en; /* MLO enable */ + u8 mlo_adie; /* a-die count */ + u8 dual_hw_band_en; /* both 2 HW-band link exist */ + + u32 link_status; /* enum mlo_dbcc_mode_type */ +}; + struct rtw89_btc_wl_active_role { u8 connected: 1; u8 pid: 3; @@ -1895,6 +1914,7 @@ struct rtw89_btc_wl_info { struct rtw89_btc_wl_role_info_v8 role_info_v8; struct rtw89_btc_wl_scan_info scan_info; struct rtw89_btc_wl_dbcc_info dbcc_info; + struct rtw89_btc_wl_mlo_info mlo_info; struct rtw89_btc_rf_para rf_para; struct rtw89_btc_wl_nhm nhm; union rtw89_btc_wl_state_map status; @@ -1907,12 +1927,16 @@ struct rtw89_btc_wl_info { u8 bt_polut_type[RTW89_PHY_NUM]; /* BT polluted WL-Tx type for phy0/1 */ bool is_5g_hi_channel; + bool go_client_exist; + bool noa_exist; bool pta_reg_mac_chg; bool bg_mode; bool he_mode; bool scbd_change; bool fw_ver_mismatch; bool client_cnt_inc_2g; + bool link_mode_chg; + bool dbcc_chg; u32 scbd; }; @@ -2903,6 +2927,12 @@ struct rtw89_btc_trx_info { u32 rx_err_ratio; }; +enum btc_rf_path { + BTC_RF_S0 = 0, + BTC_RF_S1 = 1, + BTC_RF_NUM, +}; + union rtw89_btc_fbtc_slot_u { struct rtw89_btc_fbtc_slot v1[CXST_MAX]; struct rtw89_btc_fbtc_slot_v7 v7[CXST_MAX]; From 26c62dca8243f6f6be6251336db6a24dba34daab Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 11 Jun 2025 11:55:17 +0800 Subject: [PATCH 39/63] wifi: rtw89: coex: Update Wi-Fi status logic for WiFi 7 Because WiFi 7 generation has dual MAC, logic need to assign & save the information to correct index. Update the related logic. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index a7e785bb2733..8a92bdffacae 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -8159,7 +8159,11 @@ void __rtw89_btc_ntfy_wl_sta_iter(struct rtw89_vif_link *rtwvif_link, rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR; rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi); - link_info = &wl->link_info[port]; + if (btc->ver->fwlrole != 8) + link_info = &wl->link_info[port]; + else + link_info = &wl->rlink_info[port][rtwvif_link->mac_idx]; + link_info->stat.traffic = *stats; link_info_t = &link_info->stat.traffic; @@ -8240,13 +8244,12 @@ void __rtw89_btc_ntfy_wl_sta_iter(struct rtw89_vif_link *rtwvif_link, r1->active_role_v1[port].rx_lvl = stats->rx_tfc_lv; r1->active_role_v1[port].tx_rate = rtwsta_link->ra_report.hw_rate; r1->active_role_v1[port].rx_rate = rtwsta_link->rx_hw_rate; - } else if (ver->fwlrole == 2) { - dm->trx_info.tx_lvl = stats->tx_tfc_lv; - dm->trx_info.rx_lvl = stats->rx_tfc_lv; - dm->trx_info.tx_rate = rtwsta_link->ra_report.hw_rate; - dm->trx_info.rx_rate = rtwsta_link->rx_hw_rate; } + dm->trx_info.tx_lvl = stats->tx_tfc_lv; + dm->trx_info.rx_lvl = stats->rx_tfc_lv; + dm->trx_info.tx_rate = rtwsta_link->ra_report.hw_rate; + dm->trx_info.rx_rate = rtwsta_link->rx_hw_rate; dm->trx_info.tx_tp = link_info_t->tx_throughput; dm->trx_info.rx_tp = link_info_t->rx_throughput; From fac16e4147a20e8488304b2630471eec6555b0d1 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 11 Jun 2025 11:55:18 +0800 Subject: [PATCH 40/63] wifi: rtw89: coex: refine debug log with format version and readable string Fix unexpected line warp. Collect firmware report format version and driver support report format version code to check unexpected C2H report exception. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 150 ++++++++++++++++------ drivers/net/wireless/realtek/rtw89/core.h | 51 ++++---- 2 files changed, 134 insertions(+), 67 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 8a92bdffacae..6ec83b928bc2 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -278,6 +278,39 @@ static u32 chip_id_to_bt_rom_code_id(u32 id) } } +#define CASE_BTC_MLME_STATE(e) case MLME_##e: return #e + +static const char *id_to_mlme_state(u32 id) +{ + switch (id) { + CASE_BTC_MLME_STATE(NO_LINK); + CASE_BTC_MLME_STATE(LINKING); + CASE_BTC_MLME_STATE(LINKED); + default: + return "unknown"; + } +} + +static char *chip_id_str(u32 id) +{ + switch (id) { + case RTL8852A: + return "RTL8852A"; + case RTL8852B: + return "RTL8852B"; + case RTL8852C: + return "RTL8852C"; + case RTL8852BT: + return "RTL8852BT"; + case RTL8851B: + return "RTL8851B"; + case RTL8922A: + return "RTL8922A"; + default: + return "UNKNOWN"; + } +} + struct rtw89_btc_btf_tlv { u8 type; u8 len; @@ -1354,6 +1387,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, u8 *prptbuf, u32 index) { struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_ver *fwsubver = &btc->fwinfo.fw_subver; const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; @@ -1396,23 +1430,29 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxbtcrpt == 1) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v1); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v1.fver; } else if (ver->fcxbtcrpt == 4) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v4; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v4); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v4.fver; } else if (ver->fcxbtcrpt == 5) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v5; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v5); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v5.fver; } else if (ver->fcxbtcrpt == 105) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v105; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v105); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v105.fver; pcinfo->req_fver = 5; break; } else if (ver->fcxbtcrpt == 8) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v8; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v8); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v8.fver; } else if (ver->fcxbtcrpt == 7) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v7); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v7.fver; } else { goto err; } @@ -1423,9 +1463,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxtdma == 1) { pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1); + fwsubver->fcxtdma = 0; } else if (ver->fcxtdma == 3 || ver->fcxtdma == 7) { pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3); + fwsubver->fcxtdma = pfwinfo->rpt_fbtc_tdma.finfo.v3.fver; } else { goto err; } @@ -1436,9 +1478,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxslots == 1) { pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v1); + fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v1.fver; } else if (ver->fcxslots == 7) { pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v7); + fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v7.fver; } else { goto err; } @@ -1451,22 +1495,27 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v2; pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v2); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v2.fver; } else if (ver->fcxcysta == 3) { pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v3; pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v3); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v3.fver; } else if (ver->fcxcysta == 4) { pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v4; pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v4); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v4.fver; } else if (ver->fcxcysta == 5) { pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v5; pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v5); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v5.fver; } else if (ver->fcxcysta == 7) { pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v7; pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v7); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v7.fver; } else { goto err; } @@ -1482,11 +1531,13 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v2.step[0]) * trace_step + offsetof(struct rtw89_btc_fbtc_steps_v2, step); + fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v2.fver; } else if (ver->fcxstep == 3) { pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v3; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v3.step[0]) * trace_step + offsetof(struct rtw89_btc_fbtc_steps_v3, step); + fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v3.fver; } else { goto err; } @@ -1497,12 +1548,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxnullsta == 1) { pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v1); + fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v1.fver; } else if (ver->fcxnullsta == 2) { pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v2); + fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v2.fver; } else if (ver->fcxnullsta == 7) { pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v7); + fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v7.fver; } else { goto err; } @@ -1513,12 +1567,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxmreg == 1) { pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v1); + fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v1.fver; } else if (ver->fcxmreg == 2) { pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v2); + fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v2.fver; } else if (ver->fcxmreg == 7) { pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v7); + fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v7.fver; } else { goto err; } @@ -1529,9 +1586,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxgpiodbg == 7) { pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7); + fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7.fver; } else { pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1); + fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1.fver; } pcinfo->req_fver = ver->fcxgpiodbg; break; @@ -1540,9 +1599,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxbtver == 1) { pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v1); + fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v1.fver; } else if (ver->fcxbtver == 7) { pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v7); + fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v7.fver; } pcinfo->req_fver = ver->fcxbtver; break; @@ -1551,12 +1612,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxbtscan == 1) { pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v1); + fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v1.fver; } else if (ver->fcxbtscan == 2) { pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v2); + fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v2.fver; } else if (ver->fcxbtscan == 7) { pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v7); + fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v7.fver; } else { goto err; } @@ -1567,12 +1631,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxbtafh == 1) { pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v1); + fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v1.fver; } else if (ver->fcxbtafh == 2) { pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v2); + fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v2.fver; } else if (ver->fcxbtafh == 7) { pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v7); + fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v7.fver; } else { goto err; } @@ -1582,6 +1649,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo; pfinfo = &pfwinfo->rpt_fbtc_btdev.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btdev.finfo); + fwsubver->fcxbtdevinfo = pfwinfo->rpt_fbtc_btdev.finfo.fver; pcinfo->req_fver = ver->fcxbtdevinfo; break; default: @@ -8454,11 +8522,9 @@ static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) if (!(dm->coex_info_map & BTC_COEX_INFO_CX)) return 0; - dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO]++; - p += scnprintf(p, end - p, - "========== [BTC COEX INFO (%d)] ==========\n", - chip->chip_id); + "\n========== [BTC COEX INFO (%s)] ==========\n", + chip_id_str(chip->chip_id)); ver_main = FIELD_GET(GENMASK(31, 24), RTW89_COEX_VERSION); ver_sub = FIELD_GET(GENMASK(23, 16), RTW89_COEX_VERSION); @@ -8549,10 +8615,11 @@ static int _show_wl_role_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) continue; p += scnprintf(p, end - p, - " [port_%d] : role=%d(phy-%d), connect=%d(client_cnt=%d), mode=%d, center_ch=%d, bw=%d", + " [port_%d] : role=%d(phy-%d), connect=%s(client_cnt=%d), mode=%d, center_ch=%d, bw=%d", plink->pid, plink->role, plink->phy, - plink->connected, plink->client_cnt - 1, - plink->mode, plink->ch, plink->bw); + id_to_mlme_state(plink->connected), + plink->client_cnt - 1, plink->mode, + plink->ch, plink->bw); if (plink->connected == MLME_NO_LINK) continue; @@ -8614,8 +8681,8 @@ static int _show_wl_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) else goto out; - p += scnprintf(p, end - p, " %-15s : link_mode:%d, ", "[status]", - mode); + p += scnprintf(p, end - p, " %-15s : link_mode:%s, ", "[status]", + id_to_linkmode(mode)); p += scnprintf(p, end - p, "rf_off:%d, power_save:%d, scan:%s(band:%d/phy_map:0x%x), ", @@ -9414,7 +9481,6 @@ static int _show_fbtc_slots(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) if (i % 5 == 4) p += scnprintf(p, end - p, "\n"); } - p += scnprintf(p, end - p, "\n"); return p - buf; } @@ -9986,7 +10052,7 @@ static int _show_fbtc_cysta_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz return 0; pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v7; - p += scnprintf(p, end - p, "\n\r %-15s : cycle:%d", "[slot_stat]", + p += scnprintf(p, end - p, "\n %-15s : cycle:%d", "[slot_stat]", le16_to_cpu(pcysta->cycles)); for (i = 0; i < CXST_MAX; i++) { @@ -10134,7 +10200,7 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) ns = &pfwinfo->rpt_fbtc_nullsta.finfo; if (ver->fcxnullsta == 1) { for (i = 0; i < 2; i++) { - p += scnprintf(p, end - p, " %-15s : ", "[NULL-STA]"); + p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]"); p += scnprintf(p, end - p, "null-%d", i); p += scnprintf(p, end - p, "[ok:%d/", le32_to_cpu(ns->v1.result[i][1])); @@ -10147,13 +10213,13 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "avg_t:%d.%03d/", le32_to_cpu(ns->v1.avg_t[i]) / 1000, le32_to_cpu(ns->v1.avg_t[i]) % 1000); - p += scnprintf(p, end - p, "max_t:%d.%03d]\n", + p += scnprintf(p, end - p, "max_t:%d.%03d]", le32_to_cpu(ns->v1.max_t[i]) / 1000, le32_to_cpu(ns->v1.max_t[i]) % 1000); } } else if (ver->fcxnullsta == 7) { for (i = 0; i < 2; i++) { - p += scnprintf(p, end - p, " %-15s : ", "[NULL-STA]"); + p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]"); p += scnprintf(p, end - p, "null-%d", i); p += scnprintf(p, end - p, "[Tx:%d/", le32_to_cpu(ns->v7.result[i][4])); @@ -10168,13 +10234,13 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "avg_t:%d.%03d/", le32_to_cpu(ns->v7.tavg[i]) / 1000, le32_to_cpu(ns->v7.tavg[i]) % 1000); - p += scnprintf(p, end - p, "max_t:%d.%03d]\n", + p += scnprintf(p, end - p, "max_t:%d.%03d]", le32_to_cpu(ns->v7.tmax[i]) / 1000, le32_to_cpu(ns->v7.tmax[i]) % 1000); } } else { for (i = 0; i < 2; i++) { - p += scnprintf(p, end - p, " %-15s : ", "[NULL-STA]"); + p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]"); p += scnprintf(p, end - p, "null-%d", i); p += scnprintf(p, end - p, "[Tx:%d/", le32_to_cpu(ns->v2.result[i][4])); @@ -10189,7 +10255,7 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "avg_t:%d.%03d/", le32_to_cpu(ns->v2.avg_t[i]) / 1000, le32_to_cpu(ns->v2.avg_t[i]) % 1000); - p += scnprintf(p, end - p, "max_t:%d.%03d]\n", + p += scnprintf(p, end - p, "max_t:%d.%03d]", le32_to_cpu(ns->v2.max_t[i]) / 1000, le32_to_cpu(ns->v2.max_t[i]) % 1000); } @@ -10431,7 +10497,6 @@ static int _show_gpio_dbg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n", __func__); - p += scnprintf(p, end - p, "\n"); goto out; } @@ -10704,7 +10769,6 @@ static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) id_to_regtype(type), offset, val); cnt++; } - p += scnprintf(p, end - p, "\n"); out: return p - buf; @@ -11404,37 +11468,39 @@ static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) ssize_t rtw89_btc_dump_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) { - struct rtw89_fw_suit *fw_suit = &rtwdev->fw.normal; struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_ver *fwsubver = &btc->fwinfo.fw_subver; const struct rtw89_btc_ver *ver = btc->ver; - struct rtw89_btc_cx *cx = &btc->cx; - struct rtw89_btc_bt_info *bt = &cx->bt; + struct rtw89_btc_dm *dm = &btc->dm; char *p = buf, *end = buf + bufsz; - p += scnprintf(p, end - p, - "=========================================\n"); - p += scnprintf(p, end - p, - "WL FW / BT FW %d.%d.%d.%d / NA\n", - fw_suit->major_ver, fw_suit->minor_ver, - fw_suit->sub_ver, fw_suit->sub_idex); - p += scnprintf(p, end - p, "manual %d\n", - btc->manual_ctrl); + dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO]++; p += scnprintf(p, end - p, - "=========================================\n"); - + "\n\n\n** Page:%3d/RunCNT:%3d **", + dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO], + dm->cnt_dm[BTC_DCNT_RUN]); p += scnprintf(p, end - p, - "\n\r %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)", - "[bt_info]", - bt->raw_info[2], bt->raw_info[3], - bt->raw_info[4], bt->raw_info[5], - bt->raw_info[6], bt->raw_info[7], - bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply", - cx->cnt_bt[BTC_BCNT_INFOUPDATE], - cx->cnt_bt[BTC_BCNT_INFOSAME]); - + "\n========== [BTC FEATURE SUB VER] =========="); p += scnprintf(p, end - p, - "\n=========================================\n"); + "\n %-15s : fcxbtcrpt[%d/%d], fcxtdma[%d/%d], fcxslots[%d/%d], fcxcysta[%d/%d]", + "[FW/DRV]", fwsubver->fcxbtcrpt, ver->fcxbtcrpt, + fwsubver->fcxtdma, ver->fcxtdma, fwsubver->fcxslots, + ver->fcxslots, fwsubver->fcxcysta, ver->fcxcysta); + p += scnprintf(p, end - p, + "\n %-15s : fcxstep[%d/%d], fcxnullsta[%d/%d], fcxmreg[%d/%d], fcxgpiodbg[%d/%d]", + "[FW/DRV]", fwsubver->fcxstep, ver->fcxstep, + fwsubver->fcxnullsta, ver->fcxnullsta, fwsubver->fcxmreg, + ver->fcxmreg, fwsubver->fcxgpiodbg, ver->fcxgpiodbg); + p += scnprintf(p, end - p, + "\n %-15s : fcxbtver[%d/%d], fcxbtscan[%d/%d], fcxbtafh[%d/%d], fcxbtdevinfo[%d/%d]", + "[FW/DRV]", fwsubver->fcxbtver, ver->fcxbtver, + fwsubver->fcxbtscan, ver->fcxbtscan, fwsubver->fcxbtafh, + ver->fcxbtafh, fwsubver->fcxbtdevinfo, ver->fcxbtdevinfo); + p += scnprintf(p, end - p, + "\n %-15s : fcxosi[%d/%d], fcxmlo[%d/%d],", + "[FW/DRV]", fwsubver->fcxosi, ver->fcxosi, + fwsubver->fcxmlo, ver->fcxmlo); p += _show_cx_info(rtwdev, p, end - p); p += _show_wl_info(rtwdev, p, end - p); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c910362851f1..6ee0fb44915d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3146,31 +3146,6 @@ enum rtw89_btc_btfre_type { BTFRE_MAX, }; -struct rtw89_btc_btf_fwinfo { - u32 cnt_c2h; - u32 cnt_h2c; - u32 cnt_h2c_fail; - u32 event[BTF_EVNT_MAX]; - - u32 err[BTFRE_MAX]; - u32 len_mismch; - u32 fver_mismch; - u32 rpt_en_map; - - struct rtw89_btc_report_ctrl_state rpt_ctrl; - struct rtw89_btc_rpt_fbtc_tdma rpt_fbtc_tdma; - struct rtw89_btc_rpt_fbtc_slots rpt_fbtc_slots; - struct rtw89_btc_rpt_fbtc_cysta rpt_fbtc_cysta; - struct rtw89_btc_rpt_fbtc_step rpt_fbtc_step; - struct rtw89_btc_rpt_fbtc_nullsta rpt_fbtc_nullsta; - struct rtw89_btc_rpt_fbtc_mreg rpt_fbtc_mregval; - struct rtw89_btc_rpt_fbtc_gpio_dbg rpt_fbtc_gpio_dbg; - struct rtw89_btc_rpt_fbtc_btver rpt_fbtc_btver; - struct rtw89_btc_rpt_fbtc_btscan rpt_fbtc_btscan; - struct rtw89_btc_rpt_fbtc_btafh rpt_fbtc_btafh; - struct rtw89_btc_rpt_fbtc_btdev rpt_fbtc_btdev; -}; - struct rtw89_btc_ver { enum rtw89_core_chip_id chip_id; u32 fw_ver_code; @@ -3201,6 +3176,32 @@ struct rtw89_btc_ver { u8 fcxmlo; }; +struct rtw89_btc_btf_fwinfo { + u32 cnt_c2h; + u32 cnt_h2c; + u32 cnt_h2c_fail; + u32 event[BTF_EVNT_MAX]; + + u32 err[BTFRE_MAX]; + u32 len_mismch; + u32 fver_mismch; + u32 rpt_en_map; + + struct rtw89_btc_ver fw_subver; + struct rtw89_btc_report_ctrl_state rpt_ctrl; + struct rtw89_btc_rpt_fbtc_tdma rpt_fbtc_tdma; + struct rtw89_btc_rpt_fbtc_slots rpt_fbtc_slots; + struct rtw89_btc_rpt_fbtc_cysta rpt_fbtc_cysta; + struct rtw89_btc_rpt_fbtc_step rpt_fbtc_step; + struct rtw89_btc_rpt_fbtc_nullsta rpt_fbtc_nullsta; + struct rtw89_btc_rpt_fbtc_mreg rpt_fbtc_mregval; + struct rtw89_btc_rpt_fbtc_gpio_dbg rpt_fbtc_gpio_dbg; + struct rtw89_btc_rpt_fbtc_btver rpt_fbtc_btver; + struct rtw89_btc_rpt_fbtc_btscan rpt_fbtc_btscan; + struct rtw89_btc_rpt_fbtc_btafh rpt_fbtc_btafh; + struct rtw89_btc_rpt_fbtc_btdev rpt_fbtc_btdev; +}; + #define RTW89_BTC_POLICY_MAXLEN 512 struct rtw89_btc { From 825f5514127ad52a4f5c9abf1d56cf301890bed7 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 11 Jun 2025 11:55:19 +0800 Subject: [PATCH 41/63] wifi: rtw89: coex: Add H2C command to collect driver outsource information to firmware In order to reduce driver I/O & some detail instant hardware control, some of the necessary API offload to Wi-Fi firmware. Collect the reference parameters to let firmware do decisions. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 12 ++++++- drivers/net/wireless/realtek/rtw89/core.h | 16 ++++++++- drivers/net/wireless/realtek/rtw89/fw.c | 40 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 6 ++++ 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 6ec83b928bc2..d2d673fe8e18 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -154,7 +154,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, - .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, + .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 2, .info_buf = 1800, .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0), @@ -2776,6 +2776,16 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type) case CXDRVINFO_FDDT: case CXDRVINFO_MLO: case CXDRVINFO_OSI: + if (!ver->fcxosi) + return; + + if (ver->drvinfo_type == 2) + type = 7; + else + return; + + rtw89_fw_h2c_cxdrv_osi_info(rtwdev, type); + break; default: break; } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 6ee0fb44915d..328d4e9352fe 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1205,7 +1205,7 @@ struct rtw89_mac_ax_gnt { struct rtw89_mac_ax_wl_act { u8 wlan_act_en; u8 wlan_act; -}; +} __packed; #define RTW89_MAC_AX_COEX_GNT_NR 2 struct rtw89_mac_ax_coex_gnt { @@ -2933,12 +2933,26 @@ enum btc_rf_path { BTC_RF_NUM, }; +struct rtw89_btc_fbtc_outsrc_set_info { + u8 rf_band[BTC_RF_NUM]; /* 0:2G, 1:non-2G */ + u8 btg_rx[BTC_RF_NUM]; + u8 nbtg_tx[BTC_RF_NUM]; + + struct rtw89_mac_ax_gnt gnt_set[BTC_RF_NUM]; /* refer to btc_gnt_ctrl */ + struct rtw89_mac_ax_wl_act wlact_set[BTC_RF_NUM]; /* BT0/BT1 */ + + u8 pta_req_hw_band; + u8 rf_gbt_source; +} __packed; + union rtw89_btc_fbtc_slot_u { struct rtw89_btc_fbtc_slot v1[CXST_MAX]; struct rtw89_btc_fbtc_slot_v7 v7[CXST_MAX]; }; struct rtw89_btc_dm { + struct rtw89_btc_fbtc_outsrc_set_info ost_info_last; /* outsrc API setup info */ + struct rtw89_btc_fbtc_outsrc_set_info ost_info; /* outsrc API setup info */ union rtw89_btc_fbtc_slot_u slot; union rtw89_btc_fbtc_slot_u slot_now; struct rtw89_btc_fbtc_tdma tdma; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 2d649186b700..c613431e754f 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5084,6 +5084,46 @@ int rtw89_fw_h2c_cxdrv_role_v8(struct rtw89_dev *rtwdev, u8 type) return ret; } +int rtw89_fw_h2c_cxdrv_osi_info(struct rtw89_dev *rtwdev, u8 type) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_fbtc_outsrc_set_info *osi = &btc->dm.ost_info; + struct rtw89_h2c_cxosi *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 cxdrv_osi\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cxosi *)skb->data; + + h2c->hdr.type = type; + h2c->hdr.ver = btc->ver->fcxosi; + h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7; + h2c->osi = *osi; + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, BTFC_SET, + SET_DRV_INFO, 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; +} + #define H2C_LEN_CXDRVINFO_CTRL (4 + H2C_LEN_CXDRVHDR) int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev, u8 type) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 116a17f7dfc6..24d2e8b0d079 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2251,6 +2251,11 @@ struct rtw89_h2c_cxrole_v8 { struct rtw89_btc_wl_role_info_v8_u32 _u32; } __packed; +struct rtw89_h2c_cxosi { + struct rtw89_h2c_cxhdr_v7 hdr; + struct rtw89_btc_fbtc_outsrc_set_info osi; +} __packed; + struct rtw89_h2c_cxinit { struct rtw89_h2c_cxhdr hdr; u8 ant_type; @@ -4746,6 +4751,7 @@ int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_role_v7(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_role_v8(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_osi_info(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev, u8 type); From 1683ae3e0069678815c9444fc395958bf5dc53cb Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 11 Jun 2025 11:55:20 +0800 Subject: [PATCH 42/63] wifi: rtw89: coex: Update Pre-AGC logic for WiFi 7 Pre-AGC is Wi-Fi auto Rx gain control. The mechanism need to switching very fast, especially while Wi-Fi is under 2GHz/5GHz multi-port scenario. To earn a more accuracy & sensitive gain control, in the WiFi 7 later firmware, Pre-AGC mechanism has offloaded to firmware. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 37 ++++++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index d2d673fe8e18..139173dae62b 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -5056,6 +5056,7 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_fbtc_outsrc_set_info *o_info = &btc->dm.ost_info; struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info_v2 *rinfo_v2 = &wl->role_info_v2; @@ -5087,9 +5088,7 @@ static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) return; } - if (link_mode == BTC_WLINK_25G_MCC) { - is_preagc = BTC_PREAGC_BB_FWCTRL; - } else if (!(bt->run_patch_code && bt->enable.now)) { + if (!(bt->run_patch_code && bt->enable.now)) { is_preagc = BTC_PREAGC_DISABLE; } else if (link_mode == BTC_WLINK_5G) { is_preagc = BTC_PREAGC_DISABLE; @@ -5109,6 +5108,9 @@ static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) is_preagc = BTC_PREAGC_ENABLE; } + if (!btc->ver->fcxosi && link_mode == BTC_WLINK_25G_MCC) + is_preagc = BTC_PREAGC_BB_FWCTRL; + if (dm->wl_pre_agc_rb != dm->wl_pre_agc && dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND) { _get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC, &val); @@ -5122,9 +5124,34 @@ static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) is_preagc != dm->wl_pre_agc) { dm->wl_pre_agc = is_preagc; - if (is_preagc > BTC_PREAGC_ENABLE) + if (!btc->ver->fcxosi && is_preagc > BTC_PREAGC_ENABLE) return; - chip->ops->ctrl_nbtg_bt_tx(rtwdev, dm->wl_pre_agc, RTW89_PHY_0); + + if (o_info->rf_band[BTC_RF_S0] != o_info->rf_band[BTC_RF_S1]) {/* 1+1 */ + if (o_info->rf_band[BTC_RF_S0]) /* Non-2G */ + o_info->nbtg_tx[BTC_RF_S0] = BTC_PREAGC_DISABLE; + else + o_info->nbtg_tx[BTC_RF_S0] = is_preagc; + + if (o_info->rf_band[BTC_RF_S1]) /* Non-2G */ + o_info->nbtg_tx[BTC_RF_S1] = BTC_PREAGC_DISABLE; + else + o_info->nbtg_tx[BTC_RF_S1] = is_preagc; + + } else { /* 2+0 or 0+2 */ + o_info->nbtg_tx[BTC_RF_S0] = is_preagc; + o_info->nbtg_tx[BTC_RF_S1] = is_preagc; + } + + if (btc->ver->fcxosi) + return; + + chip->ops->ctrl_nbtg_bt_tx(rtwdev, o_info->nbtg_tx[BTC_RF_S0], + RTW89_PHY_0); + if (chip->chip_id != RTL8922A) + return; + chip->ops->ctrl_nbtg_bt_tx(rtwdev, o_info->nbtg_tx[BTC_RF_S1], + RTW89_PHY_1); } } From 4cb9092289ec4fc34d0756362876c79784801638 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 11 Jun 2025 11:55:21 +0800 Subject: [PATCH 43/63] wifi: rtw89: coex: Update BTG control for WiFi 7 BTG means a path work for Bluetooth & Wi-Fi 2.4GHz. To earn a better coexistence performance, need to do some RF setting for BTG path. WiFi 7 generation offload the feature to firmware, to get a more accuracy control. And decrease driver I/O. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 92 +++++++++++------------ 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 139173dae62b..04a05958fad4 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -4972,16 +4972,14 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2; struct rtw89_btc_wl_role_info_v7 *wl_rinfo_v7 = &wl->role_info_v7; struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8; + struct rtw89_btc_fbtc_outsrc_set_info *o_info = &btc->dm.ost_info; struct rtw89_btc_wl_role_info *wl_rinfo_v0 = &wl->role_info; - struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_dm *dm = &btc->dm; struct _wl_rinfo_now wl_rinfo; - u32 run_reason = btc->dm.run_reason; - u32 is_btg; - u8 i, val; + u32 is_btg = BTC_BTGCTRL_DISABLE; if (btc->manual_ctrl) return; @@ -4999,58 +4997,56 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) else return; - if (rtwdev->dbcc_en) { - if (ver->fwlrole == 0) { - wl_rinfo.dbcc_2g_phy = RTW89_PHY_NUM; + /* notify halbb ignore GNT_BT or not for WL BB Rx-AGC control */ + if (btc->ant_type == BTC_ANT_SHARED) { + if (!(bt->run_patch_code && bt->enable.now)) + is_btg = BTC_BTGCTRL_DISABLE; + else if (wl_rinfo.link_mode != BTC_WLINK_5G) + is_btg = BTC_BTGCTRL_ENABLE; + else + is_btg = BTC_BTGCTRL_DISABLE; - for (i = 0; i < RTW89_PHY_NUM; i++) { - if (wl_dinfo->real_band[i] == RTW89_BAND_2G) - wl_rinfo.dbcc_2g_phy = i; - } - } else if (ver->fwlrole == 1) { - wl_rinfo.dbcc_2g_phy = wl_rinfo_v1->dbcc_2g_phy; - } else if (ver->fwlrole == 2) { - wl_rinfo.dbcc_2g_phy = wl_rinfo_v2->dbcc_2g_phy; - } else if (ver->fwlrole == 7) { - wl_rinfo.dbcc_2g_phy = wl_rinfo_v7->dbcc_2g_phy; - } else if (ver->fwlrole == 8) { - wl_rinfo.dbcc_2g_phy = wl_rinfo_v8->dbcc_2g_phy; - } else { - return; - } + /* bb call ctrl_btg() in WL FW by slot */ + if (!ver->fcxosi && + wl_rinfo.link_mode == BTC_WLINK_25G_MCC) + is_btg = BTC_BTGCTRL_BB_GNT_FWCTRL; } - if (wl_rinfo.link_mode == BTC_WLINK_25G_MCC) - is_btg = BTC_BTGCTRL_BB_GNT_FWCTRL; - else if (!(bt->run_patch_code && bt->enable.now)) - is_btg = BTC_BTGCTRL_DISABLE; - else if (wl_rinfo.link_mode == BTC_WLINK_5G) - is_btg = BTC_BTGCTRL_DISABLE; - else if (dm->freerun) - is_btg = BTC_BTGCTRL_DISABLE; - else if (rtwdev->dbcc_en && wl_rinfo.dbcc_2g_phy != RTW89_PHY_1) - is_btg = BTC_BTGCTRL_DISABLE; + if (is_btg == dm->wl_btg_rx) + return; else - is_btg = BTC_BTGCTRL_ENABLE; - - if (dm->wl_btg_rx_rb != dm->wl_btg_rx && - dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) { - _get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX, &val); - dm->wl_btg_rx_rb = val; - } - - if (run_reason == BTC_RSN_NTFY_INIT || - run_reason == BTC_RSN_NTFY_SWBAND || - dm->wl_btg_rx_rb != dm->wl_btg_rx || - is_btg != dm->wl_btg_rx) { - dm->wl_btg_rx = is_btg; - if (is_btg > BTC_BTGCTRL_ENABLE) - return; + /* skip setup if btg_ctrl set by wl fw */ + if (!ver->fcxosi && is_btg > BTC_BTGCTRL_ENABLE) + return; - chip->ops->ctrl_btg_bt_rx(rtwdev, is_btg, RTW89_PHY_0); + /* Below flow is for BTC_FEAT_NEW_BBAPI_FLOW = 1 */ + if (o_info->rf_band[BTC_RF_S0] != o_info->rf_band[BTC_RF_S1]) {/* 1+1 */ + if (o_info->rf_band[BTC_RF_S0]) /* Non-2G */ + o_info->btg_rx[BTC_RF_S0] = BTC_BTGCTRL_DISABLE; + else + o_info->btg_rx[BTC_RF_S0] = is_btg; + + if (o_info->rf_band[BTC_RF_S1]) /* Non-2G */ + o_info->btg_rx[BTC_RF_S1] = BTC_BTGCTRL_DISABLE; + else + o_info->btg_rx[BTC_RF_S1] = is_btg; + } else { /* 2+0 or 0+2 */ + o_info->btg_rx[BTC_RF_S0] = is_btg; + o_info->btg_rx[BTC_RF_S1] = is_btg; } + + if (ver->fcxosi) + return; + + chip->ops->ctrl_btg_bt_rx(rtwdev, o_info->btg_rx[BTC_RF_S0], + RTW89_PHY_0); + if (chip->chip_id != RTL8922A) + return; + + chip->ops->ctrl_btg_bt_rx(rtwdev, o_info->btg_rx[BTC_RF_S1], + RTW89_PHY_1); } static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) From 7d1b3c22fe0f9881ffe6a196dcd5f42b3724483b Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 11 Jun 2025 11:55:22 +0800 Subject: [PATCH 44/63] wifi: rtw89: coex: Update hardware PTA resource binding logic WiFi 7 generation has 2 MAC, the PTA should bind the input/output to correct MAC to do the packet arbitration as expected. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 41 ++++++++++++++++++----- drivers/net/wireless/realtek/rtw89/reg.h | 1 + 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 04a05958fad4..97df4b2b3368 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -5360,15 +5360,47 @@ static void _set_bt_rx_scan_pri(struct rtw89_dev *rtwdev) _write_scbd(rtwdev, BTC_WSCB_RXSCAN_PRI, (bool)(!!bt->scan_rx_low_pri)); } +static void _wl_req_mac(struct rtw89_dev *rtwdev, u8 mac) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_dm *dm = &btc->dm; + u32 add; + + if (mac == wl->pta_req_mac) + return; + + dm->ost_info.pta_req_hw_band = mac; + wl->pta_req_mac = mac; + wl->pta_reg_mac_chg = true; + + if (btc->ver->fcxosi) + return; + + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) + add = R_BE_BTC_CFG; + else + add = R_AX_BTC_CFG; + + if (mac == RTW89_MAC_0) + rtw89_write32_clr(rtwdev, add, B_AX_WL_SRC); + else + rtw89_write32_set(rtwdev, add, B_AX_WL_SRC); +} + static void _action_common(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_wl_role_info_v8 *rinfo_v8 = &wl->role_info_v8; struct rtw89_btc_wl_smap *wl_smap = &wl->status.map; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_dm *dm = &btc->dm; u32 bt_rom_code_id, bt_fw_ver; + if (btc->ver->fwlrole == 8) + _wl_req_mac(rtwdev, rinfo_v8->pta_req_band); + _set_btg_ctrl(rtwdev); _set_wl_preagc_ctrl(rtwdev); _set_wl_tx_limit(rtwdev); @@ -5405,6 +5437,7 @@ static void _action_common(struct rtw89_dev *rtwdev) btc->cx.cnt_wl[BTC_WCNT_SCBDUPDATE]++; } btc->dm.tdma_instant_excute = 0; + wl->pta_reg_mac_chg = false; } static void _action_by_bt(struct rtw89_dev *rtwdev) @@ -5867,14 +5900,6 @@ _update_rssi_state(struct rtw89_dev *rtwdev, u8 pre_state, u8 rssi, u8 thresh) return next_state; } -static void _wl_req_mac(struct rtw89_dev *rtwdev, u8 mac) -{ - if (mac == RTW89_MAC_0) - rtw89_write32_clr(rtwdev, R_AX_BTC_CFG, B_AX_WL_SRC); - else - rtw89_write32_set(rtwdev, R_AX_BTC_CFG, B_AX_WL_SRC); -} - static void _update_dbcc_band(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 255a8635b195..4a65b0c9c2d1 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -6070,6 +6070,7 @@ #define B_BE_MACID_ACQ_GRP0_CLR_P BIT(2) #define B_BE_R_MACID_ACQ_CHK_EN BIT(0) +#define R_BE_BTC_CFG 0x0E300 #define R_BE_BT_BREAK_TABLE 0x0E344 #define R_BE_GNT_SW_CTRL 0x0E348 From 0bc2aef36949ea49285370ceab1da5b011bfd478 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Wed, 11 Jun 2025 11:55:23 +0800 Subject: [PATCH 45/63] wifi: rtw89: coex: Add PTA grant signal setting offload to firmware feature In the before experience there are many issue occurred because of the grant control signal can not be set in time especially WiFi power save enter/leave. To control the signal more accuracy, offload the control to firmware. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250611035523.36432-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 30 +++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 97df4b2b3368..934407dc53ea 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -2866,6 +2866,8 @@ static void _set_gnt_v1(struct rtw89_dev *rtwdev, u8 phy_map, { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_fbtc_outsrc_set_info *osi = &dm->ost_info; + struct rtw89_mac_ax_wl_act *b = dm->gnt.bt; struct rtw89_mac_ax_gnt *g = dm->gnt.band; u8 i, bt_idx = dm->bt_select + 1; @@ -2914,21 +2916,35 @@ static void _set_gnt_v1(struct rtw89_dev *rtwdev, u8 phy_map, switch (wlact_state) { case BTC_WLACT_HW: - dm->gnt.bt[i].wlan_act_en = 0; - dm->gnt.bt[i].wlan_act = 0; + b[i].wlan_act_en = 0; + b[i].wlan_act = 0; break; case BTC_WLACT_SW_LO: - dm->gnt.bt[i].wlan_act_en = 1; - dm->gnt.bt[i].wlan_act = 0; + b[i].wlan_act_en = 1; + b[i].wlan_act = 0; break; case BTC_WLACT_SW_HI: - dm->gnt.bt[i].wlan_act_en = 1; - dm->gnt.bt[i].wlan_act = 1; + b[i].wlan_act_en = 1; + b[i].wlan_act = 1; break; } } } - rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt); + + if (!btc->ver->fcxosi) { + rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt); + return; + } + + memcpy(osi->gnt_set, dm->gnt.band, sizeof(osi->gnt_set)); + memcpy(osi->wlact_set, dm->gnt.bt, sizeof(osi->wlact_set)); + + /* GBT source should be GBT_S1 in 1+1 (HWB0:5G + HWB1:2G) case */ + if (osi->rf_band[BTC_RF_S0] == 1 && + osi->rf_band[BTC_RF_S1] == 0) + osi->rf_gbt_source = BTC_RF_S1; + else + osi->rf_gbt_source = BTC_RF_S0; } #define BTC_TDMA_WLROLE_MAX 3 From d8643e681825cc5ac233f7a782c8b9406d016166 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:42 +0800 Subject: [PATCH 46/63] wifi: rtw89: coex: Add v1 Bluetooth AFH handshake for WiFi 7 WiFi 7 generation has dual MAC, Coexistence need to find out the 2GHz WiFi connection in the connected links. And assign its channel to Bluetooth to make Bluetooth not to hop into WiFi channel. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 111 +++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 934407dc53ea..d95ddc928e3d 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -3186,7 +3186,7 @@ static void _update_btc_state_map(struct rtw89_dev *rtwdev) } } -static void _set_bt_afh_info(struct rtw89_dev *rtwdev) +static void _set_bt_afh_info_v0(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; @@ -3355,6 +3355,115 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) btc->cx.cnt_wl[BTC_WCNT_CH_UPDATE]++; } +static void _set_bt_afh_info_v1(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; + struct rtw89_btc_wl_afh_info *wl_afh = &wl->afh_info; + struct rtw89_btc_bt_info *bt = &btc->cx.bt; + struct rtw89_btc_wl_rlink *rlink; + u8 en = 0, ch = 0, bw = 0, buf[3] = {}; + u8 i, j, link_mode; + + if (btc->manual_ctrl || wl->status.map.scan) + return; + + link_mode = wl_rinfo->link_mode; + + for (i = 0; i < btc->ver->max_role_num; i++) { + for (j = RTW89_MAC_0; j < RTW89_MAC_NUM; j++) { + if (wl->status.map.rf_off || bt->whql_test || + link_mode == BTC_WLINK_NOLINK || + link_mode == BTC_WLINK_5G) + break; + + rlink = &wl_rinfo->rlink[i][j]; + + /* Don't care no-connected/non-2G-band role */ + if (!rlink->connected || !rlink->active || + rlink->rf_band != RTW89_BAND_2G) + continue; + + en = 1; + ch = rlink->ch; + bw = rlink->bw; + + if (link_mode == BTC_WLINK_2G_MCC && + (rlink->role == RTW89_WIFI_ROLE_AP || + rlink->role == RTW89_WIFI_ROLE_P2P_GO || + rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT)) { + /* for 2.4G MCC, take role = ap/go/gc */ + break; + } else if (link_mode != BTC_WLINK_2G_SCC || + rlink->bw == RTW89_CHANNEL_WIDTH_40) { + /* for 2.4G scc, take bw = 40M */ + break; + } + } + } + + /* default AFH channel sapn = center-ch +- 6MHz */ + switch (bw) { + case RTW89_CHANNEL_WIDTH_20: + if (btc->dm.freerun || btc->dm.fddt_train) + bw = 48; + else + bw = 20 + chip->afh_guard_ch * 2; + break; + case RTW89_CHANNEL_WIDTH_40: + if (btc->dm.freerun) + bw = 40 + chip->afh_guard_ch * 2; + else + bw = 40; + break; + case RTW89_CHANNEL_WIDTH_5: + bw = 5 + chip->afh_guard_ch * 2; + break; + case RTW89_CHANNEL_WIDTH_10: + bw = 10 + chip->afh_guard_ch * 2; + break; + default: + en = false; /* turn off AFH info if invalid BW */ + bw = 0; + ch = 0; + break; + } + + if (!en || ch > 14 || ch == 0) { + en = false; + bw = 0; + ch = 0; + } + + if (wl_afh->en == en && + wl_afh->ch == ch && + wl_afh->bw == bw && + (!bt->enable.now || bt->enable.last)) + return; + + wl_afh->en = buf[0]; + wl_afh->ch = buf[1]; + wl_afh->bw = buf[2]; + + if (_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_WL_CH_INFO, &wl->afh_info, 3)) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): en=%d, ch=%d, bw=%d\n", + __func__, en, ch, bw); + + btc->cx.cnt_wl[BTC_WCNT_CH_UPDATE]++; + } +} + +static void _set_bt_afh_info(struct rtw89_dev *rtwdev) +{ + if (rtwdev->chip->chip_id == RTL8922A) + _set_bt_afh_info_v1(rtwdev); + else + _set_bt_afh_info_v0(rtwdev); +} + static bool _check_freerun(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; From 39251e189e4144c935adc8f2c08d7d703c3b8537 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:43 +0800 Subject: [PATCH 47/63] wifi: rtw89: coex: Enable outsource info H2C command The before several patches collect driver information, then this patch packet these information as outsource info and update to firmware by H2C command. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index d95ddc928e3d..3c607f5548b8 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -5561,6 +5561,16 @@ static void _action_common(struct rtw89_dev *rtwdev) wl->scbd_change = false; btc->cx.cnt_wl[BTC_WCNT_SCBDUPDATE]++; } + + if (btc->ver->fcxosi) { + if (memcmp(&dm->ost_info_last, &dm->ost_info, + sizeof(dm->ost_info_last)) || + dm->run_reason == BTC_RSN_NTFY_INIT || + dm->run_reason == BTC_RSN_NTFY_RADIO_STATE) { + dm->ost_info_last = dm->ost_info; + _fw_set_drv_info(rtwdev, CXDRVINFO_OSI); + } + } btc->dm.tdma_instant_excute = 0; wl->pta_reg_mac_chg = false; } From 10a39b9fd7a11591371bc352c16524f1a4d76396 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:44 +0800 Subject: [PATCH 48/63] wifi: rtw89: coex: Query Bluetooth TX power when firmware support Add firmware report to monitor Bluetooth TX power/gain settings, so that we can check it works as expected or not. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 101 +++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/core.h | 11 +++ 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 3c607f5548b8..d02725aad6c7 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -153,8 +153,8 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, - .fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, - .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 2, .info_buf = 1800, + .fwlrole = 8, .frptmap = 4, .fcxctrl = 7, .fcxinit = 7, + .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800, .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0), @@ -333,6 +333,7 @@ enum btc_btf_set_report_en { RPT_EN_BT_DEVICE_INFO, RPT_EN_BT_AFH_MAP, RPT_EN_BT_AFH_MAP_LE, + RPT_EN_BT_TX_PWR_LVL, RPT_EN_FW_STEP_INFO, RPT_EN_TEST, RPT_EN_WL_ALL, @@ -896,6 +897,9 @@ static int _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, return ret; } +#define BTC_BT_DEF_BR_TX_PWR 4 +#define BTC_BT_DEF_LE_TX_PWR 4 + static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; @@ -964,6 +968,9 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) if (type & BTC_RESET_MDINFO) memset(&btc->mdinfo, 0, sizeof(btc->mdinfo)); + + bt->link_info.bt_txpwr_desc.br_dbm = BTC_BT_DEF_BR_TX_PWR; + bt->link_info.bt_txpwr_desc.le_dbm = BTC_BT_DEF_LE_TX_PWR; } static u8 _search_reg_index(struct rtw89_dev *rtwdev, u8 mreg_num, u16 reg_type, u32 target) @@ -2381,6 +2388,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) bit_map = BIT(6); break; case 3: + case 4: bit_map = BIT(5); break; default: @@ -2395,6 +2403,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) bit_map = BIT(5); break; case 3: + case 4: bit_map = BIT(6); break; default: @@ -2407,12 +2416,27 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) bit_map = BIT(8); break; case 3: + case 4: bit_map = BIT(7); break; default: break; } break; + case RPT_EN_BT_TX_PWR_LVL: + switch (ver->frptmap) { + case 0: + case 1: + case 2: + case 3: + break; + case 4: + bit_map = BIT(8); + break; + default: + break; + } + break; case RPT_EN_FW_STEP_INFO: switch (ver->frptmap) { case 1: @@ -2422,6 +2446,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = BIT(8); break; + case 4: + bit_map = BIT(9); + break; default: break; } @@ -2439,6 +2466,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = GENMASK(2, 0) | BIT(8); break; + case 4: + bit_map = GENMASK(2, 0) | BIT(9); + break; default: break; } @@ -2455,6 +2485,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = GENMASK(7, 3); break; + case 4: + bit_map = GENMASK(8, 3); + break; default: break; } @@ -2471,6 +2504,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = GENMASK(8, 0); break; + case 4: + bit_map = GENMASK(9, 0); + break; default: break; } @@ -2487,6 +2523,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = GENMASK(8, 2); break; + case 4: + bit_map = GENMASK(9, 2); + break; default: break; } @@ -7379,6 +7418,25 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update) _run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD); } +#define BTC_BTINFO_PWR_LEN 5 +static void _update_bt_txpwr_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) +{ + struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt; + struct rtw89_btc_bt_link_info *b = &bt->link_info; + + if (len != BTC_BTINFO_PWR_LEN) + return; + + if (!memcmp(bt->txpwr_info, buf, sizeof(bt->txpwr_info))) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s return by info duplicate!\n", __func__); + return; + } + + memcpy(bt->txpwr_info, buf, BTC_BTINFO_MAX); + memcpy(&b->bt_txpwr_desc, &buf[2], sizeof(b->bt_txpwr_desc)); +} + static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -8617,6 +8675,8 @@ static u8 rtw89_btc_c2h_get_index_by_ver(struct rtw89_dev *rtwdev, u8 func) return BTF_EVNT_BUF_OVERFLOW; else if (ver->fwc2hfunc == 2) return func; + else if (ver->fwc2hfunc == 3) + return BTF_EVNT_BUF_OVERFLOW; else return BTF_EVNT_MAX; case BTF_EVNT_BUF_OVERFLOW: @@ -8626,11 +8686,20 @@ static u8 rtw89_btc_c2h_get_index_by_ver(struct rtw89_dev *rtwdev, u8 func) return BTF_EVNT_C2H_LOOPBACK; else if (ver->fwc2hfunc == 2) return func; + else if (ver->fwc2hfunc == 3) + return BTF_EVNT_C2H_LOOPBACK; else return BTF_EVNT_MAX; case BTF_EVNT_C2H_LOOPBACK: if (ver->fwc2hfunc == 2) return func; + else if (ver->fwc2hfunc == 3) + return BTF_EVNT_BT_LEAUDIO_INFO; + else + return BTF_EVNT_MAX; + case BTF_EVNT_BT_QUERY_TXPWR: + if (ver->fwc2hfunc == 3) + return func; else return BTF_EVNT_MAX; case BTF_EVNT_MAX: @@ -8693,6 +8762,9 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, case BTF_EVNT_CX_RUNINFO: btc->dm.cnt_dm[BTC_DCNT_CX_RUNINFO]++; break; + case BTF_EVNT_BT_QUERY_TXPWR: + btc->cx.cnt_bt[BTC_BCNT_BTTXPWR_UPDATE]++; + _update_bt_txpwr_info(rtwdev, buf, len); } } @@ -8965,8 +9037,11 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_bt_info *bt = &cx->bt; struct rtw89_btc_wl_info *wl = &cx->wl; + u32 ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw_coex); struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; union rtw89_btc_module_info *md = &btc->mdinfo; + s8 br_dbm = bt->link_info.bt_txpwr_desc.br_dbm; + s8 le_dbm = bt->link_info.bt_txpwr_desc.le_dbm; char *p = buf, *end = buf + bufsz; u8 *afh = bt_linfo->afh_map; u8 *afh_le = bt_linfo->afh_map_le; @@ -9099,6 +9174,28 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "\n"); } + if (ver_main >= 9 && bt_linfo->profile_cnt.now) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_TX_PWR_LVL, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_TX_PWR_LVL, false); + + if (cx->cnt_bt[BTC_BCNT_BTTXPWR_UPDATE]) { + p += scnprintf(p, end - p, + " %-15s : br_index:0x%x, le_index:0x%x", + "[bt_txpwr_lvl]", + bt->link_info.bt_txpwr_desc.br_gain_index, + bt->link_info.bt_txpwr_desc.le_gain_index); + p += scnprintf(p, end - p, ", br_dbm:%d dBm", br_dbm); + p += scnprintf(p, end - p, ", le_dbm:%d dBm", le_dbm); + } else { + p += scnprintf(p, end - p, + " %-15s : br_index:NA, le_index:NA, br_dbm:%d dBm[def], le_dbm:%d dBm[def]", + "[bt_txpwr_lvl]", + bt->link_info.bt_txpwr_desc.br_dbm, + bt->link_info.bt_txpwr_desc.le_dbm); + } + p += scnprintf(p, end - p, "\n"); + if (bt_linfo->profile_cnt.now || bt_linfo->status.map.ble_connect) rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, true); else diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 328d4e9352fe..3b046727e04a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1322,6 +1322,7 @@ enum rtw89_btc_bt_state_cnt { BTC_BCNT_POLUT_NOW, BTC_BCNT_POLUT_DIFF, BTC_BCNT_RATECHG, + BTC_BCNT_BTTXPWR_UPDATE, BTC_BCNT_NUM, }; @@ -1810,6 +1811,13 @@ union rtw89_btc_bt_state_map { #define BTC_BT_AFH_GROUP 12 #define BTC_BT_AFH_LE_GROUP 5 +struct rtw89_btc_bt_txpwr_desc { + s8 br_dbm; + s8 le_dbm; + u8 br_gain_index; + u8 le_gain_index; +}; + struct rtw89_btc_bt_link_info { struct rtw89_btc_u8_sta_chg profile_cnt; struct rtw89_btc_bool_sta_chg multi_link; @@ -1819,6 +1827,7 @@ struct rtw89_btc_bt_link_info { struct rtw89_btc_bt_a2dp_desc a2dp_desc; struct rtw89_btc_bt_pan_desc pan_desc; union rtw89_btc_bt_state_map status; + struct rtw89_btc_bt_txpwr_desc bt_txpwr_desc; u8 sut_pwr_level[BTC_PROFILE_MAX]; u8 golden_rx_shift[BTC_PROFILE_MAX]; @@ -2089,6 +2098,7 @@ struct rtw89_btc_bt_info { union rtw89_btc_bt_rfk_info_map rfk_info; u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */ + u8 txpwr_info[BTC_BTINFO_MAX]; u8 rssi_level; u32 scbd; @@ -3042,6 +3052,7 @@ enum rtw89_btc_btf_fw_event { BTF_EVNT_BT_LEAUDIO_INFO = 7, /* fwc2hfunc > 1 */ BTF_EVNT_BUF_OVERFLOW, BTF_EVNT_C2H_LOOPBACK, + BTF_EVNT_BT_QUERY_TXPWR, /* fwc2hfunc > 3 */ BTF_EVNT_MAX, }; From 43be50111483cf0a6d966194ee8f1127a7168ed1 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:45 +0800 Subject: [PATCH 49/63] wifi: rtw89: coex: RTL8922A add Wi-Fi firmware support for v0.35.71.0 The latest Wi-Fi firmware no feature update with Wi-Fi/Bluetooth coexistence. The patch describe the features support version. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index d02725aad6c7..a4c4b56e7fdd 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -149,6 +149,14 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, }, + {RTL8922A, RTW89_FW_VER_CODE(0, 35, 71, 0), + .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, + .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, + .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, + .fwlrole = 8, .frptmap = 4, .fcxctrl = 7, .fcxinit = 7, + .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800, + .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, + }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 63, 0), .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, From fc9b3028aae826a95376d571917212431b685f66 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:46 +0800 Subject: [PATCH 50/63] wifi: rtw89: coex: Get Bluetooth desired version by WiFi firmware version Because when Wi-Fi/Bluetooth want to communicate with each other, their contact window are their firmware. So the desired version code is more reasonable to change with firmware version. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 34 +++++++++---------- drivers/net/wireless/realtek/rtw89/core.h | 2 +- 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 - 8 files changed, 18 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index a4c4b56e7fdd..d34af499e137 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -139,7 +139,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, - .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 8, }, {RTL8852BT, RTW89_FW_VER_CODE(0, 29, 90, 0), .fcxbtcrpt = 7, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, @@ -147,7 +147,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, - .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 8, }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 71, 0), .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, @@ -155,7 +155,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 8, .frptmap = 4, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800, - .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, + .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, .bt_desired = 9, }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 63, 0), .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, @@ -163,7 +163,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 8, .frptmap = 4, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800, - .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, + .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, .bt_desired = 9, }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0), .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, @@ -171,7 +171,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 1, .drvinfo_type = 1, .info_buf = 1800, - .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, @@ -179,7 +179,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, - .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -187,7 +187,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -195,7 +195,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -203,7 +203,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, @@ -211,7 +211,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, - .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0), .fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4, @@ -219,7 +219,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, - .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -227,7 +227,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -235,7 +235,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0), .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, @@ -243,7 +243,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1024, - .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, /* keep it to be the last as default entry */ @@ -253,7 +253,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1024, - .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, }; @@ -8823,8 +8823,8 @@ static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "BT_FW_coex:%d(%s, desired:%d)\n", bt->ver_info.fw_coex, - (bt->ver_info.fw_coex >= chip->btcx_desired ? - "Match" : "Mismatch"), chip->btcx_desired); + (bt->ver_info.fw_coex >= ver->bt_desired ? + "Match" : "Mismatch"), ver->bt_desired); if (bt->enable.now && bt->ver_info.fw == 0) rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, true); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 3b046727e04a..cdacf100a59a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3199,6 +3199,7 @@ struct rtw89_btc_ver { u8 max_role_num; u8 fcxosi; u8 fcxmlo; + u8 bt_desired; }; struct rtw89_btc_btf_fwinfo { @@ -4422,7 +4423,6 @@ struct rtw89_chip_info { u32 para_ver; u32 wlcx_desired; - u8 btcx_desired; u8 scbd; u8 mailbox; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 39df1a255095..c55833f259de 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2529,7 +2529,6 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .phycap_size = 128, .para_ver = 0, .wlcx_desired = 0x06000000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index dc4eab2e7919..080636e8d0c3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2247,7 +2247,6 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .phycap_size = 128, .para_ver = 0x0, .wlcx_desired = 0x06000000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 1f1e10f2b39d..c0bf80450acf 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -883,7 +883,6 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .phycap_size = 128, .para_ver = 0, .wlcx_desired = 0x05050000, - .btcx_desired = 0x5, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 4c34f5037908..95e088734423 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -816,7 +816,6 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .phycap_size = 128, .para_ver = 0, .wlcx_desired = 0x070e0000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index b39add1b798c..8f3d0c91a3f8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -3070,7 +3070,6 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .phycap_size = 0x60, .para_ver = 0x1, .wlcx_desired = 0x06000000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index ca32ccb00107..603212ed4558 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2923,7 +2923,6 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .phycap_size = 0x38, .para_ver = 0xf, .wlcx_desired = 0x07110000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, From 3ba79eaee051373234c7e75153a29509fff37ccb Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:47 +0800 Subject: [PATCH 51/63] wifi: rtw89: coex: Update scoreboard to avoid Bluetooth re-link fail When platform resume, there will have fail rate when Bluetooth try to re-link. And when Bluetooth is booting up, it will run the ROM code first, then load the firmware code from file. Catch this change and set the mechanism for Bluetooth re-link. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index d34af499e137..399c86288d76 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -7420,6 +7420,8 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update) bt->rfk_info.map.req = !!(val & BTC_BSCB_RFK_REQ); bt->hi_lna_rx = !!(val & BTC_BSCB_BT_HILNA); bt->link_info.status.map.connect = !!(val & BTC_BSCB_BT_CONNECT); + if (bt->run_patch_code != !!(val & BTC_BSCB_PATCH_CODE)) + status_change = true; bt->run_patch_code = !!(val & BTC_BSCB_PATCH_CODE); if (!only_update && status_change) From d997fb2f8c49feef1a72a7d52d6031a6b847603d Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:48 +0800 Subject: [PATCH 52/63] wifi: rtw89: coex: Assign priority table before entering power save When Wi-Fi firmware scan, it will update the priority tables, and if stay at these priority tables then enter power saving will trigger Bluetooth issues. So update the priority before entering power saving. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 399c86288d76..138b3559a37b 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -3996,6 +3996,15 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) u32 tbl_w1, tbl_b1, tbl_b4; u16 dur_2; + if (wl->status.map.lps) { + _slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur, + s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype); + _slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur, + s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype); + _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, + s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); + } + type = FIELD_GET(BTC_CXP_MASK, policy_type); if (btc->ant_type == BTC_ANT_SHARED) { From a7feafea4ce80d5fa5284d05d54b4f108d2ab575 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:49 +0800 Subject: [PATCH 53/63] wifi: rtw89: coex: Not to set slot duration to zero to avoid firmware issue If the duration set to zero, Wi-Fi firmware will trigger some unexpected issue when firmware try to enable timer. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 138b3559a37b..60760512e93d 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -4125,13 +4125,13 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) switch (policy_type) { case BTC_CXP_OFFE_2GBWISOB: /* for normal-case */ - _slot_set(btc, CXST_E2G, 0, tbl_w1, SLOT_ISO); + _slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_ISO); _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); _slot_set_dur(btc, CXST_EBT, dur_2); break; case BTC_CXP_OFFE_2GISOB: /* for bt no-link */ - _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_ISO); + _slot_set(btc, CXST_E2G, 5, cxtbl[1], SLOT_ISO); _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); _slot_set_dur(btc, CXST_EBT, dur_2); @@ -4157,15 +4157,15 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) break; case BTC_CXP_OFFE_2GBWMIXB: if (a2dp->exist) - _slot_set(btc, CXST_E2G, 0, cxtbl[2], SLOT_MIX); + _slot_set(btc, CXST_E2G, 5, cxtbl[2], SLOT_MIX); else - _slot_set(btc, CXST_E2G, 0, tbl_w1, SLOT_MIX); + _slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_MIX); _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); break; case BTC_CXP_OFFE_WL: /* for 4-way */ - _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_MIX); - _slot_set(btc, CXST_EBT, 0, cxtbl[1], SLOT_MIX); + _slot_set(btc, CXST_E2G, 5, cxtbl[1], SLOT_MIX); + _slot_set(btc, CXST_EBT, 5, cxtbl[1], SLOT_MIX); break; default: break; From 8ef99ee5d278eed066daeb5d30f06a9872508c13 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:50 +0800 Subject: [PATCH 54/63] wifi: rtw89: coex: Update Bluetooth slot length when Wi-Fi is scanning If Wi-Fi isn't connected to AP, the firmware scan will not switch to operation channel. Bluetooth may not have enough time to TX data. This patch extend the slot to let Bluetooth can TX more to avoid audio lag. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 60760512e93d..f6b482b20dc7 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -4160,7 +4160,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) _slot_set(btc, CXST_E2G, 5, cxtbl[2], SLOT_MIX); else _slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_MIX); - _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, + _slot_set_le(btc, CXST_EBT, cpu_to_le16(40), s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); break; case BTC_CXP_OFFE_WL: /* for 4-way */ From 206a8f999fcb3ca6cf3c1bf8bd287698ba9692b2 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:51 +0800 Subject: [PATCH 55/63] wifi: rtw89: coex: RTL8852B coexistence Wi-Fi firmware support for v0.29.122.0 Add format version of Wi-Fi firmware commands/events for firmware version v0.29.122.0. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index f6b482b20dc7..9eecd8e6bfad 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -205,6 +205,14 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, + {RTL8852B, RTW89_FW_VER_CODE(0, 29, 122, 0), + .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, + .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, + .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, + .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, + .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 8, + }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, From c5ef95e29166ac868a96ae6e2c5b6357e3495f10 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Mon, 16 Jun 2025 17:02:52 +0800 Subject: [PATCH 56/63] wifi: rtw89: coex: Update Wi-Fi/Bluetooth coexistence version to 9.0.0 The version 9 support the WiFi7 related functions. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616090252.51098-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 9eecd8e6bfad..e4e6daf51a1b 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -11,7 +11,7 @@ #include "ps.h" #include "reg.h" -#define RTW89_COEX_VERSION 0x07000413 +#define RTW89_COEX_VERSION 0x09000013 #define FCXDEF_STEP 50 /* MUST <= FCXMAX_STEP and match with wl fw*/ #define BTC_E2G_LIMIT_DEF 80 From 9c5c5a920a7926791c2c44f374c4354b4eda85d3 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Wed, 18 Jun 2025 20:46:44 +0800 Subject: [PATCH 57/63] wifi: rtw89: mac: differentiate mem_page_size by chip generation When debugging or recovering system error recovery (SER), it's necessary to dump internal memory to perform status inspection. Since the memory page size differs between WiFi 6 and 7 chips, define them accordingly. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250618124649.11436-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/debug.c | 13 +++++++------ drivers/net/wireless/realtek/rtw89/mac.c | 1 + drivers/net/wireless/realtek/rtw89/mac.h | 5 ++++- drivers/net/wireless/realtek/rtw89/mac_be.c | 1 + drivers/net/wireless/realtek/rtw89/ser.c | 11 ++++++----- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index d6016fa107fb..4acb567b3ad4 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -1114,6 +1114,7 @@ static int rtw89_debug_dump_mac_mem(struct rtw89_dev *rtwdev, const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 filter_model_addr = mac->filter_model_addr; u32 indir_access_addr = mac->indir_access_addr; + u32 mem_page_size = mac->mem_page_size; u32 base_addr, start_page, residue; char *p = buf, *end = buf + bufsz; u32 i, j, pp, pages; @@ -1121,14 +1122,14 @@ static int rtw89_debug_dump_mac_mem(struct rtw89_dev *rtwdev, u32 val; remain = len; - pages = len / MAC_MEM_DUMP_PAGE_SIZE + 1; - start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE; - residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE; + pages = len / mem_page_size + 1; + start_page = start_addr / mem_page_size; + residue = start_addr % mem_page_size; base_addr = mac->mem_base_addrs[sel]; - base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE; + base_addr += start_page * mem_page_size; for (pp = 0; pp < pages; pp++) { - dump_len = min_t(u32, remain, MAC_MEM_DUMP_PAGE_SIZE); + dump_len = min_t(u32, remain, mem_page_size); rtw89_write32(rtwdev, filter_model_addr, base_addr); for (i = indir_access_addr + residue; i < indir_access_addr + dump_len;) { @@ -1142,7 +1143,7 @@ static int rtw89_debug_dump_mac_mem(struct rtw89_dev *rtwdev, } p += scnprintf(p, end - p, "\n"); } - base_addr += MAC_MEM_DUMP_PAGE_SIZE; + base_addr += mem_page_size; } return p - buf; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 8ec86e1fa9d6..53628838a7c5 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -6914,6 +6914,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .filter_model_addr = R_AX_FILTER_MODEL_ADDR, .indir_access_addr = R_AX_INDIR_ACCESS_ENTRY, .mem_base_addrs = rtw89_mac_mem_base_addrs_ax, + .mem_page_size = MAC_MEM_DUMP_PAGE_SIZE_AX, .rx_fltr = R_AX_RX_FLTR_OPT, .port_base = &rtw89_port_base_ax, .agg_len_ht = R_AX_AGG_LEN_HT_0, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index c1cbc53b16a7..b7fd4a0fdb84 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -8,7 +8,9 @@ #include "core.h" #include "reg.h" -#define MAC_MEM_DUMP_PAGE_SIZE 0x40000 +#define MAC_MEM_DUMP_PAGE_SIZE_AX 0x40000 +#define MAC_MEM_DUMP_PAGE_SIZE_BE 0x80000 + #define ADDR_CAM_ENT_SIZE 0x40 #define ADDR_CAM_ENT_SHORT_SIZE 0x20 #define BSSID_CAM_ENT_SIZE 0x08 @@ -970,6 +972,7 @@ struct rtw89_mac_gen_def { u32 filter_model_addr; u32 indir_access_addr; const u32 *mem_base_addrs; + u32 mem_page_size; u32 rx_fltr; const struct rtw89_port_reg *port_base; u32 agg_len_ht; diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 8c9d326dc907..0078080b3999 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2567,6 +2567,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .filter_model_addr = R_BE_FILTER_MODEL_ADDR, .indir_access_addr = R_BE_INDIR_ACCESS_ENTRY, .mem_base_addrs = rtw89_mac_mem_base_addrs_be, + .mem_page_size = MAC_MEM_DUMP_PAGE_SIZE_BE, .rx_fltr = R_BE_RX_FLTR_OPT, .port_base = &rtw89_port_base_be, .agg_len_ht = R_BE_AGG_LEN_HT_0, diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 811c91481441..d504518b8a57 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -566,21 +566,22 @@ static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf, const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 filter_model_addr = mac->filter_model_addr; u32 indir_access_addr = mac->indir_access_addr; + u32 mem_page_size = mac->mem_page_size; u32 *ptr = (u32 *)buf; u32 base_addr, start_page, residue; u32 cnt = 0; u32 i; - start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE; - residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE; + start_page = start_addr / mem_page_size; + residue = start_addr % mem_page_size; base_addr = mac->mem_base_addrs[sel]; - base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE; + base_addr += start_page * mem_page_size; while (cnt < len) { rtw89_write32(rtwdev, filter_model_addr, base_addr); for (i = indir_access_addr + residue; - i < indir_access_addr + MAC_MEM_DUMP_PAGE_SIZE; + i < indir_access_addr + mem_page_size; i += 4, ptr++) { *ptr = rtw89_read32(rtwdev, i); cnt += 4; @@ -589,7 +590,7 @@ static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf, } residue = 0; - base_addr += MAC_MEM_DUMP_PAGE_SIZE; + base_addr += mem_page_size; } } From 8408366f61a7dddc1262ac74662b6238a22c447f Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Wed, 18 Jun 2025 20:46:45 +0800 Subject: [PATCH 58/63] wifi: rtw89: update EDCCA report for subband 40M/80M/sub-20M EDCCA report is obtained from the hardware to display OBSS interference and their respective power levels for each subband. Modify the query settings to improve resolution for debugging purposes. Signed-off-by: Eric Huang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250618124649.11436-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index a05841304e0e..f81bee4149bf 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -7128,7 +7128,7 @@ static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *b const struct rtw89_edcca_p_regs *edcca_p_regs; bool flag_fb, flag_p20, flag_s20, flag_s40, flag_s80; s8 pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80; - u8 path, per20_bitmap; + u8 path, per20_bitmap = 0; u8 pwdb[8]; u32 tmp; @@ -7158,14 +7158,11 @@ static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *b pwdb_fb = u32_get_bits(tmp, MASKBYTE3); rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel, - edcca_p_regs->rpt_sel_mask, 4); + edcca_p_regs->rpt_sel_mask, 5); tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_b); pwdb_s80 = u32_get_bits(tmp, MASKBYTE1); pwdb_s40 = u32_get_bits(tmp, MASKBYTE2); - per20_bitmap = rtw89_phy_read32_mask(rtwdev, edcca_p_regs->rpt_a, - MASKBYTE0); - if (rtwdev->chip->chip_id == RTL8922A) { rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, edcca_regs->rpt_sel_be_mask, 4); @@ -7174,6 +7171,8 @@ static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *b pwdb[1] = u32_get_bits(tmp, MASKBYTE2); pwdb[2] = u32_get_bits(tmp, MASKBYTE1); pwdb[3] = u32_get_bits(tmp, MASKBYTE0); + per20_bitmap = rtw89_phy_read32_mask(rtwdev, edcca_p_regs->rpt_a, + MASKBYTE0); rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, edcca_regs->rpt_sel_be_mask, 5); @@ -7190,7 +7189,7 @@ static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *b pwdb[1] = u32_get_bits(tmp, MASKBYTE2); rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel, - edcca_p_regs->rpt_sel_mask, 1); + edcca_p_regs->rpt_sel_mask, 5); tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_a); pwdb[2] = u32_get_bits(tmp, MASKBYTE3); pwdb[3] = u32_get_bits(tmp, MASKBYTE2); From 640c27b2e0c504e5021b6b7635e3626781a45dba Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Wed, 18 Jun 2025 20:46:46 +0800 Subject: [PATCH 59/63] wifi: rtw89: correct length for IE18/19 PHY report and IE parser Correct the length when parsing with 2nd IE header and the length of IE18/19 PHY status report. These two IE contain PHY OFDM signal information and can be used for debug. Signed-off-by: Eric Huang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250618124649.11436-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 4026cda04ef6..d0d2ca31b376 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1723,7 +1723,7 @@ static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, }, [RTW89_CHIP_BE] = { 32, 40, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, - VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, + VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 88, 56, VAR_LEN, VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 }, }; @@ -1918,6 +1918,8 @@ static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev, return -EINVAL; pos = phy_ppdu->buf + PHY_STS_HDR_LEN; + if (phy_ppdu->hdr_2_en) + pos += PHY_STS_HDR_LEN; end = phy_ppdu->buf + phy_ppdu->len; while (pos < end) { const struct rtw89_phy_sts_iehdr *iehdr = pos; From 7e04f01bb94fe61c73cc59f0495c3b6c16a83231 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 18 Jun 2025 20:46:47 +0800 Subject: [PATCH 60/63] wifi: rtw89: avoid NULL dereference when RX problematic packet on unsupported 6 GHz band With a quite rare chance, RX report might be problematic to make SW think a packet is received on 6 GHz band even if the chip does not support 6 GHz band actually. Since SW won't initialize stuffs for unsupported bands, NULL dereference will happen then in the sequence, rtw89_vif_rx_stats_iter() -> rtw89_core_cancel_6ghz_probe_tx(). So, add a check to avoid it. The following is a crash log for this case. BUG: kernel NULL pointer dereference, address: 0000000000000032 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 1 PID: 1907 Comm: irq/131-rtw89_p Tainted: G U 6.6.56-05896-g89f5fb0eb30b #1 (HASH:1400 4) Hardware name: Google Telith/Telith, BIOS Google_Telith.15217.747.0 11/12/2024 RIP: 0010:rtw89_vif_rx_stats_iter+0xd2/0x310 [rtw89_core] Code: 4c 89 7d c8 48 89 55 c0 49 8d 44 24 02 48 89 45 b8 45 31 ff eb 11 41 c6 45 3a 01 41 b7 01 4d 8b 6d 00 4d 39 f5 74 42 8b 43 10 <41> 33 45 32 0f b7 4b 14 66 41 33 4d 36 0f b7 c9 09 c1 74 d8 4d 85 RSP: 0018:ffff9f3080138ca0 EFLAGS: 00010246 RAX: 00000000b8bf5770 RBX: ffff91b5e8c639c0 RCX: 0000000000000011 RDX: ffff91b582de1be8 RSI: 0000000000000000 RDI: ffff91b5e8c639e6 RBP: ffff9f3080138d00 R08: 0000000000000000 R09: 0000000000000000 R10: ffff91b59de70000 R11: ffffffffc069be50 R12: ffff91b5e8c639e4 R13: 0000000000000000 R14: ffff91b5828020b8 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff91b8efa40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000032 CR3: 00000002bf838000 CR4: 0000000000750ee0 PKRU: 55555554 Call Trace: ? __die_body+0x68/0xb0 ? page_fault_oops+0x379/0x3e0 ? exc_page_fault+0x4f/0xa0 ? asm_exc_page_fault+0x22/0x30 ? __pfx_rtw89_vif_rx_stats_iter+0x10/0x10 [rtw89_core (HASH:1400 5)] ? rtw89_vif_rx_stats_iter+0xd2/0x310 [rtw89_core (HASH:1400 5)] __iterate_interfaces+0x59/0x110 [mac80211 (HASH:1400 6)] ? __pfx_rtw89_vif_rx_stats_iter+0x10/0x10 [rtw89_core (HASH:1400 5)] ? __pfx_rtw89_vif_rx_stats_iter+0x10/0x10 [rtw89_core (HASH:1400 5)] ieee80211_iterate_active_interfaces_atomic+0x36/0x50 [mac80211 (HASH:1400 6)] rtw89_core_rx_to_mac80211+0xfd/0x1b0 [rtw89_core (HASH:1400 5)] rtw89_core_rx+0x43a/0x980 [rtw89_core (HASH:1400 5)] Fixes: c6aa9a9c4725 ("wifi: rtw89: add RNR support for 6 GHz scan") Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250618124649.11436-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index d0d2ca31b376..0babf5472195 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2161,6 +2161,11 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev, if (rx_status->band != NL80211_BAND_6GHZ) return; + if (unlikely(!(rtwdev->chip->support_bands & BIT(NL80211_BAND_6GHZ)))) { + rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "invalid rx on unsupported 6 GHz\n"); + return; + } + ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, skb->len); list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) { From c2852b5a0575b0f9de7e6359b9725a5b074778f8 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 18 Jun 2025 20:46:48 +0800 Subject: [PATCH 61/63] wifi: rtw89: report boottime of receiving beacon and probe response Userspace tools will parse NL80211_BSS_LAST_SEEN_BOOTTIME (if any) for a more accurate timing when a BSS was seen. For example, iw, wpa_supplicant. For beacon and probe response, fill RX boottime_ns in ieee80211_rx_status. And for certain, it shouldn't count the waiting time for the PPDU status, i.e. the possible buffering time of a frame in driver. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250618124649.11436-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 0babf5472195..1f5639a5d166 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2796,9 +2796,11 @@ static void rtw89_core_stats_sta_rx_status(struct rtw89_dev *rtwdev, } static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev, + struct sk_buff *skb, struct rtw89_rx_desc_info *desc_info, struct ieee80211_rx_status *rx_status) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; const struct cfg80211_chan_def *chandef = rtw89_chandef_get(rtwdev, RTW89_CHANCTX_0); u16 data_rate; @@ -2810,6 +2812,10 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev, rx_status->freq = chandef->chan->center_freq; rx_status->band = chandef->chan->band; + if (ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) + rx_status->boottime_ns = ktime_get_boottime_ns(); + if (rtwdev->scanning && RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) { const struct rtw89_chan *cur = rtw89_scan_chan_get(rtwdev); @@ -2966,7 +2972,7 @@ void rtw89_core_rx(struct rtw89_dev *rtwdev, rx_status = IEEE80211_SKB_RXCB(skb); memset(rx_status, 0, sizeof(*rx_status)); - rtw89_core_update_rx_status(rtwdev, desc_info, rx_status); + rtw89_core_update_rx_status(rtwdev, skb, desc_info, rx_status); rtw89_core_rx_pkt_hdl(rtwdev, skb, desc_info); if (desc_info->long_rxdesc && BIT(desc_info->frame_type) & PPDU_FILTER_BITMAP) From 44c0e191004f0e3aa1bdee3be248be14dbe5b020 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Mon, 16 Jun 2025 12:56:30 +0200 Subject: [PATCH 62/63] wifi: rtlwifi: fix possible skb memory leak in `_rtl_pci_rx_interrupt()`. The function `_rtl_pci_init_one_rxdesc()` can fail even when the new `skb` is passed because of a DMA mapping error. If it fails, the `skb` is not saved in the rx ringbuffer and thus lost. Compile tested only Signed-off-by: Thomas Fourier Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250616105631.444309-4-fourier.thomas@gmail.com --- drivers/net/wireless/realtek/rtlwifi/pci.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 472072630f8d..d080469264cf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -805,13 +805,19 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) skb = new_skb; no_new: if (rtlpriv->use_new_trx_flow) { - _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)buffer_desc, - rxring_idx, - rtlpci->rx_ring[rxring_idx].idx); + if (!_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)buffer_desc, + rxring_idx, + rtlpci->rx_ring[rxring_idx].idx)) { + if (new_skb) + dev_kfree_skb_any(skb); + } } else { - _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc, - rxring_idx, - rtlpci->rx_ring[rxring_idx].idx); + if (!_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc, + rxring_idx, + rtlpci->rx_ring[rxring_idx].idx)) { + if (new_skb) + dev_kfree_skb_any(skb); + } if (rtlpci->rx_ring[rxring_idx].idx == rtlpci->rxringcount - 1) rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, From 16d8fd74dbfca0ea58645cd2fca13be10cae3cdd Mon Sep 17 00:00:00 2001 From: Daniil Dulov Date: Tue, 17 Jun 2025 16:56:34 +0300 Subject: [PATCH 63/63] wifi: rtl818x: Kill URBs before clearing tx status queue In rtl8187_stop() move the call of usb_kill_anchored_urbs() before clearing b_tx_status.queue. This change prevents callbacks from using already freed skb due to anchor was not killed before freeing such skb. BUG: kernel NULL pointer dereference, address: 0000000000000080 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: Oops: 0000 [#1] SMP NOPTI CPU: 7 UID: 0 PID: 0 Comm: swapper/7 Not tainted 6.15.0 #8 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015 RIP: 0010:ieee80211_tx_status_irqsafe+0x21/0xc0 [mac80211] Call Trace: rtl8187_tx_cb+0x116/0x150 [rtl8187] __usb_hcd_giveback_urb+0x9d/0x120 usb_giveback_urb_bh+0xbb/0x140 process_one_work+0x19b/0x3c0 bh_worker+0x1a7/0x210 tasklet_action+0x10/0x30 handle_softirqs+0xf0/0x340 __irq_exit_rcu+0xcd/0xf0 common_interrupt+0x85/0xa0 Tested on RTL8187BvE device. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: c1db52b9d27e ("rtl8187: Use usb anchor facilities to manage urbs") Signed-off-by: Daniil Dulov Reviewed-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250617135634.21760-1-d.dulov@aladdin.ru --- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 220ac5bdf279..8a57d6c72335 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1041,10 +1041,11 @@ static void rtl8187_stop(struct ieee80211_hw *dev, bool suspend) rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + usb_kill_anchored_urbs(&priv->anchored); + while ((skb = skb_dequeue(&priv->b_tx_status.queue))) dev_kfree_skb_any(skb); - usb_kill_anchored_urbs(&priv->anchored); mutex_unlock(&priv->conf_mutex); if (!priv->is_rtl8187b)