From 9f68fdcdc9dbf21be2a48feced90ff7f77d07443 Mon Sep 17 00:00:00 2001 From: Roman Peshkichev Date: Tue, 25 Nov 2025 23:09:37 +0500 Subject: [PATCH 01/81] wifi: rtw88: fix DTIM period handling when conf->dtim_period is zero The function rtw_set_dtim_period() accepted an 'int' dtim_period parameter, while mac80211 provides dtim_period as 'u8' in struct ieee80211_bss_conf. In IBSS (ad-hoc) mode mac80211 may set dtim_period to 0. The driver unconditionally wrote (dtim_period - 1) to REG_DTIM_COUNTER_ROOT, which resulted in 0xFF when dtim_period was 0. This caused delays in broadcast/multicast traffic processing and issues with ad-hoc operation. Convert the function parameter to u8 to match ieee80211_bss_conf and avoid the underflow by writing 0 when dtim_period is 0. Link: https://github.com/lwfinger/rtw88/issues/406 Signed-off-by: Roman Peshkichev Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251125180937.22977-1-roman.peshkichev@gmail.com --- drivers/net/wireless/realtek/rtw88/main.c | 4 ++-- drivers/net/wireless/realtek/rtw88/main.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index fa0ed39cb199..361ce0d40956 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -730,10 +730,10 @@ void rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel) } EXPORT_SYMBOL(rtw_set_rx_freq_band); -void rtw_set_dtim_period(struct rtw_dev *rtwdev, int dtim_period) +void rtw_set_dtim_period(struct rtw_dev *rtwdev, u8 dtim_period) { rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_TIMIE); - rtw_write8(rtwdev, REG_DTIM_COUNTER_ROOT, dtim_period - 1); + rtw_write8(rtwdev, REG_DTIM_COUNTER_ROOT, dtim_period ? dtim_period - 1 : 0); } void rtw_update_channel(struct rtw_dev *rtwdev, u8 center_channel, diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 43ed6d6b4291..1ab70214ce36 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -2226,7 +2226,7 @@ enum nl80211_band rtw_hw_to_nl80211_band(enum rtw_supported_band hw_band) } void rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel); -void rtw_set_dtim_period(struct rtw_dev *rtwdev, int dtim_period); +void rtw_set_dtim_period(struct rtw_dev *rtwdev, u8 dtim_period); void rtw_get_channel_params(struct cfg80211_chan_def *chandef, struct rtw_channel_params *ch_param); bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target); From 44d1f624bbdd2d60319374ba85f7195a28d00c90 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sun, 30 Nov 2025 16:50:31 +0200 Subject: [PATCH 02/81] wifi: rtw88: 8822b: Avoid WARNING in rtw8822b_config_trx_mode() rtw8822b_set_antenna() can be called from userspace when the chip is powered off. In that case a WARNING is triggered in rtw8822b_config_trx_mode() because trying to read the RF registers when the chip is powered off returns an unexpected value. Call rtw8822b_config_trx_mode() in rtw8822b_set_antenna() only when the chip is powered on. ------------[ cut here ]------------ write RF mode table fail WARNING: CPU: 0 PID: 7183 at rtw8822b.c:824 rtw8822b_config_trx_mode.constprop.0+0x835/0x840 [rtw88_8822b] CPU: 0 UID: 0 PID: 7183 Comm: iw Tainted: G W OE 6.17.5-arch1-1 #1 PREEMPT(full) 01c39fc421df2af799dd5e9180b572af860b40c1 Tainted: [W]=WARN, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE Hardware name: LENOVO 82KR/LNVNB161216, BIOS HBCN18WW 08/27/2021 RIP: 0010:rtw8822b_config_trx_mode.constprop.0+0x835/0x840 [rtw88_8822b] Call Trace: rtw8822b_set_antenna+0x57/0x70 [rtw88_8822b 370206f42e5890d8d5f48eb358b759efa37c422b] rtw_ops_set_antenna+0x50/0x80 [rtw88_core 711c8fb4f686162be4625b1d0b8e8c6a5ac850fb] ieee80211_set_antenna+0x60/0x100 [mac80211 f1845d85d2ecacf3b71867635a050ece90486cf3] nl80211_set_wiphy+0x384/0xe00 [cfg80211 296485ee85696d2150309a6d21a7fbca83d3dbda] ? netdev_run_todo+0x63/0x550 genl_family_rcv_msg_doit+0xfc/0x160 genl_rcv_msg+0x1aa/0x2b0 ? __pfx_nl80211_pre_doit+0x10/0x10 [cfg80211 296485ee85696d2150309a6d21a7fbca83d3dbda] ? __pfx_nl80211_set_wiphy+0x10/0x10 [cfg80211 296485ee85696d2150309a6d21a7fbca83d3dbda] ? __pfx_nl80211_post_doit+0x10/0x10 [cfg80211 296485ee85696d2150309a6d21a7fbca83d3dbda] ? __pfx_genl_rcv_msg+0x10/0x10 netlink_rcv_skb+0x59/0x110 genl_rcv+0x28/0x40 netlink_unicast+0x285/0x3c0 ? __alloc_skb+0xdb/0x1a0 netlink_sendmsg+0x20d/0x430 ____sys_sendmsg+0x39f/0x3d0 ? import_iovec+0x2f/0x40 ___sys_sendmsg+0x99/0xe0 ? refill_obj_stock+0x12e/0x240 __sys_sendmsg+0x8a/0xf0 do_syscall_64+0x81/0x970 ? do_syscall_64+0x81/0x970 ? ksys_read+0x73/0xf0 ? do_syscall_64+0x81/0x970 ? count_memcg_events+0xc2/0x190 ? handle_mm_fault+0x1d7/0x2d0 ? do_user_addr_fault+0x21a/0x690 ? exc_page_fault+0x7e/0x1a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e ---[ end trace 0000000000000000 ]--- Link: https://github.com/lwfinger/rtw88/issues/366 Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/fb9a3444-9319-4aa2-8719-35a6308bf568@gmail.com --- drivers/net/wireless/realtek/rtw88/rtw8822b.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 89b6485b229a..4d88cc2f4148 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -1005,7 +1005,8 @@ static int rtw8822b_set_antenna(struct rtw_dev *rtwdev, hal->antenna_tx = antenna_tx; hal->antenna_rx = antenna_rx; - rtw8822b_config_trx_mode(rtwdev, antenna_tx, antenna_rx, false); + if (test_bit(RTW_FLAG_POWERON, rtwdev->flags)) + rtw8822b_config_trx_mode(rtwdev, antenna_tx, antenna_rx, false); return 0; } From 77653c327e11c71c5363b18a53fbf2b92ed21da4 Mon Sep 17 00:00:00 2001 From: Hsiu-Ming Chang Date: Fri, 5 Dec 2025 08:32:04 +0800 Subject: [PATCH 03/81] wifi: rtw88: rtw8821cu: Add ID for Mercusys MU6H Add support for Mercusys MU6H AC650 High Gain Wireless Dual Band USB Adapter V1.30. It is based on RTL8811CU, usb device ID is 2c4e:0105. Signed-off-by: Hsiu-Ming Chang Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251205003245.5762-1-cges30901@gmail.com --- drivers/net/wireless/realtek/rtw88/rtw8821cu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821cu.c b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c index 7a0fffc359e2..8cd09d66655d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821cu.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c @@ -37,6 +37,8 @@ static const struct usb_device_id rtw_8821cu_id_table[] = { .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */ { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd811, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x0105, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Mercusys */ {}, }; MODULE_DEVICE_TABLE(usb, rtw_8821cu_id_table); From 41be33d3efc120f6a2c02d12742655f2aa09e1b6 Mon Sep 17 00:00:00 2001 From: Jose Ignacio Tornos Martinez Date: Wed, 26 Nov 2025 10:18:56 +0100 Subject: [PATCH 04/81] wifi: rtw89: 8922a: set random mac if efuse contains zeroes I have some rtl8922ae devices with no permanent mac stored in efuse. It could be properly saved and/or configured from user tools like NetworkManager, but it would be desirable to be able to initialize it somehow to get the device working by default. So, in the same way as with other devices, if the mac address read from efuse contains zeros, a random mac address is assigned to at least allow operation, and the user is warned about this in case any action needs to be considered. Signed-off-by: Jose Ignacio Tornos Martinez Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251126091905.217951-1-jtornosm@redhat.com --- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 4437279c554b..4bcf20612a45 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -636,16 +636,30 @@ static int rtw8922a_read_efuse_rf(struct rtw89_dev *rtwdev, u8 *log_map) static int rtw8922a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, enum rtw89_efuse_block block) { + struct rtw89_efuse *efuse = &rtwdev->efuse; + int ret; + switch (block) { case RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO: - return rtw8922a_read_efuse_pci_sdio(rtwdev, log_map); + ret = rtw8922a_read_efuse_pci_sdio(rtwdev, log_map); + break; case RTW89_EFUSE_BLOCK_HCI_DIG_USB: - return rtw8922a_read_efuse_usb(rtwdev, log_map); + ret = rtw8922a_read_efuse_usb(rtwdev, log_map); + break; case RTW89_EFUSE_BLOCK_RF: - return rtw8922a_read_efuse_rf(rtwdev, log_map); + ret = rtw8922a_read_efuse_rf(rtwdev, log_map); + break; default: - return 0; + ret = 0; + break; } + + if (!ret && is_zero_ether_addr(efuse->addr)) { + rtw89_info(rtwdev, "efuse mac address is zero, using random mac\n"); + eth_random_addr(efuse->addr); + } + + return ret; } #define THM_TRIM_POSITIVE_MASK BIT(6) From 36f2deb2f55f1d72800758e3eeaac17fe31dffe0 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Wed, 10 Dec 2025 11:12:09 +0100 Subject: [PATCH 05/81] wifi: rtw89: add WQ_PERCPU to alloc_workqueue users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue flag in: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The refactoring is going to alter the default behavior of alloc_workqueue() to be unbound by default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. For more details see the Link tag below. In order to keep alloc_workqueue() behavior identical, explicitly request WQ_PERCPU. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/ Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251210101209.47176-1-marco.crivellari@suse.com --- drivers/net/wireless/realtek/rtw89/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c index d7d968207a39..e77561a4d971 100644 --- a/drivers/net/wireless/realtek/rtw89/usb.c +++ b/drivers/net/wireless/realtek/rtw89/usb.c @@ -620,7 +620,7 @@ static int rtw89_usb_init_rx(struct rtw89_dev *rtwdev) struct sk_buff *rx_skb; int i; - rtwusb->rxwq = alloc_workqueue("rtw89_usb: rx wq", WQ_BH, 0); + rtwusb->rxwq = alloc_workqueue("rtw89_usb: rx wq", WQ_BH | WQ_PERCPU, 0); if (!rtwusb->rxwq) { rtw89_err(rtwdev, "failed to create RX work queue\n"); return -ENOMEM; From a2f1fc9ab6fb0d5c9d701a516c342944258fb20e Mon Sep 17 00:00:00 2001 From: Jan Gerber Date: Fri, 12 Dec 2025 01:54:21 +0100 Subject: [PATCH 06/81] wifi: rtw89: 8852au: add support for TP TX30U Plus the device shows up like this and everything seams to work: Bus 004 Device 003: ID 3625:010d Realtek 802.11ax WLAN Adapter Signed-off-by: Jan Gerber Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251212005515.2059533-1-j@mailb.org --- drivers/net/wireless/realtek/rtw89/rtw8852au.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c index ca782469c455..74a976c984ad 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c @@ -60,6 +60,8 @@ static const struct usb_device_id rtw_8852au_id_table[] = { .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0141, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3625, 0x010d, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x3625, 0x010f, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, {}, From d3a9e132a4c6273a5254e743da14887502e928c8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 17 Dec 2025 15:26:46 +0800 Subject: [PATCH 07/81] wifi: rtw89: correct use sequence of driver_data in skb->info As ieee80211_tx_info is used to assist filling TX descriptor, and layout of IEEE80211_SKB_CB(skb)->driver_data (accessing by RTW89_TX_SKB_CB()) is union, so driver_data must be used by/after rtw89_hci_tx_write() or just before calling rtw89_hci_tx_write(). Otherwise, ieee80211_tx_info::control data is overwritten. Found this by using injected packets which uses ieee80211_tx_info::control, but always sending incorrect data rate. Cc: Fedor Pchelkin Fixes: d5da3d9fb05f ("wifi: rtw89: process TX wait skbs for USB via C2H handler") Signed-off-by: Ping-Ke Shih Tested-by: Fedor Pchelkin Link: https://patch.msgid.link/20251217072646.43209-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 6 ++++-- drivers/net/wireless/realtek/rtw89/core.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 0824940c91ae..53d32f3137eb 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1207,7 +1207,7 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, if (addr_cam->valid && desc_info->mlo) upd_wlan_hdr = true; - if (rtw89_is_tx_rpt_skb(rtwdev, tx_req->skb)) + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS || tx_req->with_wait) rtw89_tx_rpt_init(rtwdev, tx_req); is_bmc = (is_broadcast_ether_addr(hdr->addr1) || @@ -1342,13 +1342,15 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, tx_req.rtwvif_link = rtwvif_link; tx_req.rtwsta_link = rtwsta_link; tx_req.desc_info.sw_mld = sw_mld; - rcu_assign_pointer(skb_data->wait, wait); + tx_req.with_wait = !!wait; rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, true, true); rtw89_wow_parse_akm(rtwdev, skb); rtw89_core_tx_update_desc_info(rtwdev, &tx_req); rtw89_core_tx_wake(rtwdev, &tx_req); + rcu_assign_pointer(skb_data->wait, wait); + ret = rtw89_hci_tx_write(rtwdev, &tx_req); if (ret) { rtw89_err(rtwdev, "failed to transmit skb to HCI\n"); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a9cb47ea0b93..92636cfc5ca5 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1211,6 +1211,8 @@ struct rtw89_core_tx_request { struct rtw89_vif_link *rtwvif_link; struct rtw89_sta_link *rtwsta_link; struct rtw89_tx_desc_info desc_info; + + bool with_wait; }; struct rtw89_txq { From af04c1e8e7a92540ba8649c815c6f35b5a424616 Mon Sep 17 00:00:00 2001 From: Rohit Chourasia Date: Thu, 11 Dec 2025 21:49:11 +0530 Subject: [PATCH 08/81] wifi: rtlwifi: fix typo 'received' in comment Fix typo received -> received by review. Signed-off-by: Rohit Chourasia Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251211161911.30611-1-chourasiarohit27@gmail.com --- drivers/net/wireless/realtek/rtlwifi/regd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c index 0bc4afa4fda3..fd967006b3e1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/regd.c +++ b/drivers/net/wireless/realtek/rtlwifi/regd.c @@ -206,7 +206,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, } /* - *If a country IE has been recieved check its rule for this + *If a country IE has been received check its rule for this *channel first before enabling active scan. The passive scan *would have been enforced by the initial processing of our *custom regulatory domain. From 6b31738043477c1c5d8461921710bb34a865d5aa Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Tue, 23 Dec 2025 11:06:40 +0800 Subject: [PATCH 09/81] wifi: rtw89: 8852b: increase beacon loss to 6 seconds Intermittent beacon loss from a specific AP can lead to disconnections. Increasing the beacon loss threshold helps stabilize the connection. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-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 7b9d9989e517..0f278476d55b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -837,6 +837,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 7, BEACON_FILTER), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 15, BEACON_LOSS_COUNT_V1), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1), From fdbff298742e5045a23a10595fca3c8c15cf90a0 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Tue, 23 Dec 2025 11:06:41 +0800 Subject: [PATCH 10/81] wifi: rtw89: mlo: fix missing TX null-data 1 during link switch Fix missing null-data 1 when switching links. The FW should send a null-data 1 to notify AP before disabling the old link. Adjust the position of the H2C rtw89_fw_h2c_mlo_link_cfg to ensure proper FW behavior during link transition. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac80211.c | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index f39ca1c2ed10..e4fc513aa158 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -1612,12 +1612,23 @@ static int __rtw89_ops_set_vif_links(struct rtw89_dev *rtwdev, return 0; } -static void rtw89_vif_cfg_fw_links(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - unsigned long links, bool en) +static void rtw89_vif_update_fw_links(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + u16 current_links, bool en) { + struct rtw89_vif_ml_trans *trans = &rtwvif->ml_trans; struct rtw89_vif_link *rtwvif_link; unsigned int link_id; + unsigned long links; + + /* Do follow-up when all updating links exist. */ + if (current_links != trans->mediate_links) + return; + + if (en) + links = trans->links_to_add; + else + links = trans->links_to_del; for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { rtwvif_link = rtwvif->links[link_id]; @@ -1628,20 +1639,6 @@ static void rtw89_vif_cfg_fw_links(struct rtw89_dev *rtwdev, } } -static void rtw89_vif_update_fw_links(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - u16 current_links) -{ - struct rtw89_vif_ml_trans *trans = &rtwvif->ml_trans; - - /* Do follow-up when all updating links exist. */ - if (current_links != trans->mediate_links) - return; - - rtw89_vif_cfg_fw_links(rtwdev, rtwvif, trans->links_to_del, false); - rtw89_vif_cfg_fw_links(rtwdev, rtwvif, trans->links_to_add, true); -} - static int rtw89_ops_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1683,7 +1680,7 @@ int rtw89_ops_change_vif_links(struct ieee80211_hw *hw, if (rtwdev->scanning) rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); - rtw89_vif_update_fw_links(rtwdev, rtwvif, old_links); + rtw89_vif_update_fw_links(rtwdev, rtwvif, old_links, true); if (!old_links) __rtw89_ops_clr_vif_links(rtwdev, rtwvif, @@ -1716,6 +1713,9 @@ int rtw89_ops_change_vif_links(struct ieee80211_hw *hw, BIT(RTW89_VIF_IDLE_LINK_ID)); } + if (!ret) + rtw89_vif_update_fw_links(rtwdev, rtwvif, new_links, false); + rtw89_enter_ips_by_hwflags(rtwdev); return ret; } From de1ba591d9311e84bb969cd47414dca66a94557a Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Tue, 23 Dec 2025 11:06:42 +0800 Subject: [PATCH 11/81] wifi: rtw89: mlo: fix incorrect link address in management frames Deauth frames used wrong link address after switching from default link to another, causing AP to reject subsequent auth frames. This affected not only deauth but all management frames. Fixed by setting correct mac_id to let header conversion references correct address CAM. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 53d32f3137eb..d07dc97e22d4 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -548,7 +548,7 @@ rtw89_core_get_tx_type(struct rtw89_dev *rtwdev, struct ieee80211_hdr *hdr = (void *)skb->data; __le16 fc = hdr->frame_control; - if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) + if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) return RTW89_CORE_TX_TYPE_MGMT; return RTW89_CORE_TX_TYPE_DATA; @@ -833,6 +833,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, desc_info->qsel = qsel; desc_info->ch_dma = ch_dma; + desc_info->sw_mld = true; desc_info->port = desc_info->hiq ? rtwvif_link->port : 0; desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); desc_info->hw_ssn_sel = RTW89_MGMT_HW_SSN_SEL; @@ -1051,6 +1052,7 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, desc_info->ch_dma = ch_dma; desc_info->tid_indicate = tid_indicate; desc_info->qsel = qsel; + desc_info->sw_mld = false; desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); desc_info->port = desc_info->hiq ? rtwvif_link->port : 0; desc_info->er_cap = rtwsta_link ? rtwsta_link->er_cap : false; @@ -1326,7 +1328,7 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev, static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, - struct sk_buff *skb, int *qsel, bool sw_mld, + struct sk_buff *skb, int *qsel, struct rtw89_tx_wait_info *wait) { struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link); @@ -1341,7 +1343,6 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, tx_req.sta = sta; tx_req.rtwvif_link = rtwvif_link; tx_req.rtwsta_link = rtwsta_link; - tx_req.desc_info.sw_mld = sw_mld; tx_req.with_wait = !!wait; rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, true, true); @@ -1387,8 +1388,7 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, } } - return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false, - NULL); + return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, NULL); } static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info) @@ -4093,8 +4093,7 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt goto out; } - ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true, - wait); + ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, wait); if (ret) { rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret); dev_kfree_skb_any(skb); From b0f1289fd61763934d8b38f7687178087241cc3e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 23 Dec 2025 11:06:43 +0800 Subject: [PATCH 12/81] wifi: rtw89: mac: reset power state before switching to power on To run power on function properly, reset power states (off/on/PS) to initial state. Otherwise, it might be unusable due to fail to power on. Since a USB adapter might play as USB mass storage with driver and then switch to WiFi adapter, causing it stays on power-on state when doing WiFi USB probe. Exclude this case. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 35 ++++-- drivers/net/wireless/realtek/rtw89/mac.h | 1 + drivers/net/wireless/realtek/rtw89/mac_be.c | 130 ++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 27 ++++ 4 files changed, 186 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index d78fbe73e365..0cea01e322c6 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1478,13 +1478,11 @@ static void rtw89_mac_power_switch_boot_mode(struct rtw89_dev *rtwdev) static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) { -#define PWR_ACT 1 const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_pwr_cfg * const *cfg_seq; int (*cfg_func)(struct rtw89_dev *rtwdev); int ret; - u8 val; rtw89_mac_power_switch_boot_mode(rtwdev); @@ -1499,10 +1497,10 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) __rtw89_leave_ps_mode(rtwdev); - val = rtw89_read32_mask(rtwdev, R_AX_IC_PWR_STATE, B_AX_WLMAC_PWR_STE_MASK); - if (on && val == PWR_ACT) { - rtw89_err(rtwdev, "MAC has already powered on\n"); - return -EBUSY; + if (on) { + ret = mac->reset_pwr_state(rtwdev); + if (ret) + return ret; } ret = cfg_func ? cfg_func(rtwdev) : rtw89_mac_pwr_seq(rtwdev, cfg_seq); @@ -1529,7 +1527,6 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) } return 0; -#undef PWR_ACT } int rtw89_mac_pwr_on(struct rtw89_dev *rtwdev) @@ -3931,6 +3928,29 @@ static int rtw89_mac_feat_init(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_mac_reset_pwr_state_ax(struct rtw89_dev *rtwdev) +{ + u8 val; + + val = rtw89_read32_mask(rtwdev, R_AX_IC_PWR_STATE, B_AX_WLMAC_PWR_STE_MASK); + if (val == MAC_AX_MAC_ON) { + /* + * A USB adapter might play as USB mass storage with driver and + * then switch to WiFi adapter, causing it stays on power-on + * state when doing WiFi USB probe. Return EAGAIN to caller to + * power-off and power-on again to reset the state. + */ + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB && + !test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) + return -EAGAIN; + + rtw89_err(rtwdev, "MAC has already powered on\n"); + return -EBUSY; + } + + return 0; +} + static void rtw89_disable_fw_watchdog(struct rtw89_dev *rtwdev) { u32 val32; @@ -7206,6 +7226,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .set_cpuio = set_cpuio_ax, .dle_quota_change = dle_quota_change_ax, + .reset_pwr_state = rtw89_mac_reset_pwr_state_ax, .disable_cpu = rtw89_mac_disable_cpu_ax, .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax, .fwdl_get_status = rtw89_fw_get_rdy_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 0007229d6753..9ec70729e9e1 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1052,6 +1052,7 @@ struct rtw89_mac_gen_def { struct rtw89_cpuio_ctrl *ctrl_para, bool wd); int (*dle_quota_change)(struct rtw89_dev *rtwdev, bool band1_en); + int (*reset_pwr_state)(struct rtw89_dev *rtwdev); void (*disable_cpu)(struct rtw89_dev *rtwdev); int (*fwdl_enable_wcpu)(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw, bool include_bb); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 556e5f98e8d4..65c0c0de3a30 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -425,6 +425,135 @@ int rtw89_mac_read_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 *val) return 0; } +static int rtw89_mac_reset_pwr_state_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + int ret; + + val32 = rtw89_read32(rtwdev, R_BE_SYSON_FSM_MON); + val32 &= WLAN_FSM_MASK; + val32 |= WLAN_FSM_SET; + rtw89_write32(rtwdev, R_BE_SYSON_FSM_MON, val32); + + ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == WLAN_FSM_IDLE, + 1000, 2000000, false, + rtwdev, R_BE_SYSON_FSM_MON, WLAN_FSM_STATE_MASK); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling WLAN PMC timeout= %X\n", val32); + return ret; + } + + val32 = rtw89_read32_mask(rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK); + if (val32 == MAC_AX_MAC_OFF) { + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, + B_BE_HAXIDMA_IO_ST | B_BE_HAXIDMA_BACKUP_RESTORE_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling HAXI IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling WLAN IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS); + } else if (val32 == MAC_AX_MAC_ON) { + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, + B_BE_HAXIDMA_IO_ST | B_BE_HAXIDMA_BACKUP_RESTORE_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling HAXI IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling WLAN IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC); + + ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == MAC_AX_MAC_OFF, + 1000, 2000000, false, + rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling MAC state timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS); + } else if (val32 == MAC_AX_MAC_LPS) { + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, + B_BE_HAXIDMA_IO_ST | B_BE_HAXIDMA_BACKUP_RESTORE_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling HAXI IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling WLAN IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_set(rtwdev, R_BE_WLLPS_CTRL, B_BE_FORCE_LEAVE_LPS); + + ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == MAC_AX_MAC_ON, + 1000, 2000000, false, + rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling MAC STS timeout= %X\n", val32); + return ret; + } + + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC); + + ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == MAC_AX_MAC_OFF, + 1000, 2000000, false, + rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling MAC state timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_WLLPS_CTRL, B_BE_FORCE_LEAVE_LPS); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS); + } + + return 0; +} + static void rtw89_mac_disable_cpu_be(struct rtw89_dev *rtwdev) { u32 val32; @@ -2623,6 +2752,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .set_cpuio = set_cpuio_be, .dle_quota_change = dle_quota_change_be, + .reset_pwr_state = rtw89_mac_reset_pwr_state_be, .disable_cpu = rtw89_mac_disable_cpu_be, .fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be, .fwdl_get_status = fwdl_get_status_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 5b4a459cf29c..fb641cefa4c9 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -149,6 +149,7 @@ #define R_AX_WLLPS_CTRL 0x0090 #define B_AX_LPSOP_ASWRM BIT(17) #define B_AX_LPSOP_DSWRM BIT(9) +#define B_AX_FORCE_LEAVE_LPS BIT(3) #define B_AX_DIS_WLBT_LPSEN_LOPC BIT(1) #define SW_LPS_OPTION 0x0001A0B2 @@ -313,6 +314,9 @@ #define R_AX_IC_PWR_STATE 0x03F0 #define B_AX_WHOLE_SYS_PWR_STE_MASK GENMASK(25, 16) #define B_AX_WLMAC_PWR_STE_MASK GENMASK(9, 8) +#define MAC_AX_MAC_OFF 0 +#define MAC_AX_MAC_ON 1 +#define MAC_AX_MAC_LPS 2 #define B_AX_UART_HCISYS_PWR_STE_MASK GENMASK(7, 6) #define B_AX_SDIO_HCISYS_PWR_STE_MASK GENMASK(5, 4) #define B_AX_USB_HCISYS_PWR_STE_MASK GENMASK(3, 2) @@ -2094,6 +2098,7 @@ #define B_AX_B1_ISR_ERR_USRCTL_REINIT BIT(0) #define R_AX_AFE_CTRL1 0x0024 +#define B_AX_CMAC_CLK_SEL BIT(21) #define B_AX_R_SYM_WLCMAC1_P4_PC_EN BIT(4) #define B_AX_R_SYM_WLCMAC1_P3_PC_EN BIT(3) @@ -2107,6 +2112,12 @@ #define B_AX_R_SYM_FEN_WLBBFUN_1 BIT(16) #define B_AX_R_SYM_ISO_CMAC12PP BIT(5) +#define R_AX_SYSON_FSM_MON 0x00A0 +#define B_AX_FSM_MON_SEL_MASK GENMASK(26, 24) +#define B_AX_DOP_ELDO BIT(23) +#define B_AX_FSM_MON_UPD BIT(15) +#define B_AX_FSM_PAR_MASK GENMASK(14, 0) + #define R_AX_CMAC_REG_START 0xC000 #define R_AX_CMAC_FUNC_EN 0xC000 @@ -4172,6 +4183,22 @@ #define B_BE_LPSROP_LOWPWRPLL BIT(7) #define B_BE_LPSROP_DSWRSD_SEL_MASK GENMASK(5, 4) +#define R_BE_SYSON_FSM_MON 0x00A0 +#define B_BE_FSM_MON_SEL_MASK GENMASK(26, 24) +#define B_BE_DOP_ELDO BIT(23) +#define B_BE_AFE_PLL_BYPASS BIT(22) +#define B_BE_PON_SWR_BYPASS BIT(21) +#define B_BE_PON_ADIE_BYPASS BIT(20) +#define B_BE_AFE_LS_BYPASS BIT(19) +#define B_BE_BTPMC_XTAL_SI_BYPASS BIT(17) +#define B_BE_WLPMC_XTAL_SI_BYPASS BIT(16) +#define B_BE_FSM_MON_UPD BIT(15) +#define B_BE_FSM_PAR_MASK GENMASK(14, 0) +#define WLAN_FSM_MASK 0xFFFFFF +#define WLAN_FSM_SET 0x4000000 +#define WLAN_FSM_STATE_MASK 0x1FF +#define WLAN_FSM_IDLE 0 + #define R_BE_EFUSE_CTRL_2_V1 0x00A4 #define B_BE_EF_ENT BIT(31) #define B_BE_EF_TCOLUMN_EN BIT(29) From f4de946bdb379f543e3a599f8f048d741ad4a58e Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 23 Dec 2025 11:06:44 +0800 Subject: [PATCH 13/81] wifi: rtw89: ser: enable error IMR after recovering from L1 After recovering from L1, explicitly enable error IMR to ensure next L1 SER (system error recovery) can work normally. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 1 + drivers/net/wireless/realtek/rtw89/mac.h | 1 + drivers/net/wireless/realtek/rtw89/mac_be.c | 1 + drivers/net/wireless/realtek/rtw89/ser.c | 10 ++++++++++ 4 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 0cea01e322c6..acd95d55ae27 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -7204,6 +7204,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .check_mac_en = rtw89_mac_check_mac_en_ax, .sys_init = sys_init_ax, .trx_init = trx_init_ax, + .err_imr_ctrl = err_imr_ctrl_ax, .hci_func_en = rtw89_mac_hci_func_en_ax, .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_ax, .dle_func_en = dle_func_en_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 9ec70729e9e1..9941d500bc68 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1019,6 +1019,7 @@ struct rtw89_mac_gen_def { enum rtw89_mac_hwmod_sel sel); int (*sys_init)(struct rtw89_dev *rtwdev); int (*trx_init)(struct rtw89_dev *rtwdev); + void (*err_imr_ctrl)(struct rtw89_dev *rtwdev, bool en); void (*hci_func_en)(struct rtw89_dev *rtwdev); void (*dmac_func_pre_en)(struct rtw89_dev *rtwdev); void (*dle_func_en)(struct rtw89_dev *rtwdev, bool enable); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 65c0c0de3a30..2bc329c13443 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2730,6 +2730,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .check_mac_en = rtw89_mac_check_mac_en_be, .sys_init = sys_init_be, .trx_init = trx_init_be, + .err_imr_ctrl = err_imr_ctrl_be, .hci_func_en = rtw89_mac_hci_func_en_be, .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_be, .dle_func_en = dle_func_en_be, diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index f99e179f7ff9..7fdc69578da3 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -431,6 +431,14 @@ static void hal_send_m4_event(struct rtw89_ser *ser) rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_RCVY_EN); } +static void hal_enable_err_imr(struct rtw89_ser *ser) +{ + struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + mac->err_imr_ctrl(rtwdev, true); +} + /* state handler */ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) { @@ -552,6 +560,8 @@ static void ser_do_hci_st_hdl(struct rtw89_ser *ser, u8 evt) break; case SER_EV_MAC_RESET_DONE: + hal_enable_err_imr(ser); + ser_state_goto(ser, SER_IDLE_ST); break; From 44ec302e029d82fbe4b28a659eff00fd5ad6f502 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 23 Dec 2025 11:06:45 +0800 Subject: [PATCH 14/81] wifi: rtw89: ser: L1 skip polling status if FW runs event mode Originally, polling FW status was required during recovering from L1. Now, because newer FW support event mode, the polling can be skipped. Add a FW feature flag and configure the supported chips. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 4 ++++ drivers/net/wireless/realtek/rtw89/mac.c | 11 +++++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 92636cfc5ca5..4c35b968ac36 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4682,6 +4682,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_LPS_DACK_BY_C2H_REG, RTW89_FW_FEATURE_BEACON_TRACKING, RTW89_FW_FEATURE_ADDR_CAM_V0, + RTW89_FW_FEATURE_SER_L1_BY_EVENT, }; struct rtw89_fw_suit { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 0f278476d55b..7150892a6274 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -826,6 +826,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER_TYPE_0), + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 127, 0, SER_L1_BY_EVENT), __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), @@ -840,6 +841,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 15, BEACON_LOSS_COUNT_V1), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, SER_L1_BY_EVENT), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, BEACON_TRACKING), @@ -852,6 +854,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SER_L1_BY_EVENT), __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), @@ -863,6 +866,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 129, 1, BEACON_TRACKING), + __CFG_FW_FEAT(RTL8852C, ge, 0, 29, 94, 0, SER_L1_BY_EVENT), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index acd95d55ae27..637fbf15a850 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -848,6 +848,7 @@ EXPORT_SYMBOL(rtw89_mac_get_err_status); int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err) { struct rtw89_ser *ser = &rtwdev->ser; + bool ser_l1_hdl = false; u32 halt; int ret = 0; @@ -856,6 +857,12 @@ int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err) return -EINVAL; } + if (err == MAC_AX_ERR_L1_DISABLE_EN || err == MAC_AX_ERR_L1_RCVY_EN) + ser_l1_hdl = true; + + if (RTW89_CHK_FW_FEATURE(SER_L1_BY_EVENT, &rtwdev->fw) && ser_l1_hdl) + goto set; + ret = read_poll_timeout(rtw89_read32, halt, (halt == 0x0), 1000, 100000, false, rtwdev, R_AX_HALT_H2C_CTRL); if (ret) { @@ -863,10 +870,10 @@ int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err) return -EFAULT; } +set: rtw89_write32(rtwdev, R_AX_HALT_H2C, err); - if (ser->prehandle_l1 && - (err == MAC_AX_ERR_L1_DISABLE_EN || err == MAC_AX_ERR_L1_RCVY_EN)) + if (ser->prehandle_l1 && ser_l1_hdl) return 0; rtw89_write32(rtwdev, R_AX_HALT_H2C_CTRL, B_AX_HALT_H2C_TRIGGER); From 2ac399c5f54a41d7c6b2c8cc6cb283f743acb0be Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 23 Dec 2025 11:06:46 +0800 Subject: [PATCH 15/81] wifi: rtw89: debug: add ser_counters dbgfs Dump counters of SER (system error recoery) L0/L1 related cases. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/debug.c | 57 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 5 +- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 1264c2f82600..0d9a158f6df1 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -79,6 +79,7 @@ struct rtw89_debugfs { struct rtw89_debugfs_priv send_h2c; struct rtw89_debugfs_priv early_h2c; struct rtw89_debugfs_priv fw_crash; + struct rtw89_debugfs_priv ser_counters; struct rtw89_debugfs_priv btc_info; struct rtw89_debugfs_priv btc_manual; struct rtw89_debugfs_priv fw_log_manual; @@ -3680,6 +3681,60 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev, return count; } +struct rtw89_dbg_ser_counters { + unsigned int l0; + unsigned int l1; + unsigned int l0_to_l1; +}; + +static void rtw89_dbg_get_ser_counters_ax(struct rtw89_dev *rtwdev, + struct rtw89_dbg_ser_counters *cnt) +{ + const u32 val = rtw89_read32(rtwdev, R_AX_SER_DBG_INFO); + + cnt->l0 = u32_get_bits(val, B_AX_SER_L0_COUNTER_MASK); + cnt->l1 = u32_get_bits(val, B_AX_SER_L1_COUNTER_MASK); + cnt->l0_to_l1 = u32_get_bits(val, B_AX_L0_TO_L1_EVENT_MASK); +} + +static void rtw89_dbg_get_ser_counters_be(struct rtw89_dev *rtwdev, + struct rtw89_dbg_ser_counters *cnt) +{ + const u32 val = rtw89_read32(rtwdev, R_BE_SER_DBG_INFO); + + cnt->l0 = u32_get_bits(val, B_BE_SER_L0_COUNTER_MASK); + cnt->l1 = u32_get_bits(val, B_BE_SER_L1_COUNTER_MASK); + cnt->l0_to_l1 = u32_get_bits(val, B_BE_SER_L0_PROMOTE_L1_EVENT_MASK); +} + +static ssize_t rtw89_debug_priv_ser_counters_get(struct rtw89_dev *rtwdev, + struct rtw89_debugfs_priv *debugfs_priv, + char *buf, size_t bufsz) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_dbg_ser_counters cnt = {}; + char *p = buf, *end = buf + bufsz; + + rtw89_leave_ps_mode(rtwdev); + + switch (chip->chip_gen) { + case RTW89_CHIP_AX: + rtw89_dbg_get_ser_counters_ax(rtwdev, &cnt); + break; + case RTW89_CHIP_BE: + rtw89_dbg_get_ser_counters_be(rtwdev, &cnt); + break; + default: + return -EOPNOTSUPP; + } + + p += scnprintf(p, end - p, "SER L0 Count: %d\n", cnt.l0); + p += scnprintf(p, end - p, "SER L1 Count: %d\n", cnt.l1); + p += scnprintf(p, end - p, "SER L0 promote event: %d\n", cnt.l0_to_l1); + + return p - buf; +} + static ssize_t rtw89_debug_priv_btc_info_get(struct rtw89_dev *rtwdev, struct rtw89_debugfs_priv *debugfs_priv, char *buf, size_t bufsz) @@ -4767,6 +4822,7 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = { .send_h2c = rtw89_debug_priv_set(send_h2c), .early_h2c = rtw89_debug_priv_set_and_get(early_h2c, RWLOCK), .fw_crash = rtw89_debug_priv_set_and_get(fw_crash, WLOCK), + .ser_counters = rtw89_debug_priv_get(ser_counters, RLOCK), .btc_info = rtw89_debug_priv_get(btc_info, RSIZE_12K), .btc_manual = rtw89_debug_priv_set(btc_manual), .fw_log_manual = rtw89_debug_priv_set(fw_log_manual, WLOCK), @@ -4814,6 +4870,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top rtw89_debugfs_add_w(send_h2c); rtw89_debugfs_add_rw(early_h2c); rtw89_debugfs_add_rw(fw_crash); + rtw89_debugfs_add_r(ser_counters); rtw89_debugfs_add_r(btc_info); rtw89_debugfs_add_w(btc_manual); rtw89_debugfs_add_w(fw_log_manual); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index fb641cefa4c9..28ceab7726c6 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -607,6 +607,9 @@ #define R_AX_SER_DBG_INFO 0x8424 #define B_AX_L0_TO_L1_EVENT_MASK GENMASK(31, 28) +#define B_AX_SER_L1_COUNTER_MASK GENMASK(27, 24) +#define B_AX_RMAC_PPDU_HANG_CNT_MASK GENMASK(23, 16) +#define B_AX_SER_L0_COUNTER_MASK GENMASK(7, 0) #define R_AX_DLE_EMPTY0 0x8430 #define B_AX_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26) @@ -4731,7 +4734,7 @@ #define B_BE_SER_L0_PROMOTE_L1_EVENT_MASK GENMASK(31, 28) #define B_BE_SER_L1_COUNTER_MASK GENMASK(27, 24) #define B_BE_RMAC_PPDU_HANG_CNT_MASK GENMASK(23, 16) -#define B_BE_SER_L0_COUNTER_MASK GENMASK(8, 0) +#define B_BE_SER_L0_COUNTER_MASK GENMASK(7, 0) #define R_BE_DMAC_SYS_CR32B 0x842C #define B_BE_DMAC_BB_PHY1_MASK GENMASK(31, 16) From 0ca9cb5b8dd287cf5520e1b20e2c95006d856e78 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 23 Dec 2025 11:06:47 +0800 Subject: [PATCH 16/81] wifi: rtw89: debug: support SER L0/L1 simulation via halt H2C Original methods of SER (system error recovery) L0/L1 simulations need to leave PS mode before working. Introduce new methods to simulate SER L0/L1 and they can work under PS. Since new methods require FW support, so add a FW feature flag and configure the supported chips. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/debug.c | 22 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.c | 4 ++++ drivers/net/wireless/realtek/rtw89/mac.h | 3 +++ 4 files changed, 30 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 4c35b968ac36..64e7b241074b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4683,6 +4683,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_BEACON_TRACKING, RTW89_FW_FEATURE_ADDR_CAM_V0, RTW89_FW_FEATURE_SER_L1_BY_EVENT, + RTW89_FW_FEATURE_SIM_SER_L0L1_BY_HALT_H2C, }; struct rtw89_fw_suit { diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 0d9a158f6df1..2b48ccea27fb 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3538,6 +3538,14 @@ rtw89_debug_priv_early_h2c_set(struct rtw89_dev *rtwdev, return count; } +static int rtw89_dbg_trigger_ctrl_error_by_halt_h2c(struct rtw89_dev *rtwdev) +{ + if (!test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) + return -EBUSY; + + return rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_RESET_FORCE); +} + static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -3545,6 +3553,9 @@ static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev) u16 pkt_id; int ret; + if (RTW89_CHK_FW_FEATURE(SIM_SER_L0L1_BY_HALT_H2C, &rtwdev->fw)) + return rtw89_dbg_trigger_ctrl_error_by_halt_h2c(rtwdev); + rtw89_leave_ps_mode(rtwdev); ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id); @@ -3601,10 +3612,21 @@ static int rtw89_dbg_trigger_mac_error_be(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_dbg_trigger_mac_error_by_halt_h2c(struct rtw89_dev *rtwdev) +{ + if (!test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) + return -EBUSY; + + return rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L0_RESET_FORCE); +} + static int rtw89_dbg_trigger_mac_error(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + if (RTW89_CHK_FW_FEATURE(SIM_SER_L0L1_BY_HALT_H2C, &rtwdev->fw)) + return rtw89_dbg_trigger_mac_error_by_halt_h2c(rtwdev); + rtw89_leave_ps_mode(rtwdev); switch (chip->chip_gen) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 7150892a6274..4e51ffb5be21 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -827,6 +827,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 127, 0, SER_L1_BY_EVENT), + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), @@ -845,6 +846,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, BEACON_TRACKING), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), @@ -855,6 +857,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SER_L1_BY_EVENT), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), __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), @@ -867,6 +870,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 129, 1, BEACON_TRACKING), __CFG_FW_FEAT(RTL8852C, ge, 0, 29, 94, 0, SER_L1_BY_EVENT), + __CFG_FW_FEAT(RTL8852C, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 9941d500bc68..9d0c491f053f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -914,6 +914,9 @@ enum mac_ax_err_info { MAC_AX_ERR_L0_CFG_DIS_NOTIFY = 0x0011, MAC_AX_ERR_L0_CFG_HANDSHAKE = 0x0012, MAC_AX_ERR_L0_RCVY_EN = 0x0013, + MAC_AX_ERR_L0_RESET_FORCE = 0x0020, + MAC_AX_ERR_L0_RESET_FORCE_C1 = 0x0021, + MAC_AX_ERR_L1_RESET_FORCE = 0x0022, MAC_AX_SET_ERR_MAX, }; From d38289fd1243996f3ed19620bf9a2022aab5af2e Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 23 Dec 2025 11:06:48 +0800 Subject: [PATCH 17/81] wifi: rtw89: refine C2H reg event polling timeout for LPS The each of C2H reg event have different polling timeout. Refine the LPS C2H reg event polling timeout. Otherwise, during SER, the FW has already crashed, the leave LPS check will wait until timeout expires, causing the SER recovery to take too long. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 3 +++ drivers/net/wireless/realtek/rtw89/fw.h | 1 + drivers/net/wireless/realtek/rtw89/ps.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 4e51ffb5be21..fd49e651aeed 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -7053,6 +7053,9 @@ static int rtw89_fw_read_c2h_reg(struct rtw89_dev *rtwdev, else timeout = RTW89_C2H_TIMEOUT; + if (info->timeout) + timeout = info->timeout; + ret = read_poll_timeout_atomic(rtw89_read8, val, val, 1, timeout, false, rtwdev, chip->c2h_ctrl_reg); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index cedb4a47a769..dfae652686cd 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -120,6 +120,7 @@ struct rtw89_h2creg_sch_tx_en { struct rtw89_mac_c2h_info { u8 id; u8 content_len; + u32 timeout; union { u32 c2hreg[RTW89_C2HREG_MAX]; struct rtw89_c2hreg_hdr hdr; diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index 3f69dd4361c3..abd8aee02b47 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -16,7 +16,7 @@ static int rtw89_fw_receive_lps_h2c_check(struct rtw89_dev *rtwdev, u8 macid) { - struct rtw89_mac_c2h_info c2h_info = {}; + struct rtw89_mac_c2h_info c2h_info = {.timeout = 5000}; u16 c2hreg_macid; u32 c2hreg_ret; int ret; From 7b0c36c968369456a0a9ac058d6a01eb135ce45b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 23 Dec 2025 11:06:49 +0800 Subject: [PATCH 18/81] wifi: rtw89: warn unexpected polling value of XTAL SI XTAL SI is an indirect serial interface to access registers in another hardware domain. When BT driver initializes UART interface, firmware might rarely control XTAL SI at the same time causing access racing. Current is to adjust initialization flow to avoid the racing. To make the racing visible if it still presents, add a message to address this. USB adapters might be unplugged suddenly, causing flooding messages. Check RTW89_FLAG_UNPLUGGED flag to avoid them. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 31 +++++++++++++++++++-- drivers/net/wireless/realtek/rtw89/mac_be.c | 13 ++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 637fbf15a850..7cbe3ffd5dc8 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1483,6 +1483,15 @@ static void rtw89_mac_power_switch_boot_mode(struct rtw89_dev *rtwdev) rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); } +static int rtw89_mac_pwr_off_func_for_unplugged(struct rtw89_dev *rtwdev) +{ + /* + * Avoid accessing IO for unplugged power-off to prevent warnings, + * especially XTAL SI. + */ + return 0; +} + static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -1497,8 +1506,13 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) cfg_seq = chip->pwr_on_seq; cfg_func = chip->ops->pwr_on_func; } else { - cfg_seq = chip->pwr_off_seq; - cfg_func = chip->ops->pwr_off_func; + if (test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) { + cfg_seq = NULL; + cfg_func = rtw89_mac_pwr_off_func_for_unplugged; + } else { + cfg_seq = chip->pwr_off_seq; + cfg_func = chip->ops->pwr_off_func; + } } if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) @@ -6969,6 +6983,12 @@ int rtw89_mac_write_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 m return ret; } + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags) && + (u32_get_bits(val32, B_AX_WL_XTAL_SI_ADDR_MASK) != offset || + u32_get_bits(val32, B_AX_WL_XTAL_SI_DATA_MASK) != val)) + rtw89_warn(rtwdev, "xtal si write: offset=%x val=%x poll=%x\n", + offset, val, val32); + return 0; } @@ -6992,7 +7012,12 @@ int rtw89_mac_read_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 *val) return ret; } - *val = rtw89_read8(rtwdev, R_AX_WLAN_XTAL_SI_CTRL + 1); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags) && + u32_get_bits(val32, B_AX_WL_XTAL_SI_ADDR_MASK) != offset) + rtw89_warn(rtwdev, "xtal si read: offset=%x poll=%x\n", + offset, val32); + + *val = u32_get_bits(val32, B_AX_WL_XTAL_SI_DATA_MASK); return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 2bc329c13443..c0204e68c172 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -396,6 +396,12 @@ int rtw89_mac_write_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 m return ret; } + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags) && + (u32_get_bits(val32, B_BE_WL_XTAL_SI_ADDR_MASK) != offset || + u32_get_bits(val32, B_BE_WL_XTAL_SI_DATA_MASK) != val)) + rtw89_warn(rtwdev, "xtal si write: offset=%x val=%x poll=%x\n", + offset, val, val32); + return 0; } @@ -420,7 +426,12 @@ int rtw89_mac_read_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 *val) return ret; } - *val = rtw89_read8(rtwdev, R_BE_WLAN_XTAL_SI_CTRL + 1); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags) && + u32_get_bits(val32, B_BE_WL_XTAL_SI_ADDR_MASK) != offset) + rtw89_warn(rtwdev, "xtal si read: offset=%x poll=%x\n", + offset, val32); + + *val = u32_get_bits(val32, B_BE_WL_XTAL_SI_DATA_MASK); return 0; } From 5e5f83fba48381098b26a8b2513a6d5fc5c66ccb Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 23 Dec 2025 11:06:50 +0800 Subject: [PATCH 19/81] wifi: rtw89: setting TBTT AGG number when mac port initialization When initializing mac port, needs to set TBTT AGG number to trigger TBTT related interrupts. Otherwise, after sending join info H2C command with disconnection mode, firmware will clear TBTT AGG number. Without the setting from mac port initialization after that, this port will not be able to transmit beacons. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 7cbe3ffd5dc8..fae0527e50e8 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4382,6 +4382,7 @@ static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, #define BCN_HOLD_DEF 200 #define BCN_MASK_DEF 0 #define TBTT_ERLY_DEF 5 +#define TBTT_AGG_DEF 1 #define BCN_SET_UNIT 32 #define BCN_ERLY_SET_DLY (10 * 2) @@ -4685,6 +4686,16 @@ static void rtw89_mac_port_cfg_tbtt_early(struct rtw89_dev *rtwdev, B_AX_TBTTERLY_MASK, TBTT_ERLY_DEF); } +static void rtw89_mac_port_cfg_tbtt_agg(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + const struct rtw89_port_reg *p = mac->port_base; + + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_agg, + B_AX_TBTT_AGG_NUM_MASK, TBTT_AGG_DEF); +} + static void rtw89_mac_port_cfg_bss_color(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { @@ -4945,6 +4956,7 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvi rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif_link); rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif_link); rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_tbtt_agg(rtwdev, rtwvif_link); rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif_link); rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif_link); rtw89_mac_port_cfg_func_en(rtwdev, rtwvif_link, true); From 1b40c1c7571fcf926095ed92f25bd87900bdc8ed Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Tue, 23 Dec 2025 11:06:51 +0800 Subject: [PATCH 20/81] wifi: rtw89: mcc: reset probe counter when receiving beacon For BE chips, needs to transmit QoS null data periodically to ensure the connection with AP in GC+STA mode. However, in environments with interference, the Qos null data might fail to transmit successfully. Therefore, when receive the beacon from AP will reset the QoS null data failure counter to avoid unnecessary disconnection. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251223030651.480633-13-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 5 ++++- drivers/net/wireless/realtek/rtw89/mac80211.c | 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 86f1b39a967f..8fe6a7ef738f 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -2608,17 +2608,20 @@ bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role) { + struct rtw89_vif_link *rtwvif_link = role->rtwvif_link; struct ieee80211_vif *vif; bool start_detect; int ret; ret = rtw89_core_send_nullfunc(rtwdev, role->rtwvif_link, true, false, RTW89_MCC_PROBE_TIMEOUT); - if (ret) + if (ret && + READ_ONCE(rtwvif_link->sync_bcn_tsf) == rtwvif_link->last_sync_bcn_tsf) role->probe_count++; else role->probe_count = 0; + rtwvif_link->last_sync_bcn_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf); if (role->probe_count < RTW89_MCC_PROBE_MAX_TRIES) return; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index e4fc513aa158..f80c847d1741 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -127,6 +127,7 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; rtwvif_link->rand_tsf_done = false; rtwvif_link->detect_bcn_count = 0; + rtwvif_link->last_sync_bcn_tsf = 0; rcu_read_lock(); From 3f90942473d25b3743a95b41af2a24a3fc8f9b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Hr=C5=AFza?= Date: Wed, 24 Dec 2025 01:19:00 +0200 Subject: [PATCH 21/81] wifi: rtw88: Increase the RX gain before scanning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver reduces the RX gain while connected to a network located close by. In this condition scans return few results because the more distant networks can't be heard. Temporarily increase the RX gain before scanning in order to detect all available networks. Reset the RX gain back to the last recorded value once the scan finishes. Link: https://github.com/lwfinger/rtw88/issues/337 Signed-off-by: Martin HrĹŻza Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/c2e72aff-190d-4f59-9914-2588de756385@gmail.com --- drivers/net/wireless/realtek/rtw88/main.c | 3 +++ drivers/net/wireless/realtek/rtw88/phy.c | 20 ++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/phy.h | 2 ++ 3 files changed, 25 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 361ce0d40956..dbec7724d6af 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1483,6 +1483,8 @@ void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, set_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); set_bit(RTW_FLAG_SCANNING, rtwdev->flags); + + rtw_phy_dig_set_max_coverage(rtwdev); } void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, @@ -1494,6 +1496,7 @@ void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, if (!rtwvif) return; + rtw_phy_dig_reset(rtwdev); clear_bit(RTW_FLAG_SCANNING, rtwdev->flags); clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 55be0d8e0c28..e2ac5c6fd500 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -370,6 +370,26 @@ static void rtw_phy_statistics(struct rtw_dev *rtwdev) #define DIG_CVRG_MIN 0x1c #define DIG_RSSI_GAIN_OFFSET 15 +void rtw_phy_dig_set_max_coverage(struct rtw_dev *rtwdev) +{ + /* Lower values result in greater coverage. */ + rtw_dbg(rtwdev, RTW_DBG_PHY, "Setting IGI=%#x for max coverage\n", + DIG_CVRG_MIN); + + rtw_phy_dig_write(rtwdev, DIG_CVRG_MIN); +} + +void rtw_phy_dig_reset(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 last_igi; + + last_igi = dm_info->igi_history[0]; + rtw_dbg(rtwdev, RTW_DBG_PHY, "Resetting IGI=%#x\n", last_igi); + + rtw_phy_dig_write(rtwdev, last_igi); +} + static bool rtw_phy_dig_check_damping(struct rtw_dm_info *dm_info) { diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index c9e6b869661d..8449936497bb 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -146,6 +146,8 @@ static inline int rtw_check_supported_rfe(struct rtw_dev *rtwdev) } void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi); +void rtw_phy_dig_reset(struct rtw_dev *rtwdev); +void rtw_phy_dig_set_max_coverage(struct rtw_dev *rtwdev); struct rtw_power_params { u8 pwr_base; From 0177aa828d966117ea30a44f2e1890fdb356118e Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Wed, 24 Dec 2025 01:24:21 +0200 Subject: [PATCH 22/81] wifi: rtw88: Fix alignment fault in rtw_core_enable_beacon() rtw_core_enable_beacon() reads 4 bytes from an address that is not a multiple of 4. This results in a crash on some systems. Do 1 byte reads/writes instead. Unable to handle kernel paging request at virtual address ffff8000827e0522 Mem abort info: ESR = 0x0000000096000021 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x21: alignment fault Data abort info: ISV = 0, ISS = 0x00000021, ISS2 = 0x00000000 CM = 0, WnR = 0, TnD = 0, TagAccess = 0 GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000005492000 [ffff8000827e0522] pgd=0000000000000000, p4d=10000001021d9403, pud=10000001021da403, pmd=100000011061c403, pte=00780000f3200f13 Internal error: Oops: 0000000096000021 [#1] SMP Modules linked in: [...] rtw88_8822ce rtw88_8822c rtw88_pci rtw88_core [...] CPU: 0 UID: 0 PID: 73 Comm: kworker/u32:2 Tainted: G W 6.17.9 #1-NixOS VOLUNTARY Tainted: [W]=WARN Hardware name: FriendlyElec NanoPC-T6 LTS (DT) Workqueue: phy0 rtw_c2h_work [rtw88_core] pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : rtw_pci_read32+0x18/0x40 [rtw88_pci] lr : rtw_core_enable_beacon+0xe0/0x148 [rtw88_core] sp : ffff800080cc3ca0 x29: ffff800080cc3ca0 x28: ffff0001031fc240 x27: ffff000102100828 x26: ffffd2cb7c9b4088 x25: ffff0001031fc2c0 x24: ffff000112fdef00 x23: ffff000112fdef18 x22: ffff000111c29970 x21: 0000000000000001 x20: 0000000000000001 x19: ffff000111c22040 x18: 0000000000000000 x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 x11: 0000000000000000 x10: 0000000000000000 x9 : ffffd2cb6507c090 x8 : 0000000000000000 x7 : 0000000000000000 x6 : 0000000000000000 x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000000 x2 : 0000000000007f10 x1 : 0000000000000522 x0 : ffff8000827e0522 Call trace: rtw_pci_read32+0x18/0x40 [rtw88_pci] (P) rtw_hw_scan_chan_switch+0x124/0x1a8 [rtw88_core] rtw_fw_c2h_cmd_handle+0x254/0x290 [rtw88_core] rtw_c2h_work+0x50/0x98 [rtw88_core] process_one_work+0x178/0x3f8 worker_thread+0x208/0x418 kthread+0x120/0x220 ret_from_fork+0x10/0x20 Code: d28fe202 8b020000 f9524400 8b214000 (b9400000) ---[ end trace 0000000000000000 ]--- Fixes: ad6741b1e044 ("wifi: rtw88: Stop high queue during scan") Cc: stable@vger.kernel.org Closes: https://github.com/lwfinger/rtw88/issues/418 Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/6345300d-8c93-464c-9b05-d0d9af3c97ad@gmail.com --- drivers/net/wireless/realtek/rtw88/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index dbec7724d6af..9470042b12a8 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -2447,10 +2447,10 @@ void rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable) if (enable) { rtw_write32_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); - rtw_write32_clr(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); + rtw_write8_clr(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); } else { rtw_write32_clr(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); - rtw_write32_set(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); + rtw_write8_set(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); } } From 2ba12401cc1f2d970fa2e7d5b15abde3f5abd40d Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Wed, 24 Dec 2025 01:25:32 +0200 Subject: [PATCH 23/81] wifi: rtw88: Use devm_kmemdup() in rtw_set_supported_band() Simplify the code by using device managed memory allocations. This also fixes a memory leak in rtw_register_hw(). The supported bands were not freed in the error path. Copied from commit 145df52a8671 ("wifi: rtw89: Convert rtw89_core_set_supported_band to use devm_*"). Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/1aa7fdef-2d5b-4a31-a4e9-fac8257ed30d@gmail.com --- drivers/net/wireless/realtek/rtw88/main.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 9470042b12a8..46af5bcbb8bc 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1664,11 +1664,13 @@ static u16 rtw_get_max_scan_ie_len(struct rtw_dev *rtwdev) static void rtw_set_supported_band(struct ieee80211_hw *hw, const struct rtw_chip_info *chip) { - struct rtw_dev *rtwdev = hw->priv; struct ieee80211_supported_band *sband; + struct rtw_dev *rtwdev = hw->priv; + struct device *dev = rtwdev->dev; if (chip->band & RTW_BAND_2G) { - sband = kmemdup(&rtw_band_2ghz, sizeof(*sband), GFP_KERNEL); + sband = devm_kmemdup(dev, &rtw_band_2ghz, sizeof(*sband), + GFP_KERNEL); if (!sband) goto err_out; if (chip->ht_supported) @@ -1677,7 +1679,8 @@ static void rtw_set_supported_band(struct ieee80211_hw *hw, } if (chip->band & RTW_BAND_5G) { - sband = kmemdup(&rtw_band_5ghz, sizeof(*sband), GFP_KERNEL); + sband = devm_kmemdup(dev, &rtw_band_5ghz, sizeof(*sband), + GFP_KERNEL); if (!sband) goto err_out; if (chip->ht_supported) @@ -1693,13 +1696,6 @@ static void rtw_set_supported_band(struct ieee80211_hw *hw, rtw_err(rtwdev, "failed to set supported band\n"); } -static void rtw_unset_supported_band(struct ieee80211_hw *hw, - const struct rtw_chip_info *chip) -{ - kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]); - kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]); -} - static void rtw_vif_smps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -2323,10 +2319,7 @@ EXPORT_SYMBOL(rtw_register_hw); void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) { - const struct rtw_chip_info *chip = rtwdev->chip; - ieee80211_unregister_hw(hw); - rtw_unset_supported_band(hw, chip); rtw_debugfs_deinit(rtwdev); rtw_led_deinit(rtwdev); } From fcac0f23d4d20b11014a39f8e2527cdc12ec9c82 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Wed, 24 Dec 2025 01:26:45 +0200 Subject: [PATCH 24/81] wifi: rtw88: Fix inadvertent sharing of struct ieee80211_supported_band data Internally wiphy writes to individual channels in this structure, so we must not share one static definition of channel list between multiple device instances, because that causes hard to debug breakage. For example, with two rtw88 driven devices in the system, channel information may get incoherent, preventing channel use. Copied from commit 0ae36391c804 ("wifi: rtw89: Fix inadverent sharing of struct ieee80211_supported_band data"). Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/e94ad653-2b6d-4284-a33c-8c694f88955b@gmail.com --- drivers/net/wireless/realtek/rtw88/main.c | 34 +++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 46af5bcbb8bc..c4f9758b4e96 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1661,16 +1661,41 @@ static u16 rtw_get_max_scan_ie_len(struct rtw_dev *rtwdev) return len; } +static struct ieee80211_supported_band * +rtw_sband_dup(struct rtw_dev *rtwdev, + const struct ieee80211_supported_band *sband) +{ + struct ieee80211_supported_band *dup; + + dup = devm_kmemdup(rtwdev->dev, sband, sizeof(*sband), GFP_KERNEL); + if (!dup) + return NULL; + + dup->channels = devm_kmemdup_array(rtwdev->dev, sband->channels, + sband->n_channels, + sizeof(*sband->channels), + GFP_KERNEL); + if (!dup->channels) + return NULL; + + dup->bitrates = devm_kmemdup_array(rtwdev->dev, sband->bitrates, + sband->n_bitrates, + sizeof(*sband->bitrates), + GFP_KERNEL); + if (!dup->bitrates) + return NULL; + + return dup; +} + static void rtw_set_supported_band(struct ieee80211_hw *hw, const struct rtw_chip_info *chip) { struct ieee80211_supported_band *sband; struct rtw_dev *rtwdev = hw->priv; - struct device *dev = rtwdev->dev; if (chip->band & RTW_BAND_2G) { - sband = devm_kmemdup(dev, &rtw_band_2ghz, sizeof(*sband), - GFP_KERNEL); + sband = rtw_sband_dup(rtwdev, &rtw_band_2ghz); if (!sband) goto err_out; if (chip->ht_supported) @@ -1679,8 +1704,7 @@ static void rtw_set_supported_band(struct ieee80211_hw *hw, } if (chip->band & RTW_BAND_5G) { - sband = devm_kmemdup(dev, &rtw_band_5ghz, sizeof(*sband), - GFP_KERNEL); + sband = rtw_sband_dup(rtwdev, &rtw_band_5ghz); if (!sband) goto err_out; if (chip->ht_supported) From 86c946bcc00f6390ef65e9614ae60a9377e454f8 Mon Sep 17 00:00:00 2001 From: Ali Tariq Date: Thu, 25 Dec 2025 11:54:29 +0000 Subject: [PATCH 25/81] wifi: rtl8xxxu: fix slab-out-of-bounds in rtl8xxxu_sta_add The driver does not set hw->sta_data_size, which causes mac80211 to allocate insufficient space for driver private station data in __sta_info_alloc(). When rtl8xxxu_sta_add() accesses members of struct rtl8xxxu_sta_info through sta->drv_priv, this results in a slab-out-of-bounds write. KASAN report on RISC-V (VisionFive 2) with RTL8192EU adapter: BUG: KASAN: slab-out-of-bounds in rtl8xxxu_sta_add+0x31c/0x346 Write of size 8 at addr ffffffd6d3e9ae88 by task kworker/u16:0/12 Set hw->sta_data_size to sizeof(struct rtl8xxxu_sta_info) during probe, similar to how hw->vif_data_size is configured. This ensures mac80211 allocates sufficient space for the driver's per-station private data. Tested on StarFive VisionFive 2 v1.2A board. Fixes: eef55f1545c9 ("wifi: rtl8xxxu: support multiple interfaces in {add,remove}_interface()") Cc: stable@vger.kernel.org Signed-off-by: Ali Tariq Reviewed-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251225115430.13011-1-alitariq45892@gmail.com --- drivers/net/wireless/realtek/rtl8xxxu/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index c06ad064f37c..f9a527f6a175 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -7826,6 +7826,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, goto err_set_intfdata; hw->vif_data_size = sizeof(struct rtl8xxxu_vif); + hw->sta_data_size = sizeof(struct rtl8xxxu_sta_info); hw->wiphy->max_scan_ssids = 1; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; From 0b92c2cc4856811eaeeac5fdcbbc7bcd8eb05dc8 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Mon, 29 Dec 2025 11:09:15 +0800 Subject: [PATCH 26/81] wifi: rtw89: wow: use struct style to fill WOW CAM H2C command The WOW CAM H2C command is used to tell firmware the content of pattern match. Use struct instead of macros to fill the data. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 52 +++++++------- drivers/net/wireless/realtek/rtw89/fw.h | 88 +++++++----------------- drivers/net/wireless/realtek/rtw89/wow.c | 4 +- 3 files changed, 53 insertions(+), 91 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index fd49e651aeed..bb6f2802446e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -8717,44 +8717,48 @@ int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, return ret; } -#define H2C_WOW_CAM_UPD_LEN 24 -int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, - struct rtw89_wow_cam_info *cam_info) +int rtw89_fw_h2c_wow_cam_update(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info) { + struct rtw89_h2c_wow_cam_update *h2c; + u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_CAM_UPD_LEN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { - rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); + rtw89_err(rtwdev, "failed to alloc skb for wow cam update\n"); return -ENOMEM; } + skb_put(skb, len); + h2c = (struct rtw89_h2c_wow_cam_update *)skb->data; - skb_put(skb, H2C_WOW_CAM_UPD_LEN); + h2c->w0 = le32_encode_bits(cam_info->r_w, RTW89_H2C_WOW_CAM_UPD_W0_R_W) | + le32_encode_bits(cam_info->idx, RTW89_H2C_WOW_CAM_UPD_W0_IDX); - RTW89_SET_WOW_CAM_UPD_R_W(skb->data, cam_info->r_w); - RTW89_SET_WOW_CAM_UPD_IDX(skb->data, cam_info->idx); - if (cam_info->valid) { - RTW89_SET_WOW_CAM_UPD_WKFM1(skb->data, cam_info->mask[0]); - RTW89_SET_WOW_CAM_UPD_WKFM2(skb->data, cam_info->mask[1]); - RTW89_SET_WOW_CAM_UPD_WKFM3(skb->data, cam_info->mask[2]); - RTW89_SET_WOW_CAM_UPD_WKFM4(skb->data, cam_info->mask[3]); - RTW89_SET_WOW_CAM_UPD_CRC(skb->data, cam_info->crc); - RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(skb->data, - cam_info->negative_pattern_match); - RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(skb->data, - cam_info->skip_mac_hdr); - RTW89_SET_WOW_CAM_UPD_UC(skb->data, cam_info->uc); - RTW89_SET_WOW_CAM_UPD_MC(skb->data, cam_info->mc); - RTW89_SET_WOW_CAM_UPD_BC(skb->data, cam_info->bc); - } - RTW89_SET_WOW_CAM_UPD_VALID(skb->data, cam_info->valid); + if (!cam_info->valid) + goto fill_valid; + + h2c->wkfm0 = le32_encode_bits(cam_info->mask[0], RTW89_H2C_WOW_CAM_UPD_WKFM0); + h2c->wkfm1 = le32_encode_bits(cam_info->mask[1], RTW89_H2C_WOW_CAM_UPD_WKFM1); + h2c->wkfm2 = le32_encode_bits(cam_info->mask[2], RTW89_H2C_WOW_CAM_UPD_WKFM2); + h2c->wkfm3 = le32_encode_bits(cam_info->mask[3], RTW89_H2C_WOW_CAM_UPD_WKFM3); + h2c->w5 = le32_encode_bits(cam_info->crc, RTW89_H2C_WOW_CAM_UPD_W5_CRC) | + le32_encode_bits(cam_info->negative_pattern_match, + RTW89_H2C_WOW_CAM_UPD_W5_NEGATIVE_PATTERN_MATCH) | + le32_encode_bits(cam_info->skip_mac_hdr, + RTW89_H2C_WOW_CAM_UPD_W5_SKIP_MAC_HDR) | + le32_encode_bits(cam_info->uc, RTW89_H2C_WOW_CAM_UPD_W5_UC) | + le32_encode_bits(cam_info->mc, RTW89_H2C_WOW_CAM_UPD_W5_MC) | + le32_encode_bits(cam_info->bc, RTW89_H2C_WOW_CAM_UPD_W5_BC); +fill_valid: + h2c->w5 |= le32_encode_bits(cam_info->valid, RTW89_H2C_WOW_CAM_UPD_W5_VALID); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_WOW, H2C_FUNC_WOW_CAM_UPD, 0, 1, - H2C_WOW_CAM_UPD_LEN); + 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 dfae652686cd..8d8d82b51f43 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2053,70 +2053,28 @@ static inline void RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(void *h2c, u32 val) le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); } -static inline void RTW89_SET_WOW_CAM_UPD_R_W(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(0)); -} +struct rtw89_h2c_wow_cam_update { + __le32 w0; + __le32 wkfm0; + __le32 wkfm1; + __le32 wkfm2; + __le32 wkfm3; + __le32 w5; +} __packed; -static inline void RTW89_SET_WOW_CAM_UPD_IDX(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 1)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_WKFM1(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(31, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_WKFM2(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 2, val, GENMASK(31, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_WKFM3(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 3, val, GENMASK(31, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_WKFM4(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 4, val, GENMASK(31, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_CRC(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, GENMASK(15, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(22)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(23)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_UC(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(24)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_MC(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(25)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_BC(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(26)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_VALID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(31)); -} +#define RTW89_H2C_WOW_CAM_UPD_W0_R_W BIT(0) +#define RTW89_H2C_WOW_CAM_UPD_W0_IDX GENMASK(7, 1) +#define RTW89_H2C_WOW_CAM_UPD_WKFM0 GENMASK(31, 0) +#define RTW89_H2C_WOW_CAM_UPD_WKFM1 GENMASK(31, 0) +#define RTW89_H2C_WOW_CAM_UPD_WKFM2 GENMASK(31, 0) +#define RTW89_H2C_WOW_CAM_UPD_WKFM3 GENMASK(31, 0) +#define RTW89_H2C_WOW_CAM_UPD_W5_CRC GENMASK(15, 0) +#define RTW89_H2C_WOW_CAM_UPD_W5_NEGATIVE_PATTERN_MATCH BIT(22) +#define RTW89_H2C_WOW_CAM_UPD_W5_SKIP_MAC_HDR BIT(23) +#define RTW89_H2C_WOW_CAM_UPD_W5_UC BIT(24) +#define RTW89_H2C_WOW_CAM_UPD_W5_MC BIT(25) +#define RTW89_H2C_WOW_CAM_UPD_W5_BC BIT(26) +#define RTW89_H2C_WOW_CAM_UPD_W5_VALID BIT(31) struct rtw89_h2c_wow_gtk_ofld { __le32 w0; @@ -5055,8 +5013,8 @@ int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtw bool enable); int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); -int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, - struct rtw89_wow_cam_info *cam_info); +int rtw89_fw_h2c_wow_cam_update(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info); int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 46aba4cb2ee9..417720067e78 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -1070,7 +1070,7 @@ static void rtw89_wow_pattern_clear_cam(struct rtw89_dev *rtwdev) for (i = 0; i < rtw_wow->pattern_cnt; i++) { rtw_pattern = &rtw_wow->patterns[i]; rtw_pattern->valid = false; - rtw89_fw_wow_cam_update(rtwdev, rtw_pattern); + rtw89_fw_h2c_wow_cam_update(rtwdev, rtw_pattern); } } @@ -1081,7 +1081,7 @@ static void rtw89_wow_pattern_write(struct rtw89_dev *rtwdev) int i; for (i = 0; i < rtw_wow->pattern_cnt; i++) - rtw89_fw_wow_cam_update(rtwdev, rtw_pattern + i); + rtw89_fw_h2c_wow_cam_update(rtwdev, rtw_pattern + i); } static void rtw89_wow_pattern_clear(struct rtw89_dev *rtwdev) From 355f38849e75618ca764686742bbc56ab65e0846 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 29 Dec 2025 11:09:16 +0800 Subject: [PATCH 27/81] wifi: rtw89: wow: change type of WoWLAN pattern mask to __le32 The WoWLAN pattern mask is generated in byte stream, and actually firmware expects to see the same byte stream too. Since these byte stream is sent to firmware with 32-bit stream in little-endian order. Change to mask to __le32, and just do assignment instead of le32 conversion to wkfm fields of H2C command. For little-endian machine, it doesn't change logic at all. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/fw.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 64e7b241074b..6c4dbab999cd 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5797,7 +5797,7 @@ struct rtw89_phy_efuse_gain { struct rtw89_wow_cam_info { bool r_w; u8 idx; - u32 mask[RTW89_MAX_PATTERN_MASK_SIZE]; + __le32 mask[RTW89_MAX_PATTERN_MASK_SIZE]; u16 crc; bool negative_pattern_match; bool skip_mac_hdr; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index bb6f2802446e..c8ea4a9f24e0 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -8739,10 +8739,10 @@ int rtw89_fw_h2c_wow_cam_update(struct rtw89_dev *rtwdev, if (!cam_info->valid) goto fill_valid; - h2c->wkfm0 = le32_encode_bits(cam_info->mask[0], RTW89_H2C_WOW_CAM_UPD_WKFM0); - h2c->wkfm1 = le32_encode_bits(cam_info->mask[1], RTW89_H2C_WOW_CAM_UPD_WKFM1); - h2c->wkfm2 = le32_encode_bits(cam_info->mask[2], RTW89_H2C_WOW_CAM_UPD_WKFM2); - h2c->wkfm3 = le32_encode_bits(cam_info->mask[3], RTW89_H2C_WOW_CAM_UPD_WKFM3); + h2c->wkfm0 = cam_info->mask[0]; + h2c->wkfm1 = cam_info->mask[1]; + h2c->wkfm2 = cam_info->mask[2]; + h2c->wkfm3 = cam_info->mask[3]; h2c->w5 = le32_encode_bits(cam_info->crc, RTW89_H2C_WOW_CAM_UPD_W5_CRC) | le32_encode_bits(cam_info->negative_pattern_match, RTW89_H2C_WOW_CAM_UPD_W5_NEGATIVE_PATTERN_MATCH) | From 295c47806bc58e6c364790cd780ffa461e1e512b Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Mon, 29 Dec 2025 11:09:17 +0800 Subject: [PATCH 28/81] wifi: rtw89: wow: add WOW_CAM update function for 8922D For WOW_CAM update function, 8922DE use different H2C command from 8922AE. Use chip to distinguish them. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 3 + drivers/net/wireless/realtek/rtw89/fw.c | 59 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 39 ++++++++++++ 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 + drivers/net/wireless/realtek/rtw89/wow.c | 4 +- 10 files changed, 109 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 6c4dbab999cd..5b4f998e1978 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -25,6 +25,7 @@ struct rtw89_fw_txpwr_track_cfg; struct rtw89_phy_rfk_log_fmt; struct rtw89_debugfs; struct rtw89_regd_data; +struct rtw89_wow_cam_info; extern const struct ieee80211_ops rtw89_ops; @@ -3835,6 +3836,8 @@ struct rtw89_chip_ops { struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params); + int (*h2c_wow_cam_update)(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info); void (*btc_set_rfe)(struct rtw89_dev *rtwdev); void (*btc_init_cfg)(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index c8ea4a9f24e0..9b3a9fc7c629 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -8772,6 +8772,65 @@ int rtw89_fw_h2c_wow_cam_update(struct rtw89_dev *rtwdev, return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_wow_cam_update); + +int rtw89_fw_h2c_wow_cam_update_v1(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info) +{ + struct rtw89_h2c_wow_payload_cam_update *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 wow payload cam update\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_wow_payload_cam_update *)skb->data; + + h2c->w0 = le32_encode_bits(cam_info->r_w, RTW89_H2C_WOW_PLD_CAM_UPD_W0_R_W) | + le32_encode_bits(cam_info->idx, RTW89_H2C_WOW_PLD_CAM_UPD_W0_IDX); + h2c->w8 = le32_encode_bits(cam_info->valid, RTW89_H2C_WOW_PLD_CAM_UPD_W8_VALID) | + le32_encode_bits(1, RTW89_H2C_WOW_PLD_CAM_UPD_W8_WOW_PTR); + + if (!cam_info->valid) + goto done; + + h2c->wkfm0 = cam_info->mask[0]; + h2c->wkfm1 = cam_info->mask[1]; + h2c->wkfm2 = cam_info->mask[2]; + h2c->wkfm3 = cam_info->mask[3]; + h2c->w5 = le32_encode_bits(cam_info->uc, RTW89_H2C_WOW_PLD_CAM_UPD_W5_UC) | + le32_encode_bits(cam_info->mc, RTW89_H2C_WOW_PLD_CAM_UPD_W5_MC) | + le32_encode_bits(cam_info->bc, RTW89_H2C_WOW_PLD_CAM_UPD_W5_BC) | + le32_encode_bits(cam_info->skip_mac_hdr, + RTW89_H2C_WOW_PLD_CAM_UPD_W5_SKIP_MAC_HDR); + h2c->w6 = le32_encode_bits(cam_info->crc, RTW89_H2C_WOW_PLD_CAM_UPD_W6_CRC); + h2c->w7 = le32_encode_bits(cam_info->negative_pattern_match, + RTW89_H2C_WOW_PLD_CAM_UPD_W7_NEGATIVE_PATTERN_MATCH); + +done: + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_WOW, + H2C_FUNC_WOW_PLD_CAM_UPD, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_wow_cam_update_v1); int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 8d8d82b51f43..3a72ab3f1895 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2076,6 +2076,33 @@ struct rtw89_h2c_wow_cam_update { #define RTW89_H2C_WOW_CAM_UPD_W5_BC BIT(26) #define RTW89_H2C_WOW_CAM_UPD_W5_VALID BIT(31) +struct rtw89_h2c_wow_payload_cam_update { + __le32 w0; + __le32 wkfm0; + __le32 wkfm1; + __le32 wkfm2; + __le32 wkfm3; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; +} __packed; + +#define RTW89_H2C_WOW_PLD_CAM_UPD_W0_R_W BIT(0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W0_IDX GENMASK(7, 1) +#define RTW89_H2C_WOW_PLD_CAM_UPD_WKFM0 GENMASK(31, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_WKFM1 GENMASK(31, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_WKFM2 GENMASK(31, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_WKFM3 GENMASK(31, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W5_UC BIT(0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W5_MC BIT(1) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W5_BC BIT(2) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W5_SKIP_MAC_HDR BIT(7) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W6_CRC GENMASK(15, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W7_NEGATIVE_PATTERN_MATCH BIT(0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W8_VALID BIT(0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W8_WOW_PTR BIT(1) + struct rtw89_h2c_wow_gtk_ofld { __le32 w0; __le32 w1; @@ -4266,6 +4293,7 @@ enum rtw89_wow_h2c_func { H2C_FUNC_WAKEUP_CTRL = 0x8, H2C_FUNC_WOW_CAM_UPD = 0xC, H2C_FUNC_AOAC_REPORT_REQ = 0xD, + H2C_FUNC_WOW_PLD_CAM_UPD = 0x12, NUM_OF_RTW89_WOW_H2C_FUNC, }; @@ -5015,6 +5043,8 @@ int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_wow_cam_update(struct rtw89_dev *rtwdev, struct rtw89_wow_cam_info *cam_info); +int rtw89_fw_h2c_wow_cam_update_v1(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info); int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); @@ -5178,6 +5208,15 @@ int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, return 0; } +static inline +int rtw89_chip_h2c_wow_cam_update(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_wow_cam_update(rtwdev, cam_info); +} + /* Must consider compatibility; don't insert new in the mid. * Fill each field's default value in rtw89_regd_entcpy(). */ diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 84b628d23882..97254fe638d1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2553,6 +2553,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8851b_btc_set_rfe, .btc_init_cfg = rtw8851b_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 8677723e3561..f44ea4cd4c9e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2247,6 +2247,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8852a_btc_set_rfe, .btc_init_cfg = rtw8852a_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 70fb05bc5e98..b1ea0a6e38c2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -858,6 +858,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8852b_btc_set_rfe, .btc_init_cfg = rtw8852bx_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index f956474c3b72..362d92d86aa1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -724,6 +724,7 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8852bt_btc_set_rfe, .btc_init_cfg = rtw8852bx_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index db99450e9158..bc31f563ad93 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -3088,6 +3088,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8852c_btc_set_rfe, .btc_init_cfg = rtw8852c_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 4bcf20612a45..cfd42b0145d3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2861,6 +2861,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v2, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8922a_btc_set_rfe, .btc_init_cfg = rtw8922a_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 417720067e78..8224f0e3fb9a 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -1070,7 +1070,7 @@ static void rtw89_wow_pattern_clear_cam(struct rtw89_dev *rtwdev) for (i = 0; i < rtw_wow->pattern_cnt; i++) { rtw_pattern = &rtw_wow->patterns[i]; rtw_pattern->valid = false; - rtw89_fw_h2c_wow_cam_update(rtwdev, rtw_pattern); + rtw89_chip_h2c_wow_cam_update(rtwdev, rtw_pattern); } } @@ -1081,7 +1081,7 @@ static void rtw89_wow_pattern_write(struct rtw89_dev *rtwdev) int i; for (i = 0; i < rtw_wow->pattern_cnt; i++) - rtw89_fw_h2c_wow_cam_update(rtwdev, rtw_pattern + i); + rtw89_chip_h2c_wow_cam_update(rtwdev, rtw_pattern + i); } static void rtw89_wow_pattern_clear(struct rtw89_dev *rtwdev) From cfa262efabb7ce9d9f28633efd52115467137a46 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Mon, 29 Dec 2025 11:09:18 +0800 Subject: [PATCH 29/81] wifi: rtw89: wow: abstract DMA check register for RTL8922DE The coming RTL8922DE use different register and its bit to poll if DMA becomes idle before entering WoWLAN. Abstract to share common flow. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci_be.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index e4590879b800..95efb1094b6c 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -184,10 +184,13 @@ static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev) static int rtw89_pci_poll_txdma_ch_idle_be(struct rtw89_dev *rtwdev) { + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 dma_busy1 = info->dma_busy1.addr; + u32 check = info->dma_busy1.mask; u32 val; - return read_poll_timeout(rtw89_read32, val, (val & DMA_BUSY1_CHECK_BE) == 0, - 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1); + return read_poll_timeout(rtw89_read32, val, (val & check) == 0, + 10, 1000, false, rtwdev, dma_busy1); } static int rtw89_pci_poll_rxdma_ch_idle_be(struct rtw89_dev *rtwdev) From 040af1ac8002cff5bddc5ce7e0d3b41bc0db659d Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Mon, 29 Dec 2025 11:09:19 +0800 Subject: [PATCH 30/81] wifi: rtw89: define TX/RX aggregation and MPDU capability per chip Since TX/RX aggregation is different from chip to chip, define individual number according to hardware ability. Also the coming chip RTL8922DE can get expected performance. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 10 +++++----- drivers/net/wireless/realtek/rtw89/core.h | 7 ++++--- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 4 ++++ drivers/net/wireless/realtek/rtw89/rtw8852a.c | 4 ++++ drivers/net/wireless/realtek/rtw89/rtw8852b.c | 4 ++++ drivers/net/wireless/realtek/rtw89/rtw8852bt.c | 4 ++++ drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 ++++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 4 ++++ 8 files changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index d07dc97e22d4..51aa3d0eb2ef 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -5086,7 +5086,7 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev, } vht_cap->vht_supported = true; - vht_cap->cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + vht_cap->cap = chip->max_vht_mpdu_cap | IEEE80211_VHT_CAP_SHORT_GI_80 | IEEE80211_VHT_CAP_RXSTBC_1 | IEEE80211_VHT_CAP_HTC_VHT | @@ -5214,7 +5214,7 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | le16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | - le16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + le16_encode_bits(chip->max_vht_mpdu_cap, IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); iftype_data->he_6ghz_capa.capa = capa; } @@ -5252,7 +5252,7 @@ static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev, eht_cap->has_eht = true; eht_cap_elem->mac_cap_info[0] = - u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991, + u8_encode_bits(chip->max_eht_mpdu_cap, IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); eht_cap_elem->mac_cap_info[1] = 0; @@ -6399,8 +6399,8 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) hw->extra_tx_headroom = tx_headroom; hw->queues = IEEE80211_NUM_ACS; - hw->max_rx_aggregation_subframes = RTW89_MAX_RX_AGG_NUM; - hw->max_tx_aggregation_subframes = RTW89_MAX_TX_AGG_NUM; + hw->max_rx_aggregation_subframes = chip->max_rx_agg_num; + hw->max_tx_aggregation_subframes = chip->max_tx_agg_num; hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 5b4f998e1978..8f9c49d2ec5b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3407,9 +3407,6 @@ struct rtw89_ra_info { #define RTW89_PPDU_MAC_RX_CNT_SIZE 96 #define RTW89_PPDU_MAC_RX_CNT_SIZE_V1 128 -#define RTW89_MAX_RX_AGG_NUM 64 -#define RTW89_MAX_TX_AGG_NUM 128 - struct rtw89_ampdu_params { u16 agg_num; bool amsdu; @@ -4429,6 +4426,10 @@ struct rtw89_chip_info { bool small_fifo_size; u32 dle_scc_rsvd_size; u16 max_amsdu_limit; + u16 max_vht_mpdu_cap; + u16 max_eht_mpdu_cap; + u16 max_tx_agg_num; + u16 max_rx_agg_num; bool dis_2g_40m_ul_ofdma; u32 rsvd_ple_ofst; const struct rtw89_hfc_param_ini *hfc_param_ini[RTW89_HCI_TYPE_NUM]; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 97254fe638d1..7e97220b723a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2591,6 +2591,10 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .small_fifo_size = true, .dle_scc_rsvd_size = 98304, .max_amsdu_limit = 3500, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index f44ea4cd4c9e..58e041016c26 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2276,6 +2276,10 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .small_fifo_size = false, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 3500, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = {rtw8852a_hfc_param_ini_pcie, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index b1ea0a6e38c2..f813ec9242eb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -900,6 +900,10 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .small_fifo_size = true, .dle_scc_rsvd_size = 98304, .max_amsdu_limit = 5000, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 362d92d86aa1..534ac137b43f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -766,6 +766,10 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .small_fifo_size = true, .dle_scc_rsvd_size = 98304, .max_amsdu_limit = 5000, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = {rtw8852bt_hfc_param_ini_pcie, NULL, NULL}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index bc31f563ad93..2110c714394d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -3117,6 +3117,10 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .small_fifo_size = false, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 8000, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = {rtw8852c_hfc_param_ini_pcie, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index cfd42b0145d3..0383c3bd60dd 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2890,6 +2890,10 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .small_fifo_size = false, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 8000, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x8f800, .hfc_param_ini = {rtw8922a_hfc_param_ini_pcie, NULL, NULL}, From 9e389ad5d15962636de4e78febf609a954545d49 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 29 Dec 2025 11:09:20 +0800 Subject: [PATCH 31/81] wifi: rtw89: efuse: read hardware version from efuse for WiFi 7 chips Hardware version from efuse prioritizes to the version from register. For WiFi 7 chips, this becomes required, so implement this in common flow. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/efuse.c | 4 --- drivers/net/wireless/realtek/rtw89/efuse.h | 6 +++++ drivers/net/wireless/realtek/rtw89/efuse_be.c | 26 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac.c | 5 +++- drivers/net/wireless/realtek/rtw89/mac.h | 11 ++++++++ drivers/net/wireless/realtek/rtw89/mac_be.c | 1 + 6 files changed, 48 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c index 6c6c763510af..a2757a88d55d 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.c +++ b/drivers/net/wireless/realtek/rtw89/efuse.c @@ -7,10 +7,6 @@ #include "mac.h" #include "reg.h" -#define EF_FV_OFSET 0x5ea -#define EF_CV_MASK GENMASK(7, 4) -#define EF_CV_INV 15 - #define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0) #define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4) #define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0) diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index a96fc1044791..a14a9dfed8e8 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -11,6 +11,11 @@ #define RTW89_EFUSE_BLOCK_SIZE_MASK GENMASK(15, 0) #define RTW89_EFUSE_MAX_BLOCK_SIZE 0x10000 +#define EF_FV_OFSET 0x5EA +#define EF_FV_OFSET_BE_V1 0x17CA +#define EF_CV_MASK GENMASK(7, 4) +#define EF_CV_INV 15 + struct rtw89_efuse_block_cfg { u32 offset; u32 size; @@ -26,5 +31,6 @@ int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv); int rtw89_efuse_recognize_mss_info_v1(struct rtw89_dev *rtwdev, u8 b1, u8 b2); int rtw89_efuse_read_fw_secure_ax(struct rtw89_dev *rtwdev); int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev); +int rtw89_efuse_read_ecv_be(struct rtw89_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw89/efuse_be.c b/drivers/net/wireless/realtek/rtw89/efuse_be.c index 64768923b0f0..70c1b8be662e 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse_be.c +++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c @@ -512,3 +512,29 @@ int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev) return 0; } + +int rtw89_efuse_read_ecv_be(struct rtw89_dev *rtwdev) +{ + u32 dump_addr; + u8 buff[4]; /* efuse access must 4 bytes align */ + int ret; + u8 ecv; + u8 val; + + dump_addr = ALIGN_DOWN(EF_FV_OFSET_BE_V1, 4); + + ret = rtw89_dump_physical_efuse_map_be(rtwdev, buff, dump_addr, 4, false); + if (ret) + return ret; + + val = buff[EF_FV_OFSET_BE_V1 & 0x3]; + + ecv = u8_get_bits(val, EF_CV_MASK); + if (ecv == EF_CV_INV) + return -ENOENT; + + rtwdev->hal.cv = ecv; + + return 0; +} +EXPORT_SYMBOL(rtw89_efuse_read_ecv_be); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index fae0527e50e8..91854ae9a310 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1529,8 +1529,10 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) return ret; if (on) { - if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) + if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) { + rtw89_mac_efuse_read_ecv(rtwdev); mac->efuse_read_fw_secure(rtwdev); + } set_bit(RTW89_FLAG_POWERON, rtwdev->flags); set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); @@ -7281,6 +7283,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .parse_phycap_map = rtw89_parse_phycap_map_ax, .cnv_efuse_state = rtw89_cnv_efuse_state_ax, .efuse_read_fw_secure = rtw89_efuse_read_fw_secure_ax, + .efuse_read_ecv = NULL, .cfg_plt = rtw89_mac_cfg_plt_ax, .get_plt_cnt = rtw89_mac_get_plt_cnt_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 9d0c491f053f..2f3138b155f9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1067,6 +1067,7 @@ struct rtw89_mac_gen_def { int (*parse_phycap_map)(struct rtw89_dev *rtwdev); int (*cnv_efuse_state)(struct rtw89_dev *rtwdev, bool idle); int (*efuse_read_fw_secure)(struct rtw89_dev *rtwdev); + int (*efuse_read_ecv)(struct rtw89_dev *rtwdev); int (*cfg_plt)(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt); u16 (*get_plt_cnt)(struct rtw89_dev *rtwdev, u8 band); @@ -1602,6 +1603,16 @@ int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_rsvd_qt_cfg *cfg); int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable); +static inline int rtw89_mac_efuse_read_ecv(struct rtw89_dev *rtwdev) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + if (!mac->efuse_read_ecv) + return -ENOENT; + + return mac->efuse_read_ecv(rtwdev); +} + static inline void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode) { diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index c0204e68c172..0b29f43b38bd 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2774,6 +2774,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .parse_phycap_map = rtw89_parse_phycap_map_be, .cnv_efuse_state = rtw89_cnv_efuse_state_be, .efuse_read_fw_secure = rtw89_efuse_read_fw_secure_be, + .efuse_read_ecv = rtw89_efuse_read_ecv_be, .cfg_plt = rtw89_mac_cfg_plt_be, .get_plt_cnt = rtw89_mac_get_plt_cnt_be, From d57ec29478d64b191d1dea26f577f9c78920850d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 29 Dec 2025 11:09:21 +0800 Subject: [PATCH 32/81] wifi: rtw89: read chip ID for RTL8922D variants The coming RTL8922D has many kinds of hardware variants. Read chips ID ahead, so we can configure proper hardware settings accordingly. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 27 ++++++++++++++++--- drivers/net/wireless/realtek/rtw89/core.h | 13 +++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 2 ++ drivers/net/wireless/realtek/rtw89/reg.h | 7 +++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 -- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 2 -- .../wireless/realtek/rtw89/rtw8852b_common.c | 2 -- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 -- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 -- 9 files changed, 46 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 51aa3d0eb2ef..78cbfd6677e1 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -6081,7 +6081,9 @@ void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; int ret; + u8 val2; u8 val; u8 cv; @@ -6093,14 +6095,28 @@ static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev) cv = CHIP_CBV; } - rtwdev->hal.cv = cv; + hal->cv = cv; - if (rtw89_is_rtl885xb(rtwdev)) { + if (rtw89_is_rtl885xb(rtwdev) || chip->chip_gen >= RTW89_CHIP_BE) { ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CV, &val); if (ret) return; - rtwdev->hal.acv = u8_get_bits(val, XTAL_SI_ACV_MASK); + hal->acv = u8_get_bits(val, XTAL_SI_ACV_MASK); + } + + if (chip->chip_gen >= RTW89_CHIP_BE) { + hal->cid = + rtw89_read32_mask(rtwdev, R_BE_SYS_CHIPINFO, B_BE_HW_ID_MASK); + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CHIP_ID_L, &val); + if (ret) + return; + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CHIP_ID_H, &val2); + if (ret) + return; + + hal->aid = val | val2 << 8; } } @@ -6310,6 +6326,8 @@ void rtw89_core_rfkill_poll(struct rtw89_dev *rtwdev, bool force) int rtw89_chip_info_setup(struct rtw89_dev *rtwdev) { + struct rtw89_efuse *efuse = &rtwdev->efuse; + struct rtw89_hal *hal = &rtwdev->hal; int ret; rtw89_read_chip_ver(rtwdev); @@ -6349,6 +6367,9 @@ int rtw89_chip_info_setup(struct rtw89_dev *rtwdev) rtw89_core_setup_rfe_parms(rtwdev); rtwdev->ps_mode = rtw89_update_ps_mode(rtwdev); + rtw89_info(rtwdev, "chip info CID: %x, CV: %x, AID: %x, ACV: %x, RFE: %d\n", + hal->cid, hal->cv, hal->aid, hal->acv, efuse->rfe_type); + out: rtw89_mac_pwr_off(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 8f9c49d2ec5b..6e39894990bf 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -159,6 +159,17 @@ enum rtw89_core_chip_id { RTL8922D, }; +enum rtw89_core_chip_cid { + RTL8922D_CID7025 = 0x74, + RTL8922D_CID7090 = 0x79, +}; + +enum rtw89_core_chip_aid { + RTL8922D_AID1348 = 0x1348, + RTL8922D_AID7060 = 0x7060, + RTL8922D_AID7102 = 0x7102, +}; + enum rtw89_chip_gen { RTW89_CHIP_AX, RTW89_CHIP_BE, @@ -5034,7 +5045,9 @@ enum rtw89_dm_type { struct rtw89_hal { u32 rx_fltr; u8 cv; + u8 cid; /* enum rtw89_core_chip_cid */ u8 acv; + u16 aid; /* enum rtw89_core_chip_aid */ u32 antenna_tx; u32 antenna_rx; u8 tx_nss; diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 2f3138b155f9..79755032df2c 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1573,6 +1573,8 @@ enum rtw89_mac_xtal_si_offset { XTAL_SI_APBT = 0xD1, XTAL_SI_PLL = 0xE0, XTAL_SI_PLL_1 = 0xE1, + XTAL_SI_CHIP_ID_L = 0xFD, + XTAL_SI_CHIP_ID_H = 0xFE, }; static inline diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 28ceab7726c6..081623f84dd9 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4267,6 +4267,13 @@ #define R_BE_PCIE_MIO_INTD 0x00E8 #define B_BE_PCIE_MIO_DATA_MASK GENMASK(31, 0) +#define R_BE_SYS_CHIPINFO 0x00FC +#define B_BE_USB2_SEL BIT(31) +#define B_BE_U3PHY_RST_V1 BIT(30) +#define B_BE_U3_TERM_DETECT BIT(29) +#define B_BE_VERIFY_ENV_MASK GENMASK(9, 8) +#define B_BE_HW_ID_MASK GENMASK(7, 0) + #define R_BE_HALT_H2C_CTRL 0x0160 #define B_BE_HALT_H2C_TRIGGER BIT(0) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 7e97220b723a..e3933946d1ca 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -633,8 +633,6 @@ static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, efuse->rfe_type = map->rfe_type; efuse->xtal_cap = map->xtal_k; - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 58e041016c26..46f5e9c50222 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -678,8 +678,6 @@ static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, efuse->rfe_type = map->rfe_type; efuse->xtal_cap = map->xtal_k; - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index 4e72f4961837..65b839323e3e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -265,8 +265,6 @@ static int __rtw8852bx_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, efuse->rfe_type = map->rfe_type; efuse->xtal_cap = map->xtal_k; - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 2110c714394d..c20c732d2f6a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -600,8 +600,6 @@ static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, efuse->rfe_type = map->rfe_type; efuse->xtal_cap = map->xtal_k; - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 0383c3bd60dd..795c00d65d5e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -628,8 +628,6 @@ static int rtw8922a_read_efuse_rf(struct rtw89_dev *rtwdev, u8 *log_map) rtw8922a_efuse_parsing_tssi(rtwdev, map); rtw8922a_efuse_parsing_gain_offset(rtwdev, map); - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } From 8cb147e23712c937820761b4f43f78074b27e6ed Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 29 Dec 2025 11:09:22 +0800 Subject: [PATCH 33/81] wifi: rtw89: add default quirks as features to chip_info The coming chip will support thermal protection by default, so add default quirks to chip_info. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 3 +++ drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/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, 10 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 78cbfd6677e1..e713422ebd7c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -5924,6 +5924,9 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) struct rtw89_btc *btc = &rtwdev->btc; u8 band; + bitmap_or(rtwdev->quirks, rtwdev->quirks, &rtwdev->chip->default_quirks, + NUM_OF_RTW89_QUIRKS); + INIT_LIST_HEAD(&rtwdev->ba_list); INIT_LIST_HEAD(&rtwdev->forbid_ba_list); INIT_LIST_HEAD(&rtwdev->rtwvifs_list); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 6e39894990bf..93b633d39e47 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4559,6 +4559,7 @@ struct rtw89_chip_info { const struct rtw89_edcca_regs *edcca_regs; const struct wiphy_wowlan_support *wowlan_stub; const struct rtw89_xtal_info *xtal_info; + unsigned long default_quirks; /* bitmap of rtw89_quirks */ }; struct rtw89_chip_variant { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index e3933946d1ca..e06e70751735 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2715,6 +2715,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .wowlan_stub = &rtw_wowlan_stub_8851b, #endif .xtal_info = &rtw8851b_xtal_info, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8851b_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 46f5e9c50222..bb12982afef7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2400,6 +2400,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .wowlan_stub = &rtw_wowlan_stub_8852a, #endif .xtal_info = &rtw8852a_xtal_info, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8852a_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index f813ec9242eb..0f18555e619b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -1029,6 +1029,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .wowlan_stub = &rtw_wowlan_stub_8852b, #endif .xtal_info = NULL, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8852b_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 534ac137b43f..7b637483e9b4 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -886,6 +886,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .wowlan_stub = &rtw_wowlan_stub_8852bt, #endif .xtal_info = NULL, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8852bt_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index c20c732d2f6a..a82bbe3ec901 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -3245,6 +3245,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .wowlan_stub = &rtw_wowlan_stub_8852c, #endif .xtal_info = NULL, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8852c_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 795c00d65d5e..041ffec9a327 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -3011,6 +3011,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .wowlan_stub = &rtw_wowlan_stub_8922a, #endif .xtal_info = NULL, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8922a_chip_info); From fe17b1852fdfe5c1cb87d4d39b91f09ace7e18ae Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Mon, 29 Dec 2025 11:09:23 +0800 Subject: [PATCH 34/81] wifi: rtw89: refine TX nulldata judgement when scan with 2 OP channels When scan with 2 OP channels, for the case like not-connect(macid 0) + GO(macid 1) or not-connect(macid 0) + GC(macid 1), the macid 0 doesn't offload NULL data packet to FW. Therefore, refine the NULL data judgement to let interfaces that only connected and non-AP mode need to TX nulldata. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 54 ++++++++++++++++--------- drivers/net/wireless/realtek/rtw89/fw.h | 1 + 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 9b3a9fc7c629..1e22ea51292a 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5944,27 +5944,18 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, u8 scan_offload_ver = U8_MAX; u8 cfg_len = sizeof(*h2c); unsigned int cond; - u8 ap_idx = U8_MAX; u8 ver = U8_MAX; u8 policy_val; void *ptr; + u8 txnull; u8 txbcn; int ret; u32 len; u8 i; - scan_op[0].macid = rtwvif_link->mac_id; - scan_op[0].port = rtwvif_link->port; - scan_op[0].chan = *op; - vif = rtwvif_to_vif(rtwvif_link->rtwvif); - if (vif->type == NL80211_IFTYPE_AP) - ap_idx = 0; - - if (ext->set) { - scan_op[1] = *ext; - vif = rtwvif_to_vif(ext->rtwvif_link->rtwvif); - if (vif->type == NL80211_IFTYPE_AP) - ap_idx = 1; + if (option->num_opch > RTW89_MAX_OP_NUM_BE) { + rtw89_err(rtwdev, "num of scan OP chan %d over limit\n", option->num_opch); + return -ENOENT; } rtw89_scan_get_6g_disabled_chan(rtwdev, option); @@ -6069,11 +6060,29 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, } for (i = 0; i < option->num_opch; i++) { - bool is_ap_idx = i == ap_idx; + struct rtw89_vif_link *rtwvif_link_op; + bool is_ap; - opmode = is_ap_idx ? RTW89_SCAN_OPMODE_TBTT : RTW89_SCAN_OPMODE_INTV; - policy_val = is_ap_idx ? 2 : RTW89_OFF_CHAN_TIME / 10; - txbcn = is_ap_idx ? 1 : 0; + switch (i) { + case 0: + scan_op[0].macid = rtwvif_link->mac_id; + scan_op[0].port = rtwvif_link->port; + scan_op[0].chan = *op; + rtwvif_link_op = rtwvif_link; + break; + case 1: + scan_op[1] = *ext; + rtwvif_link_op = ext->rtwvif_link; + break; + } + + vif = rtwvif_to_vif(rtwvif_link_op->rtwvif); + is_ap = vif->type == NL80211_IFTYPE_AP; + txnull = !is_zero_ether_addr(rtwvif_link_op->bssid) && + vif->type != NL80211_IFTYPE_AP; + opmode = is_ap ? RTW89_SCAN_OPMODE_TBTT : RTW89_SCAN_OPMODE_INTV; + policy_val = is_ap ? 2 : RTW89_OFF_CHAN_TIME / 10; + txbcn = is_ap ? 1 : 0; opch = ptr; opch->w0 = le32_encode_bits(scan_op[i].macid, @@ -6084,7 +6093,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) | le32_encode_bits(opmode, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) | - le32_encode_bits(true, + le32_encode_bits(txnull, RTW89_H2C_SCANOFLD_BE_OPCH_W0_TXNULL) | le32_encode_bits(policy_val, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY_VAL); @@ -7396,6 +7405,7 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_chan *op = &rtwdev->scan_info.op_chan; struct rtw89_pktofld_info *info; + struct ieee80211_vif *vif; u8 band, probe_count = 0; int ret; @@ -7448,7 +7458,9 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, ch_info->pri_ch = op->primary_channel; ch_info->ch_band = op->band_type; ch_info->bw = op->band_width; - ch_info->tx_null = true; + vif = rtwvif_link_to_vif(rtwvif_link); + ch_info->tx_null = !is_zero_ether_addr(rtwvif_link->bssid) && + vif->type != NL80211_IFTYPE_AP; ch_info->num_pkt = 0; break; case RTW89_CHAN_DFS: @@ -7466,7 +7478,9 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, 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; + vif = rtwvif_link_to_vif(ext->rtwvif_link); + ch_info->tx_null = !is_zero_ether_addr(ext->rtwvif_link->bssid) && + vif->type != NL80211_IFTYPE_AP; ch_info->num_pkt = 0; ch_info->macid_tx = true; break; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 3a72ab3f1895..6a297fad148b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2812,6 +2812,7 @@ struct rtw89_h2c_scanofld_be_macc_role { __le32 w0; } __packed; +#define RTW89_MAX_OP_NUM_BE 2 #define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_BAND GENMASK(1, 0) #define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_PORT GENMASK(4, 2) #define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_MACID GENMASK(23, 8) From 9587ffbbd9aaf20463927bac17f41ee21e81c494 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Mon, 29 Dec 2025 11:09:24 +0800 Subject: [PATCH 35/81] wifi: rtw89: 8922a: configure FW version for SCAN_OFFLOAD_EXTRA_OP feature 8922a supports SCAN_OFFLOAD_EXTRA_OP feature. Enable it, FW can do back-op and TX NULL frames on the second connection. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-11-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 1e22ea51292a..40e5d5fab651 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -874,6 +874,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD_EXTRA_OP), __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), From 8c96752d99c0b094af68317a8c701b09bd0862d9 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Mon, 29 Dec 2025 11:09:25 +0800 Subject: [PATCH 36/81] wifi: rtw89: regd: 6 GHz power type marks default when inactive When inactive, 6 GHz power type has been assigned to the default one, but missed to mark the local control variable, dflt, true. Then, this might let some 6 GHz power info of disconnected APs keep being taken into account under certain cases. So, mark default when inactive. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/regd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 209d84909f88..c3425ed44732 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -1142,6 +1142,7 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, } } else { rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + dflt = true; } rcu_read_unlock(); From 6a0b7392a6f5487fb58704926a24b1e2ee2762e9 Mon Sep 17 00:00:00 2001 From: Dian-Syuan Yang Date: Mon, 29 Dec 2025 11:09:26 +0800 Subject: [PATCH 37/81] wifi: rtw89: enhance connection stability when triggering beacon loss If the driver supports ack status reports of TX frames, mac80211 allows it to detect AP if it's alive and determine whether the client can maintain the connection by sending null-data. Therefore, refine the flow to let driver inform mac80211 to enable beacon loss work to track AP's status upon receiving beacon loss event. Signed-off-by: Dian-Syuan Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251229030926.27004-13-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 91854ae9a310..1375ab324a8b 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5253,10 +5253,10 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l if (start_detect) return; - ieee80211_connection_loss(vif); - } else { - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); + ieee80211_beacon_loss(vif); } + + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); return; case RTW89_BCN_FLTR_NOTIFY: nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; From 8c0ac5791eb9a82426ac1f5b6ea7aa1e3f921815 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 31 Dec 2025 17:06:37 +0800 Subject: [PATCH 38/81] wifi: rtw89: rfk: update RFK pre info V2 for RTL8922D The H2C command of RFK pre info is to tell current operating channels to firmware, so RF calibrations can rely on these information as arguments to configure hardware. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 26 +++++++++++++++++++---- drivers/net/wireless/realtek/rtw89/fw.h | 8 ++++++- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 93b633d39e47..b42d3a4df4bf 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4684,6 +4684,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_WOW_REASON_V1, RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V1, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V2, RTW89_FW_FEATURE_RFK_RXDCK_V0, RTW89_FW_FEATURE_RFK_IQK_V0, RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 40e5d5fab651..d05b15ea022a 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -885,6 +885,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 46, 0, NOTIFY_AP_INFO), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 47, 0, CH_INFO_BE_V0), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 49, 0, RFK_PRE_NOTIFY_V1), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 49, 0, RFK_PRE_NOTIFY_V2), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 51, 0, NO_PHYCAP_P1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1), @@ -6368,6 +6369,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rfk_pre_info_common *common; struct rtw89_fw_h2c_rfk_pre_info_v0 *h2c_v0; struct rtw89_fw_h2c_rfk_pre_info_v1 *h2c_v1; + struct rtw89_fw_h2c_rfk_pre_info_v2 *h2c_v2; struct rtw89_fw_h2c_rfk_pre_info *h2c; u8 tbl_sel[NUM_OF_RTW89_FW_RFK_PATH]; u32 len = sizeof(*h2c); @@ -6377,7 +6379,10 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, u32 val32; int ret; - if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V1, &rtwdev->fw)) { + if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V2, &rtwdev->fw)) { + len = sizeof(*h2c_v2); + ver = 2; + } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V1, &rtwdev->fw)) { len = sizeof(*h2c_v1); ver = 1; } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V0, &rtwdev->fw)) { @@ -6391,8 +6396,21 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, return -ENOMEM; } skb_put(skb, len); + + if (ver <= 2) + goto old_format; + h2c = (struct rtw89_fw_h2c_rfk_pre_info *)skb->data; - common = &h2c->base_v1.common; + + h2c->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + h2c->phy_idx = cpu_to_le32(phy_idx); + h2c->mlo_1_1 = cpu_to_le32(rtw89_is_mlo_1_1(rtwdev)); + + goto done; + +old_format: + h2c_v2 = (struct rtw89_fw_h2c_rfk_pre_info_v2 *)skb->data; + common = &h2c_v2->base_v1.common; common->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); @@ -6419,7 +6437,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, if (ver <= 1) continue; - h2c->cur_bandwidth[path] = + h2c_v2->cur_bandwidth[path] = cpu_to_le32(rfk_mcc->data[path].bw[tbl_sel[path]]); } @@ -6450,7 +6468,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, } if (rtw89_is_mlo_1_1(rtwdev)) { - h2c_v1 = &h2c->base_v1; + h2c_v1 = &h2c_v2->base_v1; h2c_v1->mlo_1_1 = cpu_to_le32(1); } done: diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 6a297fad148b..f12728ccb31f 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4574,11 +4574,17 @@ struct rtw89_fw_h2c_rfk_pre_info_v1 { __le32 mlo_1_1; } __packed; -struct rtw89_fw_h2c_rfk_pre_info { +struct rtw89_fw_h2c_rfk_pre_info_v2 { struct rtw89_fw_h2c_rfk_pre_info_v1 base_v1; __le32 cur_bandwidth[NUM_OF_RTW89_FW_RFK_PATH]; } __packed; +struct rtw89_fw_h2c_rfk_pre_info { + __le32 mlo_mode; + __le32 phy_idx; + __le32 mlo_1_1; +} __packed; + struct rtw89_h2c_rf_tssi { __le16 len; u8 phy; From ed15dddd75663db05583402a7ff1fc11c7f8e79a Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Wed, 31 Dec 2025 17:06:38 +0800 Subject: [PATCH 39/81] wifi: rtw89: rfk: add rtw89_fw_h2c_rf_pre_ntfy_mcc for new WiFi 7 firmware The pre-notify is to notify firmware the configured channels, and then RF calibration in firmware can use these values to calibrate RF properly. Since we need more information, change and add the new H2C command format. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 + drivers/net/wireless/realtek/rtw89/fw.c | 60 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 13 +++++ drivers/net/wireless/realtek/rtw89/phy.c | 6 +++ 4 files changed, 81 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index b42d3a4df4bf..b7d5eb25ef74 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4685,6 +4685,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V1, RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V2, + RTW89_FW_FEATURE_WITH_RFK_PRE_NOTIFY, RTW89_FW_FEATURE_RFK_RXDCK_V0, RTW89_FW_FEATURE_RFK_IQK_V0, RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX, @@ -5239,6 +5240,7 @@ struct rtw89_rfk_mcc_info_data { u8 ch[RTW89_RFK_CHS_NR]; u8 band[RTW89_RFK_CHS_NR]; u8 bw[RTW89_RFK_CHS_NR]; + u32 rf18[RTW89_RFK_CHS_NR]; u8 table_idx; }; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d05b15ea022a..d13c93fafb34 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -892,6 +892,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 79, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 80, 0, BEACON_TRACKING), + __CFG_FW_FEAT(RTL8922A, le, 0, 35, 80, 0, WITH_RFK_PRE_NOTIFY), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 84, 0, ADDR_CAM_V0), }; @@ -6490,6 +6491,65 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, return ret; } +int rtw89_fw_h2c_rf_pre_ntfy_mcc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_fw_h2c_rfk_pre_info_mcc *h2c; + struct rtw89_hal *hal = &rtwdev->hal; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u8 tbl, path; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c rfk_pre_ntfy_mcc\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_fw_h2c_rfk_pre_info_mcc *)skb->data; + + BUILD_BUG_ON(NUM_OF_RTW89_FW_RFK_TBL > RTW89_RFK_CHS_NR); + + for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) + h2c->tbl_18[tbl] = cpu_to_le32(rfk_mcc->rf18[tbl]); + + BUILD_BUG_ON(ARRAY_SIZE(rtwdev->rfk_mcc.data) < NUM_OF_RTW89_FW_RFK_PATH); + + /* shared table array, but tbl_sel can be independent by path */ + for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { + tbl = rfk_mcc[path].table_idx; + h2c->cur_18[path] = cpu_to_le32(rfk_mcc->rf18[tbl]); + + if (path == phy_idx) + h2c->tbl_idx = tbl; + } + + h2c->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + + if (rtw89_is_mlo_1_1(rtwdev)) + h2c->mlo_1_1 = cpu_to_le32(1); + + h2c->phy_idx = phy_idx; + h2c->aid = cpu_to_le32(hal->aid); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY, + H2C_FUNC_OUTSRC_RF_MCC_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; +} + 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) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index f12728ccb31f..5292b568e2bf 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4471,6 +4471,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_MCC_INFO 0xf #define H2C_FUNC_OUTSRC_RF_PS_INFO 0x10 #define H2C_CL_OUTSRC_RF_FW_RFK 0xb @@ -4585,6 +4586,17 @@ struct rtw89_fw_h2c_rfk_pre_info { __le32 mlo_1_1; } __packed; +struct rtw89_fw_h2c_rfk_pre_info_mcc { + __le32 tbl_18[NUM_OF_RTW89_FW_RFK_TBL]; + __le32 cur_18[NUM_OF_RTW89_FW_RFK_PATH]; + __le32 mlo_mode; + __le32 mlo_1_1; + u8 phy_idx; + u8 tbl_idx; + u8 rsvd[2]; + __le32 aid; +} __packed; + struct rtw89_h2c_rf_tssi { __le16 len; u8 phy; @@ -4942,6 +4954,7 @@ 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_pre_ntfy_mcc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_mcc_dig(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx chanctx_idx, u8 mcc_role_idx, u8 pd_val, bool en); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 9f418b1fb7ed..d0e5d52964de 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -3808,6 +3808,12 @@ int rtw89_phy_rfk_pre_ntfy_and_wait(struct rtw89_dev *rtwdev, { int ret; + if (RTW89_CHK_FW_FEATURE(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) + goto pre_ntfy; + + return rtw89_fw_h2c_rf_pre_ntfy_mcc(rtwdev, phy_idx); + +pre_ntfy: rtw89_phy_rfk_report_prep(rtwdev); ret = rtw89_fw_h2c_rf_pre_ntfy(rtwdev, phy_idx); From 9485da4e4c9b15311161e33284867d9ee132cc47 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 31 Dec 2025 17:06:39 +0800 Subject: [PATCH 40/81] wifi: rtw89: pre-handle RF calibration on link when needed The Wi-Fi 7 RF calibration flow has a new design which mainly affect MLO cases. Before, old RFK H2C command can just send the used channels and MLO mode even if there are multiple active links. After, each RFK H2C command should send one channel corresponding to one active link. For example, connect MLD AP (channel X) and then activate second link (channel X + channel Y) Before: RFK#1: channel X (path A + path B) RFK#2: channel X (path A) + channel Y (path B) After: RFK#1: channel X (path A + path B) [set MLO mode to focus on 2nd link/channel] RFK#2: channel Y (path A + path B) [set MLO mode back to target case] Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 33 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/chan.h | 2 ++ drivers/net/wireless/realtek/rtw89/core.c | 29 +++++++++++++++- drivers/net/wireless/realtek/rtw89/core.h | 13 +++----- drivers/net/wireless/realtek/rtw89/mac80211.c | 3 +- 5 files changed, 69 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 8fe6a7ef738f..0b5509468582 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -295,6 +295,8 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev) mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE; } + hal->entity_force_hw = RTW89_PHY_NUM; + rtw89_config_default_chandef(rtwdev); } @@ -417,12 +419,43 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(__rtw89_mgnt_chan_get); +bool rtw89_entity_check_hw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + switch (rtwdev->mlo_dbcc_mode) { + case MLO_2_PLUS_0_1RF: + return phy_idx == RTW89_PHY_0; + case MLO_0_PLUS_2_1RF: + return phy_idx == RTW89_PHY_1; + default: + return false; + } +} + +void rtw89_entity_force_hw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + rtwdev->hal.entity_force_hw = phy_idx; + + if (phy_idx != RTW89_PHY_NUM) + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "%s: %d\n", __func__, phy_idx); + else + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "%s: (none)\n", __func__); +} + static enum rtw89_mlo_dbcc_mode rtw89_entity_sel_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws) { if (rtwdev->chip->chip_gen != RTW89_CHIP_BE) return MLO_DBCC_NOT_SUPPORT; + switch (rtwdev->hal.entity_force_hw) { + case RTW89_PHY_0: + return MLO_2_PLUS_0_1RF; + case RTW89_PHY_1: + return MLO_0_PLUS_2_1RF; + default: + break; + } + switch (active_hws) { case BIT(0): return MLO_2_PLUS_0_1RF; diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 5b22764d5329..c797cda2e763 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -166,6 +166,8 @@ void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev, const struct cfg80211_chan_def *chandef); void rtw89_entity_init(struct rtw89_dev *rtwdev); enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev); +bool rtw89_entity_check_hw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw89_entity_force_hw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); 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, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index e713422ebd7c..96fb2839379f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -470,6 +470,32 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev) __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_1); } +void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + bool mon = !!rtwdev->pure_monitor_mode_vif; + bool prehdl_link = false; + + if (chip->chip_gen != RTW89_CHIP_AX && + !RTW89_CHK_FW_FEATURE(WITH_RFK_PRE_NOTIFY, &rtwdev->fw) && + !mon && !rtw89_entity_check_hw(rtwdev, rtwvif_link->phy_idx)) + prehdl_link = true; + + if (prehdl_link) { + rtw89_entity_force_hw(rtwdev, rtwvif_link->phy_idx); + rtw89_set_channel(rtwdev); + } + + if (chip->ops->rfk_channel) + chip->ops->rfk_channel(rtwdev, rtwvif_link); + + if (prehdl_link) { + rtw89_entity_force_hw(rtwdev, RTW89_PHY_NUM); + rtw89_set_channel(rtwdev); + } +} + static void rtw89_chip_rfk_channel_for_pure_mon_vif(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -6218,7 +6244,8 @@ int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, goto wake_queue; } - rtw89_chip_rfk_channel(rtwdev, target); + if (RTW89_CHK_FW_FEATURE(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) + rtw89_chip_rfk_channel(rtwdev, target); rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index b7d5eb25ef74..52d6e5683d63 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5075,6 +5075,8 @@ struct rtw89_hal { enum rtw89_entity_mode entity_mode; struct rtw89_entity_mgnt entity_mgnt; + enum rtw89_phy_idx entity_force_hw; + u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */ u8 thermal_prot_th; @@ -7125,15 +7127,6 @@ static inline void rtw89_chip_rfk_init_late(struct rtw89_dev *rtwdev) chip->ops->rfk_init_late(rtwdev); } -static inline void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev, - struct rtw89_vif_link *rtwvif_link) -{ - const struct rtw89_chip_info *chip = rtwdev->chip; - - if (chip->ops->rfk_channel) - chip->ops->rfk_channel(rtwdev, rtwvif_link); -} - static inline void rtw89_chip_rfk_band_changed(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan) @@ -7647,6 +7640,8 @@ struct rtw89_sta_link *rtw89_sta_set_link(struct rtw89_sta *rtwsta, unsigned int link_id); void rtw89_sta_unset_link(struct rtw89_sta *rtwsta, unsigned int link_id); void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev); +void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); const struct rtw89_6ghz_span * rtw89_get_6ghz_span(struct rtw89_dev *rtwdev, u32 center_freq); void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef); diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index f80c847d1741..96dc94c1f556 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -720,7 +720,8 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_MLD_VALID_LINKS) { struct rtw89_vif_link *cur = rtw89_get_designated_link(rtwvif); - rtw89_chip_rfk_channel(rtwdev, cur); + if (RTW89_CHK_FW_FEATURE(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) + rtw89_chip_rfk_channel(rtwdev, cur); if (hweight16(vif->active_links) == 1) rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR; From c5e5519fd9815f2f87c256c27c6da7b37f63a7ad Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 31 Dec 2025 17:06:40 +0800 Subject: [PATCH 41/81] wifi: rtw89: fw: change FW feature map to a BITMAP Originally, FW feature map was declared as a u32. But, the number of FW feature flags is going to be over than 32. So, change it to a BITMAP and update the corresponding macros. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 52d6e5683d63..7b6dfab8e56c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4702,6 +4702,8 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_ADDR_CAM_V0, RTW89_FW_FEATURE_SER_L1_BY_EVENT, RTW89_FW_FEATURE_SIM_SER_L0L1_BY_HALT_H2C, + + NUM_OF_RTW89_FW_FEATURES, }; struct rtw89_fw_suit { @@ -4793,20 +4795,25 @@ struct rtw89_fw_info { struct rtw89_fw_suit bbmcu0; struct rtw89_fw_suit bbmcu1; struct rtw89_fw_log log; - u32 feature_map; struct rtw89_fw_elm_info elm_info; struct rtw89_fw_secure sec; + + DECLARE_BITMAP(feature_map, NUM_OF_RTW89_FW_FEATURES); }; #define RTW89_CHK_FW_FEATURE(_feat, _fw) \ - (!!((_fw)->feature_map & BIT(RTW89_FW_FEATURE_ ## _feat))) + test_bit(RTW89_FW_FEATURE_ ## _feat, (_fw)->feature_map) #define RTW89_CHK_FW_FEATURE_GROUP(_grp, _fw) \ - (!!((_fw)->feature_map & GENMASK(RTW89_FW_FEATURE_ ## _grp ## _MAX, \ - RTW89_FW_FEATURE_ ## _grp ## _MIN))) +({ \ + unsigned int bit = find_next_bit((_fw)->feature_map, \ + NUM_OF_RTW89_FW_FEATURES, \ + RTW89_FW_FEATURE_ ## _grp ## _MIN); \ + bit <= RTW89_FW_FEATURE_ ## _grp ## _MAX; \ +}) #define RTW89_SET_FW_FEATURE(_fw_feature, _fw) \ - ((_fw)->feature_map |= BIT(_fw_feature)) + set_bit(_fw_feature, (_fw)->feature_map) struct rtw89_cam_info { DECLARE_BITMAP(addr_cam_map, RTW89_MAX_ADDR_CAM_NUM); From 2d986cf3cc7193147ee20e681bfead4833a5efbf Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 31 Dec 2025 17:06:41 +0800 Subject: [PATCH 42/81] wifi: rtw89: fw: introduce helper for disabling FW feature configuration Some FW features (groups) may be valid only in a range of FW versions, i.e. after some FW versions, they can no longer be used. So, introduce some helper macros to configure this kind of things in FW feature table. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 3 ++ drivers/net/wireless/realtek/rtw89/fw.c | 36 ++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7b6dfab8e56c..8010ee070108 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4815,6 +4815,9 @@ struct rtw89_fw_info { #define RTW89_SET_FW_FEATURE(_fw_feature, _fw) \ set_bit(_fw_feature, (_fw)->feature_map) +#define RTW89_CLR_FW_FEATURE(_fw_feature, _fw) \ + clear_bit(_fw_feature, (_fw)->feature_map) + struct rtw89_cam_info { DECLARE_BITMAP(addr_cam_map, RTW89_MAX_ADDR_CAM_NUM); DECLARE_BITMAP(bssid_cam_map, RTW89_MAX_BSSID_CAM_NUM); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d13c93fafb34..8804f5da88b1 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -812,6 +812,8 @@ struct __fw_feat_cfg { enum rtw89_fw_feature feature; u32 ver_code; bool (*cond)(u32 suit_ver_code, u32 comp_ver_code); + bool disable; + int size; }; #define __CFG_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat) \ @@ -822,6 +824,30 @@ struct __fw_feat_cfg { .cond = __fw_feat_cond_ ## _cond, \ } +#define __S_DIS_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat) \ + { \ + .chip_id = _chip, \ + .feature = RTW89_FW_FEATURE_ ## _feat, \ + .ver_code = RTW89_FW_VER_CODE(_maj, _min, _sub, _idx), \ + .cond = __fw_feat_cond_ ## _cond, \ + .disable = true, \ + .size = 1, \ + } + +#define __G_DIS_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _grp) \ + { \ + .chip_id = _chip, \ + .feature = RTW89_FW_FEATURE_ ## _grp ## _MIN, \ + .ver_code = RTW89_FW_VER_CODE(_maj, _min, _sub, _idx), \ + .cond = __fw_feat_cond_ ## _cond, \ + .disable = true, \ + .size = RTW89_FW_FEATURE_ ## _grp ## _MAX - \ + RTW89_FW_FEATURE_ ## _grp ## _MIN + 1, \ + } + +#define __DIS_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat, _type) \ + __##_type##_DIS_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat) + static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), @@ -908,8 +934,16 @@ static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, if (chip->chip_id != ent->chip_id) continue; - if (ent->cond(ver_code, ent->ver_code)) + if (!ent->cond(ver_code, ent->ver_code)) + continue; + + if (!ent->disable) { RTW89_SET_FW_FEATURE(ent->feature, fw); + continue; + } + + for (int n = 0; n < ent->size; n++) + RTW89_CLR_FW_FEATURE(ent->feature + n, fw); } } From 29009d98d98f08164aafba2392a778b85e15b43e Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 31 Dec 2025 17:06:42 +0800 Subject: [PATCH 43/81] wifi: rtw89: 8922a: tweak RFK_PRE_NOTIFY FW feature configuration to align handling In the FW feature table, V0 and V1 was configured by lt, less than. So, V1 flag was also set in the range of V0. However, in RFK_PRE_NOTIFY handling, rtw89_fw_h2c_rf_pre_ntfy, V1 is tested before V0. Things would process as V1 even if V0 should be used. Tweak FW feature configuration by ge, greater or equal, to align handling. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 8804f5da88b1..067f6f0ea101 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -897,6 +897,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 129, 1, BEACON_TRACKING), __CFG_FW_FEAT(RTL8852C, ge, 0, 29, 94, 0, SER_L1_BY_EVENT), __CFG_FW_FEAT(RTL8852C, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), + __CFG_FW_FEAT(RTL8922A, ge, 0, 0, 0, 0, RFK_PRE_NOTIFY_V0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), @@ -905,12 +906,11 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __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, ge, 0, 35, 31, 0, RFK_PRE_NOTIFY_V1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, LPS_CH_INFO), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 42, 0, RFK_RXDCK_V0), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 46, 0, NOTIFY_AP_INFO), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 47, 0, CH_INFO_BE_V0), - __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 49, 0, RFK_PRE_NOTIFY_V1), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 49, 0, RFK_PRE_NOTIFY_V2), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 51, 0, NO_PHYCAP_P1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE), From 449a57911967d038d78f2c04d2effc1af0fdceb7 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 31 Dec 2025 17:06:43 +0800 Subject: [PATCH 44/81] wifi: rtw89: refine mis-ordered entries in FW feature table Make all entries in firmware feature table in increasing order of firmware version. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 067f6f0ea101..4ba99e7078fe 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -884,8 +884,8 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SER_L1_BY_EVENT), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), - __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, le, 0, 27, 33, 0, NO_DEEP_PS), __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_TYPE_0), @@ -898,12 +898,12 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 29, 94, 0, SER_L1_BY_EVENT), __CFG_FW_FEAT(RTL8852C, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), __CFG_FW_FEAT(RTL8922A, ge, 0, 0, 0, 0, RFK_PRE_NOTIFY_V0), - __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD_EXTRA_OP), - __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, lt, 0, 35, 21, 0, SCAN_OFFLOAD_BE_V0), __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, ge, 0, 35, 31, 0, RFK_PRE_NOTIFY_V1), From 6a6b0aac287406228ac1c69a0959f78a721fb8c0 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 31 Dec 2025 17:06:44 +0800 Subject: [PATCH 45/81] wifi: rtw89: fw: change WITH_RFK_PRE_NOTIFY to be a FW feature group Actually, WITH_RFK_PRE_NOTIFY means supporting one of RFK_PRE_NOTIFY_Vx. So, change it to be a FW feature group which contains RFK_PRE_NOTIFY_Vx. Then, because WITH_RFK_PRE_NOTIFY is abandoned after some FW versions by chip, disable WITH_RFK_PRE_NOTIFY correspondingly in FW feature table. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 4 ++-- drivers/net/wireless/realtek/rtw89/core.h | 10 ++++++---- drivers/net/wireless/realtek/rtw89/fw.c | 5 +++-- drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +- drivers/net/wireless/realtek/rtw89/phy.c | 2 +- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 96fb2839379f..191caafbd0fb 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -478,7 +478,7 @@ void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev, bool prehdl_link = false; if (chip->chip_gen != RTW89_CHIP_AX && - !RTW89_CHK_FW_FEATURE(WITH_RFK_PRE_NOTIFY, &rtwdev->fw) && + !RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw) && !mon && !rtw89_entity_check_hw(rtwdev, rtwvif_link->phy_idx)) prehdl_link = true; @@ -6244,7 +6244,7 @@ int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, goto wake_queue; } - if (RTW89_CHK_FW_FEATURE(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) + if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) rtw89_chip_rfk_channel(rtwdev, target); rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 8010ee070108..38a64b0bfb5c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4682,10 +4682,12 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_MACID_PAUSE_SLEEP, RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V0, RTW89_FW_FEATURE_WOW_REASON_V1, - RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, - RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V1, - RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V2, - RTW89_FW_FEATURE_WITH_RFK_PRE_NOTIFY, + RTW89_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V1, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V2, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V3, + ), RTW89_FW_FEATURE_RFK_RXDCK_V0, RTW89_FW_FEATURE_RFK_IQK_V0, RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 4ba99e7078fe..fed9b3db1543 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -918,7 +918,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 79, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 80, 0, BEACON_TRACKING), - __CFG_FW_FEAT(RTL8922A, le, 0, 35, 80, 0, WITH_RFK_PRE_NOTIFY), + __DIS_FW_FEAT(RTL8922A, ge, 0, 35, 84, 0, WITH_RFK_PRE_NOTIFY, G), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 84, 0, ADDR_CAM_V0), }; @@ -6414,7 +6414,8 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, u32 val32; int ret; - if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V2, &rtwdev->fw)) { + if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V3, &rtwdev->fw)) { + } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V2, &rtwdev->fw)) { len = sizeof(*h2c_v2); ver = 2; } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V1, &rtwdev->fw)) { diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 96dc94c1f556..ba71709a9bc9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -720,7 +720,7 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_MLD_VALID_LINKS) { struct rtw89_vif_link *cur = rtw89_get_designated_link(rtwvif); - if (RTW89_CHK_FW_FEATURE(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) + if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) rtw89_chip_rfk_channel(rtwdev, cur); if (hweight16(vif->active_links) == 1) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index d0e5d52964de..f56b433a1674 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -3808,7 +3808,7 @@ int rtw89_phy_rfk_pre_ntfy_and_wait(struct rtw89_dev *rtwdev, { int ret; - if (RTW89_CHK_FW_FEATURE(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) + if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) goto pre_ntfy; return rtw89_fw_h2c_rf_pre_ntfy_mcc(rtwdev, phy_idx); From cd7ce83ff6da0d9a760230f5dbf0c3148c534133 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Wed, 31 Dec 2025 17:06:45 +0800 Subject: [PATCH 46/81] wifi: rtw89: rfk: update rtw89_fw_h2c_rf_pre_ntfy_mcc format The H2C command rtw89_fw_h2c_rf_pre_ntfy_mcc have different format. 8922A after FW 0.35.49.0 use v0, after FW 0.35.84.0 use v1. The coming 8922D will use v2. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 5 ++ drivers/net/wireless/realtek/rtw89/fw.c | 55 ++++++++++++++++--- drivers/net/wireless/realtek/rtw89/fw.h | 12 +++- drivers/net/wireless/realtek/rtw89/phy.c | 23 ++++---- .../net/wireless/realtek/rtw89/rtw8922a_rfk.c | 48 +++++++++++++++- 5 files changed, 122 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 38a64b0bfb5c..661b6a23082a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4688,6 +4688,11 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V2, RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V3, ), + RTW89_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY_MCC, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_MCC_V0, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_MCC_V1, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_MCC_V2, + ), RTW89_FW_FEATURE_RFK_RXDCK_V0, RTW89_FW_FEATURE_RFK_IQK_V0, RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index fed9b3db1543..24077a8095c4 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -912,6 +912,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 46, 0, NOTIFY_AP_INFO), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 47, 0, CH_INFO_BE_V0), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 49, 0, RFK_PRE_NOTIFY_V2), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 49, 0, RFK_PRE_NOTIFY_MCC_V0), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 51, 0, NO_PHYCAP_P1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1), @@ -919,6 +920,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 79, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 80, 0, BEACON_TRACKING), __DIS_FW_FEAT(RTL8922A, ge, 0, 35, 84, 0, WITH_RFK_PRE_NOTIFY, G), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 84, 0, RFK_PRE_NOTIFY_MCC_V1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 84, 0, ADDR_CAM_V0), }; @@ -6529,45 +6531,84 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_rf_pre_ntfy_mcc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_mcc_info *rfk_mcc_v0 = &rtwdev->rfk_mcc; + struct rtw89_fw_h2c_rfk_pre_info_mcc_v0 *h2c_v0; + struct rtw89_fw_h2c_rfk_pre_info_mcc_v1 *h2c_v1; struct rtw89_fw_h2c_rfk_pre_info_mcc *h2c; struct rtw89_hal *hal = &rtwdev->hal; u32 len = sizeof(*h2c); struct sk_buff *skb; + u8 ver = U8_MAX; u8 tbl, path; + u8 tbl_sel; int ret; + if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_MCC_V2, &rtwdev->fw)) { + } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_MCC_V1, &rtwdev->fw)) { + len = sizeof(*h2c_v1); + ver = 1; + } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_MCC_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 rfk_pre_ntfy_mcc\n"); return -ENOMEM; } skb_put(skb, len); - h2c = (struct rtw89_fw_h2c_rfk_pre_info_mcc *)skb->data; + + if (ver != 0) + goto v1; + + h2c_v0 = (struct rtw89_fw_h2c_rfk_pre_info_mcc_v0 *)skb->data; + for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) { + for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { + h2c_v0->tbl_18[tbl][path] = + cpu_to_le32(rfk_mcc_v0->data[path].rf18[tbl]); + tbl_sel = rfk_mcc_v0->data[path].table_idx; + h2c_v0->cur_18[path] = + cpu_to_le32(rfk_mcc_v0->data[path].rf18[tbl_sel]); + } + } + + h2c_v0->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + goto done; + +v1: + h2c_v1 = (struct rtw89_fw_h2c_rfk_pre_info_mcc_v1 *)skb->data; BUILD_BUG_ON(NUM_OF_RTW89_FW_RFK_TBL > RTW89_RFK_CHS_NR); for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) - h2c->tbl_18[tbl] = cpu_to_le32(rfk_mcc->rf18[tbl]); + h2c_v1->tbl_18[tbl] = cpu_to_le32(rfk_mcc->rf18[tbl]); BUILD_BUG_ON(ARRAY_SIZE(rtwdev->rfk_mcc.data) < NUM_OF_RTW89_FW_RFK_PATH); /* shared table array, but tbl_sel can be independent by path */ for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { tbl = rfk_mcc[path].table_idx; - h2c->cur_18[path] = cpu_to_le32(rfk_mcc->rf18[tbl]); + h2c_v1->cur_18[path] = cpu_to_le32(rfk_mcc->rf18[tbl]); if (path == phy_idx) - h2c->tbl_idx = tbl; + h2c_v1->tbl_idx = tbl; } - h2c->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + h2c_v1->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + h2c_v1->phy_idx = phy_idx; if (rtw89_is_mlo_1_1(rtwdev)) - h2c->mlo_1_1 = cpu_to_le32(1); + h2c_v1->mlo_1_1 = cpu_to_le32(1); + + if (ver == 1) + goto done; + + h2c = (struct rtw89_fw_h2c_rfk_pre_info_mcc *)skb->data; - h2c->phy_idx = phy_idx; h2c->aid = cpu_to_le32(hal->aid); +done: rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY, H2C_FUNC_OUTSRC_RF_MCC_INFO, 0, 0, len); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 5292b568e2bf..91eaf07f5824 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4586,13 +4586,23 @@ struct rtw89_fw_h2c_rfk_pre_info { __le32 mlo_1_1; } __packed; -struct rtw89_fw_h2c_rfk_pre_info_mcc { +struct rtw89_fw_h2c_rfk_pre_info_mcc_v0 { + __le32 tbl_18[NUM_OF_RTW89_FW_RFK_TBL][NUM_OF_RTW89_FW_RFK_PATH]; + __le32 cur_18[NUM_OF_RTW89_FW_RFK_PATH]; + __le32 mlo_mode; +} __packed; + +struct rtw89_fw_h2c_rfk_pre_info_mcc_v1 { __le32 tbl_18[NUM_OF_RTW89_FW_RFK_TBL]; __le32 cur_18[NUM_OF_RTW89_FW_RFK_PATH]; __le32 mlo_mode; __le32 mlo_1_1; u8 phy_idx; u8 tbl_idx; +} __packed; + +struct rtw89_fw_h2c_rfk_pre_info_mcc { + struct rtw89_fw_h2c_rfk_pre_info_mcc_v1 base; u8 rsvd[2]; __le32 aid; } __packed; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index f56b433a1674..d29fbc9cb5ac 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -3808,19 +3808,22 @@ int rtw89_phy_rfk_pre_ntfy_and_wait(struct rtw89_dev *rtwdev, { int ret; - if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) - goto pre_ntfy; + if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) { + rtw89_phy_rfk_report_prep(rtwdev); + rtw89_fw_h2c_rf_pre_ntfy(rtwdev, phy_idx); + ret = rtw89_phy_rfk_report_wait(rtwdev, "PRE_NTFY", ms); + if (ret) + return ret; + } - return rtw89_fw_h2c_rf_pre_ntfy_mcc(rtwdev, phy_idx); + if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY_MCC, &rtwdev->fw)) { + ret = rtw89_fw_h2c_rf_pre_ntfy_mcc(rtwdev, phy_idx); + if (ret) + return ret; + } -pre_ntfy: - rtw89_phy_rfk_report_prep(rtwdev); + return 0; - ret = rtw89_fw_h2c_rf_pre_ntfy(rtwdev, phy_idx); - if (ret) - return ret; - - return rtw89_phy_rfk_report_wait(rtwdev, "PRE_NTFY", ms); } EXPORT_SYMBOL(rtw89_phy_rfk_pre_ntfy_and_wait); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index fce094c7ce93..98f14b31cf52 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -205,11 +205,11 @@ static void rtw8922a_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx) } } -static u8 rtw8922a_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev, - const struct rtw89_chan *chan, u8 path) +static u8 rtw8922a_chlk_reload_sel_tbl_v0(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 path) { - struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {}; + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; u8 tbl_sel; for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) { @@ -229,11 +229,53 @@ static u8 rtw8922a_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev, rfk_mcc->data[path].ch[tbl_sel] = chan->channel; rfk_mcc->data[path].band[tbl_sel] = chan->band_type; rfk_mcc->data[path].bw[tbl_sel] = chan->band_width; + rfk_mcc->data[path].rf18[tbl_sel] = rtw89_chip_chan_to_rf18_val(rtwdev, chan); rfk_mcc->data[path].table_idx = tbl_sel; return tbl_sel; } +static u8 rtw8922a_chlk_reload_sel_tbl_v1(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 path) +{ + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {}; + u8 tbl_sel; + + for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) { + struct rtw89_rfk_chan_desc *p = &desc[tbl_sel]; + + p->ch = rfk_mcc->ch[tbl_sel]; + + p->has_band = true; + p->band = rfk_mcc->band[tbl_sel]; + + p->has_bw = true; + p->bw = rfk_mcc->bw[tbl_sel]; + } + + tbl_sel = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); + + rfk_mcc->ch[tbl_sel] = chan->channel; + rfk_mcc->band[tbl_sel] = chan->band_type; + rfk_mcc->bw[tbl_sel] = chan->band_width; + rfk_mcc->rf18[tbl_sel] = rtw89_chip_chan_to_rf18_val(rtwdev, chan); + + /* shared table array, but tbl_sel can be independent by path */ + rfk_mcc[path].table_idx = tbl_sel; + + return tbl_sel; +} + +static u8 rtw8922a_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 path) +{ + if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_MCC_V1, &rtwdev->fw)) + return rtw8922a_chlk_reload_sel_tbl_v1(rtwdev, chan, path); + else + return rtw8922a_chlk_reload_sel_tbl_v0(rtwdev, chan, path); +} + static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) { const struct rtw89_chan *chan0, *chan1; From eb57be32f438c57c88d6ce756101c1dfbcc03bba Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Wed, 31 Dec 2025 17:06:46 +0800 Subject: [PATCH 47/81] wifi: rtw89: fix potential zero beacon interval in beacon tracking During fuzz testing, it was discovered that bss_conf->beacon_int might be zero, which could result in a division by zero error in subsequent calculations. Set a default value of 100 TU if the interval is zero to ensure stability. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 191caafbd0fb..6811a3970ddb 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2813,7 +2813,7 @@ static void rtw89_core_bcn_track_assoc(struct rtw89_dev *rtwdev, rcu_read_lock(); bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); - beacon_int = bss_conf->beacon_int; + beacon_int = bss_conf->beacon_int ?: 100; dtim = bss_conf->dtim_period; rcu_read_unlock(); @@ -2843,9 +2843,7 @@ static void rtw89_core_bcn_track_reset(struct rtw89_dev *rtwdev) memset(&rtwdev->bcn_track, 0, sizeof(rtwdev->bcn_track)); } -static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, - struct ieee80211_bss_conf *bss_conf, - struct sk_buff *skb) +static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, struct sk_buff *skb) { #define RTW89_APPEND_TSF_2GHZ 384 #define RTW89_APPEND_TSF_5GHZ 52 @@ -2854,7 +2852,7 @@ static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; - u32 bcn_intvl_us = ieee80211_tu_to_usec(bss_conf->beacon_int); + u32 bcn_intvl_us = ieee80211_tu_to_usec(bcn_track->beacon_int); u64 tsf = le64_to_cpu(mgmt->u.beacon.timestamp); u8 wp, num = bcn_stat->num; u16 append; @@ -2862,6 +2860,10 @@ static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) return; + /* Skip if not yet associated */ + if (!bcn_intvl_us) + return; + switch (rx_status->band) { default: case NL80211_BAND_2GHZ: @@ -2949,7 +2951,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, pkt_stat->beacon_rate = desc_info->data_rate; pkt_stat->beacon_len = skb->len; - rtw89_vif_rx_bcn_stat(rtwdev, bss_conf, skb); + rtw89_vif_rx_bcn_stat(rtwdev, skb); } if (!ether_addr_equal(bss_conf->addr, hdr->addr1)) From baef3d5d96d2f7530011cdebd7aeecdc85cd93a7 Mon Sep 17 00:00:00 2001 From: Dian-Syuan Yang Date: Wed, 31 Dec 2025 17:06:47 +0800 Subject: [PATCH 48/81] wifi: rtw89: 8852b: refine hardware parameters for RFE type 5 The RFE type 5 should set different DSWR parameters when card power on. Therefore, add the corresponding register settings for this type. Signed-off-by: Dian-Syuan Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251231090647.56407-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 2 ++ drivers/net/wireless/realtek/rtw89/rtw8852b.c | 24 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 081623f84dd9..9f963bd85f02 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -323,7 +323,9 @@ #define B_AX_PCIE_HCISYS_PWR_STE_MASK GENMASK(1, 0) #define R_AX_SPS_DIG_OFF_CTRL0 0x0400 +#define B_AX_R1_L1_MASK GENMASK(7, 6) #define B_AX_C3_L1_MASK GENMASK(5, 4) +#define B_AX_C2_L1_MASK GENMASK(3, 2) #define B_AX_C1_L1_MASK GENMASK(1, 0) #define R_AX_AFE_OFF_CTRL1 0x0444 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 0f18555e619b..a138d89bce84 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -313,6 +313,27 @@ static void rtw8852b_pwr_sps_ana(struct rtw89_dev *rtwdev) rtw89_write16(rtwdev, R_AX_SPS_ANA_ON_CTRL2, RTL8852B_RFE_05_SPS_ANA); } +static void rtw8852b_pwr_sps_dig_off(struct rtw89_dev *rtwdev) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + + if (efuse->rfe_type == 0x5) { + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C1_L1_MASK, 0x1); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C2_L1_MASK, 0x1); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C3_L1_MASK, 0x2); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_R1_L1_MASK, 0x1); + } else { + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C1_L1_MASK, 0x1); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C3_L1_MASK, 0x3); + } +} + static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; @@ -338,8 +359,7 @@ static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) if (ret) return ret; - rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, B_AX_C1_L1_MASK, 0x1); - rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, B_AX_C3_L1_MASK, 0x3); + rtw8852b_pwr_sps_dig_off(rtwdev); rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_EN_WLON); rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFN_ONMAC); From 2adaa4b36b55261c9d94ed911078071063dea12a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:02 +0800 Subject: [PATCH 49/81] wifi: rtw89: update TXWD v3 for RTL8922D Add TXWD v3 to assist in transmitting for RTL8922D according to hardware design. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 59 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/core.h | 3 ++ drivers/net/wireless/realtek/rtw89/txrx.h | 16 ++++++ 3 files changed, 78 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 6811a3970ddb..3410fce22fbf 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1659,6 +1659,17 @@ static __le32 rtw89_build_txwd_body2_v2(struct rtw89_tx_desc_info *desc_info) return cpu_to_le32(dword); } +static __le32 rtw89_build_txwd_body2_v3(struct rtw89_tx_desc_info *desc_info) +{ + u32 dword = FIELD_PREP(BE_TXD_BODY2_TID_IND_V1, desc_info->tid_indicate) | + FIELD_PREP(BE_TXD_BODY2_QSEL_V1, desc_info->qsel) | + FIELD_PREP(BE_TXD_BODY2_TXPKTSIZE, desc_info->pkt_size) | + FIELD_PREP(BE_TXD_BODY2_AGG_EN, desc_info->agg_en) | + FIELD_PREP(BE_TXD_BODY2_MACID_V1, desc_info->mac_id); + + return cpu_to_le32(dword); +} + static __le32 rtw89_build_txwd_body3_v2(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq) | @@ -1668,6 +1679,16 @@ static __le32 rtw89_build_txwd_body3_v2(struct rtw89_tx_desc_info *desc_info) return cpu_to_le32(dword); } +static __le32 rtw89_build_txwd_body3_v3(struct rtw89_tx_desc_info *desc_info) +{ + u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq) | + FIELD_PREP(BE_TXD_BODY3_MLO_FLAG, desc_info->mlo) | + FIELD_PREP(BE_TXD_BODY3_IS_MLD_SW_EN, desc_info->sw_mld) | + FIELD_PREP(BE_TXD_BODY3_BK_V1, desc_info->bk); + + return cpu_to_le32(dword); +} + static __le32 rtw89_build_txwd_body4_v2(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(BE_TXD_BODY4_SEC_IV_L0, desc_info->sec_seq[0]) | @@ -1739,6 +1760,15 @@ static __le32 rtw89_build_txwd_info2_v2(struct rtw89_tx_desc_info *desc_info) return cpu_to_le32(dword); } +static __le32 rtw89_build_txwd_info2_v3(struct rtw89_tx_desc_info *desc_info) +{ + u32 dword = FIELD_PREP(BE_TXD_INFO2_AMPDU_DENSITY, desc_info->ampdu_density) | + FIELD_PREP(BE_TXD_INFO2_FORCE_KEY_EN_V1, desc_info->sec_en) | + FIELD_PREP(BE_TXD_INFO2_SEC_CAM_IDX_V1, desc_info->sec_cam_idx); + + return cpu_to_le32(dword); +} + static __le32 rtw89_build_txwd_info4_v2(struct rtw89_tx_desc_info *desc_info) { bool rts_en = !desc_info->is_bmc; @@ -1777,6 +1807,35 @@ void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_core_fill_txdesc_v2); +void rtw89_core_fill_txdesc_v3(struct rtw89_dev *rtwdev, + struct rtw89_tx_desc_info *desc_info, + void *txdesc) +{ + struct rtw89_txwd_body_v2 *txwd_body = txdesc; + struct rtw89_txwd_info_v2 *txwd_info; + + txwd_body->dword0 = rtw89_build_txwd_body0_v2(desc_info); + txwd_body->dword1 = rtw89_build_txwd_body1_v2(desc_info); + txwd_body->dword2 = rtw89_build_txwd_body2_v3(desc_info); + txwd_body->dword3 = rtw89_build_txwd_body3_v3(desc_info); + if (desc_info->sec_en) { + txwd_body->dword4 = rtw89_build_txwd_body4_v2(desc_info); + txwd_body->dword5 = rtw89_build_txwd_body5_v2(desc_info); + } + txwd_body->dword6 = rtw89_build_txwd_body6_v2(desc_info); + txwd_body->dword7 = rtw89_build_txwd_body7_v2(desc_info); + + if (!desc_info->en_wd_info) + return; + + txwd_info = (struct rtw89_txwd_info_v2 *)(txwd_body + 1); + txwd_info->dword0 = rtw89_build_txwd_info0_v2(desc_info); + txwd_info->dword1 = rtw89_build_txwd_info1_v2(desc_info); + txwd_info->dword2 = rtw89_build_txwd_info2_v3(desc_info); + txwd_info->dword4 = rtw89_build_txwd_info4_v2(desc_info); +} +EXPORT_SYMBOL(rtw89_core_fill_txdesc_v3); + static __le32 rtw89_build_txwd_fwcmd0_v1(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(AX_RXD_RPKT_LEN_MASK, desc_info->pkt_size) | diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 661b6a23082a..c5d6c40ba3ce 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -7593,6 +7593,9 @@ void rtw89_core_fill_txdesc_v1(struct rtw89_dev *rtwdev, void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, void *txdesc); +void rtw89_core_fill_txdesc_v3(struct rtw89_dev *rtwdev, + struct rtw89_tx_desc_info *desc_info, + void *txdesc); void rtw89_core_fill_txdesc_fwcmd_v1(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, void *txdesc); diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index fa324b4a1dde..c92e25f8a2b5 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -188,12 +188,16 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_BODY2_QSEL GENMASK(22, 17) #define BE_TXD_BODY2_TID_IND BIT(23) #define BE_TXD_BODY2_MACID GENMASK(31, 24) +#define BE_TXD_BODY2_QSEL_V1 GENMASK(20, 15) +#define BE_TXD_BODY2_TID_IND_V1 BIT(21) +#define BE_TXD_BODY2_MACID_V1 GENMASK(31, 22) /* TX WD BODY DWORD 3 */ #define BE_TXD_BODY3_WIFI_SEQ GENMASK(11, 0) #define BE_TXD_BODY3_MLO_FLAG BIT(12) #define BE_TXD_BODY3_IS_MLD_SW_EN BIT(13) #define BE_TXD_BODY3_TRY_RATE BIT(14) +#define BE_TXD_BODY3_BK_V1 BIT(14) #define BE_TXD_BODY3_RELINK_FLAG_V1 BIT(15) #define BE_TXD_BODY3_BAND0_SU_TC_V1 GENMASK(21, 16) #define BE_TXD_BODY3_TOTAL_TC GENMASK(27, 22) @@ -201,6 +205,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_BODY3_MU_PRI_RTY BIT(29) #define BE_TXD_BODY3_MU_2ND_RTY BIT(30) #define BE_TXD_BODY3_BAND1_SU_RTY_V1 BIT(31) +#define BE_TXD_BODY3_DRIVER_QUEUE_TIME GENMASK(31, 16) /* TX WD BODY DWORD 4 */ #define BE_TXD_BODY4_TXDESC_CHECKSUM GENMASK(15, 0) @@ -224,6 +229,10 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_BODY6_EOSP_BIT BIT(15) #define BE_TXD_BODY6_S_IDX GENMASK(23, 16) #define BE_TXD_BODY6_RU_POS GENMASK(31, 24) +#define BE_TXD_BODY6_MU_TC_V1 GENMASK(3, 0) +#define BE_TXD_BODY6_RU_TC_V1 GENMASK(8, 5) +#define BE_TXD_BODY6_RELINK_EN BIT(9) +#define BE_TXD_BODY6_RELINK_LAST BIT(10) /* TX WD BODY DWORD 7 */ #define BE_TXD_BODY7_RTS_TC GENMASK(5, 0) @@ -262,6 +271,8 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) /* TX WD INFO DWORD 2 */ #define BE_TXD_INFO2_SEC_CAM_IDX GENMASK(7, 0) #define BE_TXD_INFO2_FORCE_KEY_EN BIT(8) +#define BE_TXD_INFO2_SEC_CAM_IDX_V1 GENMASK(9, 0) +#define BE_TXD_INFO2_FORCE_KEY_EN_V1 BIT(10) #define BE_TXD_INFO2_LIFETIME_SEL GENMASK(15, 13) #define BE_TXD_INFO2_FORCE_TXOP BIT(17) #define BE_TXD_INFO2_AMPDU_DENSITY GENMASK(20, 18) @@ -277,6 +288,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_INFO3_RTT_EN BIT(9) #define BE_TXD_INFO3_HT_DATA_SND_V1 BIT(10) #define BE_TXD_INFO3_BT_NULL BIT(11) +#define BE_TXD_INFO3_DISABLE_TXBF BIT(11) #define BE_TXD_INFO3_TRI_FRAME BIT(12) #define BE_TXD_INFO3_NULL_0 BIT(13) #define BE_TXD_INFO3_NULL_1 BIT(14) @@ -292,6 +304,8 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_INFO4_PUNC_MODE GENMASK(17, 16) #define BE_TXD_INFO4_SW_TX_OK_0 BIT(18) #define BE_TXD_INFO4_SW_TX_OK_1 BIT(19) +#define BE_TXD_INFO4_SW_EHT_NLTF_SWITCH BIT(20) +#define BE_TXD_INFO4_SW_EHT_NLTF GENMASK(22, 21) #define BE_TXD_INFO4_SW_TX_PWR_DBM GENMASK(26, 23) #define BE_TXD_INFO4_RTS_EN BIT(27) #define BE_TXD_INFO4_CTS2SELF BIT(28) @@ -308,6 +322,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_INFO6_UL_GI_LTF GENMASK(14, 12) #define BE_TXD_INFO6_UL_DOPPLER BIT(15) #define BE_TXD_INFO6_UL_STBC BIT(16) +#define BE_TXD_INFO6_UL_MU_MIMO_EN BIT(17) #define BE_TXD_INFO6_UL_LENGTH_REF GENMASK(21, 18) #define BE_TXD_INFO6_UL_RF_GAIN_IDX GENMASK(31, 22) @@ -322,6 +337,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_INFO7_UL_HELTF_SYMBOL_NUM GENMASK(19, 17) #define BE_TXD_INFO7_ULBW GENMASK(21, 20) #define BE_TXD_INFO7_ULBW_EXT GENMASK(23, 22) +#define BE_TXD_INFO7_UL_TRI_PAD_TSF BIT(24) #define BE_TXD_INFO7_USE_WD_UL GENMASK(25, 24) #define BE_TXD_INFO7_EXTEND_MODE_SEL GENMASK(31, 28) From 2b4a2fc32a475f3a3489cdb30889afe879c42429 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:03 +0800 Subject: [PATCH 50/81] wifi: rtw89: update query RXDESC v3 for RTL8922D Add RXDESC v3 to parse meta data of receiving packets for RTL8922D. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 73 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/core.h | 25 ++++++++ drivers/net/wireless/realtek/rtw89/txrx.h | 6 ++ 3 files changed, 104 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 3410fce22fbf..d8c3474da4b4 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3497,6 +3497,79 @@ void rtw89_core_query_rxdesc_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_core_query_rxdesc_v2); +void rtw89_core_query_rxdesc_v3(struct rtw89_dev *rtwdev, + struct rtw89_rx_desc_info *desc_info, + u8 *data, u32 data_offset) +{ + struct rtw89_rxdesc_phy_rpt_v2 *rxd_rpt; + struct rtw89_rxdesc_short_v3 *rxd_s; + struct rtw89_rxdesc_long_v3 *rxd_l; + u16 shift_len, drv_info_len, phy_rtp_len, hdr_cnv_len; + + rxd_s = (struct rtw89_rxdesc_short_v3 *)(data + data_offset); + + desc_info->pkt_size = le32_get_bits(rxd_s->dword0, BE_RXD_RPKT_LEN_MASK); + desc_info->drv_info_size = le32_get_bits(rxd_s->dword0, BE_RXD_DRV_INFO_SZ_MASK); + desc_info->phy_rpt_size = le32_get_bits(rxd_s->dword0, BE_RXD_PHY_RPT_SZ_MASK); + desc_info->hdr_cnv_size = le32_get_bits(rxd_s->dword0, BE_RXD_HDR_CNV_SZ_MASK); + desc_info->shift = le32_get_bits(rxd_s->dword0, BE_RXD_SHIFT_MASK); + desc_info->long_rxdesc = le32_get_bits(rxd_s->dword0, BE_RXD_LONG_RXD); + desc_info->pkt_type = le32_get_bits(rxd_s->dword0, BE_RXD_RPKT_TYPE_MASK); + desc_info->bb_sel = le32_get_bits(rxd_s->dword0, BE_RXD_BB_SEL); + if (desc_info->pkt_type == RTW89_CORE_RX_TYPE_PPDU_STAT) + desc_info->mac_info_valid = true; + + desc_info->frame_type = le32_get_bits(rxd_s->dword2, BE_RXD_TYPE_MASK); + desc_info->mac_id = le32_get_bits(rxd_s->dword2, BE_RXD_MAC_ID_V1); + desc_info->addr_cam_valid = le32_get_bits(rxd_s->dword2, BE_RXD_ADDR_CAM_VLD); + + desc_info->icv_err = le32_get_bits(rxd_s->dword3, BE_RXD_ICV_ERR); + desc_info->crc32_err = le32_get_bits(rxd_s->dword3, BE_RXD_CRC32_ERR); + desc_info->hw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_HW_DEC); + desc_info->sw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_SW_DEC); + desc_info->addr1_match = le32_get_bits(rxd_s->dword3, BE_RXD_A1_MATCH); + + desc_info->bw = le32_get_bits(rxd_s->dword4, BE_RXD_BW_MASK); + desc_info->data_rate = le32_get_bits(rxd_s->dword4, BE_RXD_RX_DATARATE_MASK); + desc_info->gi_ltf = le32_get_bits(rxd_s->dword4, BE_RXD_RX_GI_LTF_MASK); + desc_info->ppdu_cnt = le32_get_bits(rxd_s->dword4, BE_RXD_PPDU_CNT_MASK); + desc_info->ppdu_type = le32_get_bits(rxd_s->dword4, BE_RXD_PPDU_TYPE_MASK); + + desc_info->free_run_cnt = le32_to_cpu(rxd_s->dword5); + + shift_len = desc_info->shift << 1; /* 2-byte unit */ + drv_info_len = desc_info->drv_info_size << 3; /* 8-byte unit */ + phy_rtp_len = desc_info->phy_rpt_size << 3; /* 8-byte unit */ + hdr_cnv_len = desc_info->hdr_cnv_size << 4; /* 16-byte unit */ + desc_info->offset = data_offset + shift_len + drv_info_len + + phy_rtp_len + hdr_cnv_len; + + if (desc_info->long_rxdesc) + desc_info->rxd_len = sizeof(struct rtw89_rxdesc_long_v3); + else + desc_info->rxd_len = sizeof(struct rtw89_rxdesc_short_v3); + desc_info->ready = true; + + if (phy_rtp_len == sizeof(*rxd_rpt)) { + rxd_rpt = (struct rtw89_rxdesc_phy_rpt_v2 *)(data + data_offset + + desc_info->rxd_len); + desc_info->rssi = le32_get_bits(rxd_rpt->dword0, BE_RXD_PHY_RSSI); + } + + if (!desc_info->long_rxdesc) + return; + + rxd_l = (struct rtw89_rxdesc_long_v3 *)(data + data_offset); + + desc_info->sr_en = le32_get_bits(rxd_l->dword6, BE_RXD_SR_EN); + desc_info->user_id = le32_get_bits(rxd_l->dword6, BE_RXD_USER_ID_MASK); + desc_info->addr_cam_id = le32_get_bits(rxd_l->dword6, BE_RXD_ADDR_CAM_V1); + desc_info->sec_cam_id = le32_get_bits(rxd_l->dword6, BE_RXD_SEC_CAM_IDX_V1); + + desc_info->rx_pl_id = le32_get_bits(rxd_l->dword7, BE_RXD_RX_PL_ID_MASK); +} +EXPORT_SYMBOL(rtw89_core_query_rxdesc_v3); + struct rtw89_core_iter_rx_status { struct rtw89_dev *rtwdev; struct ieee80211_rx_status *rx_status; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c5d6c40ba3ce..40527354c95d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1137,6 +1137,15 @@ struct rtw89_rxdesc_short_v2 { __le32 dword5; } __packed; +struct rtw89_rxdesc_short_v3 { + __le32 dword0; + __le32 dword1; + __le32 dword2; + __le32 dword3; + __le32 dword4; + __le32 dword5; +} __packed; + struct rtw89_rxdesc_long { __le32 dword0; __le32 dword1; @@ -1161,6 +1170,19 @@ struct rtw89_rxdesc_long_v2 { __le32 dword9; } __packed; +struct rtw89_rxdesc_long_v3 { + __le32 dword0; + __le32 dword1; + __le32 dword2; + __le32 dword3; + __le32 dword4; + __le32 dword5; + __le32 dword6; + __le32 dword7; + __le32 dword8; + __le32 dword9; +} __packed; + struct rtw89_rxdesc_phy_rpt_v2 { __le32 dword0; __le32 dword1; @@ -7614,6 +7636,9 @@ void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev, void rtw89_core_query_rxdesc_v2(struct rtw89_dev *rtwdev, struct rtw89_rx_desc_info *desc_info, u8 *data, u32 data_offset); +void rtw89_core_query_rxdesc_v3(struct rtw89_dev *rtwdev, + struct rtw89_rx_desc_info *desc_info, + u8 *data, u32 data_offset); void rtw89_core_napi_start(struct rtw89_dev *rtwdev); void rtw89_core_napi_stop(struct rtw89_dev *rtwdev); int rtw89_core_napi_init(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index c92e25f8a2b5..b69a2529aefc 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -504,6 +504,7 @@ struct rtw89_phy_sts_iehdr { /* BE RXD dword2 */ #define BE_RXD_MAC_ID_MASK GENMASK(7, 0) +#define BE_RXD_MAC_ID_V1 GENMASK(9, 0) #define BE_RXD_TYPE_MASK GENMASK(11, 10) #define BE_RXD_LAST_MSDU BIT(12) #define BE_RXD_AMSDU_CUT BIT(13) @@ -535,6 +536,7 @@ struct rtw89_phy_sts_iehdr { #define BE_RXD_QNULL BIT(22) #define BE_RXD_A4_FRAME BIT(23) #define BE_RXD_FRAG_MASK GENMASK(27, 24) +#define BE_RXD_GET_CH_INFO_V2 GENMASK(31, 29) #define BE_RXD_GET_CH_INFO_V1_MASK GENMASK(31, 30) /* BE RXD dword4 */ @@ -550,10 +552,14 @@ struct rtw89_phy_sts_iehdr { /* BE RXD dword6 */ #define BE_RXD_ADDR_CAM_MASK GENMASK(7, 0) +#define BE_RXD_ADDR_CAM_V1 GENMASK(9, 0) +#define BE_RXD_RX_STATISTICS_V1 BIT(11) +#define BE_RXD_SMART_ANT_V1 BIT(12) #define BE_RXD_SR_EN BIT(13) #define BE_RXD_NON_SRG_PPDU BIT(14) #define BE_RXD_INTER_PPDU BIT(15) #define BE_RXD_USER_ID_MASK GENMASK(21, 16) +#define BE_RXD_SEC_CAM_IDX_V1 GENMASK(31, 22) #define BE_RXD_RX_STATISTICS BIT(22) #define BE_RXD_SMART_ANT BIT(23) #define BE_RXD_SEC_CAM_IDX_MASK GENMASK(31, 24) From 49218572f3312c7ff2fa3fb13e1e13b108aa856c Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:04 +0800 Subject: [PATCH 51/81] wifi: rtw89: fw: add DMAC v3 H2C command for RTL8922D Write association data including address and security key of peer to hardware. Add the command for RTL8922D accordingly. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/cam.c | 134 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/cam.h | 129 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.c | 95 ++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 7 ++ 4 files changed, 365 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index 9370cbda945c..9f63d67777fa 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -1140,3 +1140,137 @@ void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, le32_encode_bits(mld_bssid[5], DCTLINFO_V2_W12_MLD_BSSID_5); h2c->m12 = cpu_to_le32(DCTLINFO_V2_W12_ALL); } + +void rtw89_cam_fill_dctl_sec_cam_info_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct rtw89_h2c_dctlinfo_ud_v3 *h2c) +{ + struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link); + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif_link->rtwvif); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct rtw89_addr_cam_entry *addr_cam = + rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); + bool is_mld = sta ? sta->mlo : ieee80211_vif_is_mld(vif); + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv; + u8 *mld_sma, *mld_tma, *mld_bssid; + + h2c->c0 = le32_encode_bits(rtwsta_link ? rtwsta_link->mac_id : + rtwvif_link->mac_id, + DCTLINFO_V3_C0_MACID) | + le32_encode_bits(1, DCTLINFO_V3_C0_OP); + + h2c->w2 = le32_encode_bits(is_mld, DCTLINFO_V3_W2_IS_MLD); + h2c->m2 = cpu_to_le32(DCTLINFO_V3_W2_IS_MLD); + + h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0], + DCTLINFO_V3_W4_SEC_ENT0_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[1], + DCTLINFO_V3_W4_SEC_ENT1_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[2], + DCTLINFO_V3_W4_SEC_ENT2_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[3], + DCTLINFO_V3_W4_SEC_ENT3_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[4], + DCTLINFO_V3_W4_SEC_ENT4_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[5], + DCTLINFO_V3_W4_SEC_ENT5_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[6], + DCTLINFO_V3_W4_SEC_ENT6_KEYID); + h2c->m4 = cpu_to_le32(DCTLINFO_V3_W4_SEC_ENT0_KEYID | + DCTLINFO_V3_W4_SEC_ENT1_KEYID | + DCTLINFO_V3_W4_SEC_ENT2_KEYID | + DCTLINFO_V3_W4_SEC_ENT3_KEYID | + DCTLINFO_V3_W4_SEC_ENT4_KEYID | + DCTLINFO_V3_W4_SEC_ENT5_KEYID | + DCTLINFO_V3_W4_SEC_ENT6_KEYID); + + h2c->w5 = le32_encode_bits(addr_cam->sec_cam_map[0], + DCTLINFO_V3_W5_SEC_ENT_VALID_V1); + h2c->m5 = cpu_to_le32(DCTLINFO_V3_W5_SEC_ENT_VALID_V1); + + h2c->w6 = le32_encode_bits(addr_cam->sec_ent[0], + DCTLINFO_V3_W6_SEC_ENT0_V2) | + le32_encode_bits(addr_cam->sec_ent[1], + DCTLINFO_V3_W6_SEC_ENT1_V2) | + le32_encode_bits(addr_cam->sec_ent[2], + DCTLINFO_V3_W6_SEC_ENT2_V2); + h2c->m6 = cpu_to_le32(DCTLINFO_V3_W6_SEC_ENT0_V2 | + DCTLINFO_V3_W6_SEC_ENT1_V2 | + DCTLINFO_V3_W6_SEC_ENT2_V2); + + h2c->w7 = le32_encode_bits(addr_cam->sec_ent[3], + DCTLINFO_V3_W7_SEC_ENT3_V2) | + le32_encode_bits(addr_cam->sec_ent[4], + DCTLINFO_V3_W7_SEC_ENT4_V2) | + le32_encode_bits(addr_cam->sec_ent[5], + DCTLINFO_V3_W7_SEC_ENT5_V2); + h2c->m7 = cpu_to_le32(DCTLINFO_V3_W7_SEC_ENT3_V2 | + DCTLINFO_V3_W7_SEC_ENT4_V2 | + DCTLINFO_V3_W7_SEC_ENT5_V2); + + h2c->w8 = le32_encode_bits(addr_cam->sec_ent[6], + DCTLINFO_V3_W8_SEC_ENT6_V2); + h2c->m8 = cpu_to_le32(DCTLINFO_V3_W8_SEC_ENT6_V2); + + if (rtw_wow->ptk_alg) { + h2c->w0 = le32_encode_bits(ptk_tx_iv[0] | ptk_tx_iv[1] << 8, + DCTLINFO_V3_W0_AES_IV_L); + h2c->m0 = cpu_to_le32(DCTLINFO_V3_W0_AES_IV_L); + + h2c->w1 = le32_encode_bits(ptk_tx_iv[4] | + ptk_tx_iv[5] << 8 | + ptk_tx_iv[6] << 16 | + ptk_tx_iv[7] << 24, + DCTLINFO_V3_W1_AES_IV_H); + h2c->m1 = cpu_to_le32(DCTLINFO_V3_W1_AES_IV_H); + + h2c->w4 |= le32_encode_bits(rtw_wow->ptk_keyidx, + DCTLINFO_V3_W4_SEC_KEY_ID); + h2c->m4 |= cpu_to_le32(DCTLINFO_V3_W4_SEC_KEY_ID); + } + + if (!is_mld) + return; + + if (rtwvif_link->net_type == RTW89_NET_TYPE_INFRA) { + mld_sma = rtwvif->mac_addr; + mld_tma = vif->cfg.ap_addr; + mld_bssid = vif->cfg.ap_addr; + } else if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE && sta) { + mld_sma = rtwvif->mac_addr; + mld_tma = sta->addr; + mld_bssid = rtwvif->mac_addr; + } else { + return; + } + + h2c->w9 = le32_encode_bits(mld_sma[0], DCTLINFO_V3_W9_MLD_SMA_0_V2) | + le32_encode_bits(mld_sma[1], DCTLINFO_V3_W9_MLD_SMA_1_V2) | + le32_encode_bits(mld_sma[2], DCTLINFO_V3_W9_MLD_SMA_2_V2) | + le32_encode_bits(mld_sma[3], DCTLINFO_V3_W9_MLD_SMA_3_V2); + h2c->m9 = cpu_to_le32(DCTLINFO_V3_W9_ALL); + + h2c->w10 = le32_encode_bits(mld_sma[4], DCTLINFO_V3_W10_MLD_SMA_4_V2) | + le32_encode_bits(mld_sma[5], DCTLINFO_V3_W10_MLD_SMA_5_V2) | + le32_encode_bits(mld_tma[0], DCTLINFO_V3_W10_MLD_TMA_0_V2) | + le32_encode_bits(mld_tma[1], DCTLINFO_V3_W10_MLD_TMA_1_V2); + h2c->m10 = cpu_to_le32(DCTLINFO_V3_W10_ALL); + + h2c->w11 = le32_encode_bits(mld_tma[2], DCTLINFO_V3_W11_MLD_TMA_2_V2) | + le32_encode_bits(mld_tma[3], DCTLINFO_V3_W11_MLD_TMA_3_V2) | + le32_encode_bits(mld_tma[4], DCTLINFO_V3_W11_MLD_TMA_4_V2) | + le32_encode_bits(mld_tma[5], DCTLINFO_V3_W11_MLD_TMA_5_V2); + h2c->m11 = cpu_to_le32(DCTLINFO_V3_W11_ALL); + + h2c->w12 = le32_encode_bits(mld_bssid[0], DCTLINFO_V3_W12_MLD_TA_BSSID_0_V2) | + le32_encode_bits(mld_bssid[1], DCTLINFO_V3_W12_MLD_TA_BSSID_1_V2) | + le32_encode_bits(mld_bssid[2], DCTLINFO_V3_W12_MLD_TA_BSSID_2_V2) | + le32_encode_bits(mld_bssid[3], DCTLINFO_V3_W12_MLD_TA_BSSID_3_V2); + h2c->m12 = cpu_to_le32(DCTLINFO_V3_W12_ALL); + + h2c->w13 = le32_encode_bits(mld_bssid[4], DCTLINFO_V3_W13_MLD_TA_BSSID_4_V2) | + le32_encode_bits(mld_bssid[5], DCTLINFO_V3_W13_MLD_TA_BSSID_5_V2); + h2c->m13 = cpu_to_le32(DCTLINFO_V3_W13_ALL); +} diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h index c46b6f91bbdb..22868f262243 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.h +++ b/drivers/net/wireless/realtek/rtw89/cam.h @@ -302,6 +302,131 @@ struct rtw89_h2c_dctlinfo_ud_v2 { #define DCTLINFO_V2_W12_MLD_BSSID_5 GENMASK(15, 8) #define DCTLINFO_V2_W12_ALL GENMASK(15, 0) +struct rtw89_h2c_dctlinfo_ud_v3 { + __le32 c0; + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; + __le32 w12; + __le32 w13; + __le32 w14; + __le32 w15; + __le32 m0; + __le32 m1; + __le32 m2; + __le32 m3; + __le32 m4; + __le32 m5; + __le32 m6; + __le32 m7; + __le32 m8; + __le32 m9; + __le32 m10; + __le32 m11; + __le32 m12; + __le32 m13; + __le32 m14; + __le32 m15; +} __packed; + +#define DCTLINFO_V3_C0_MACID GENMASK(15, 0) +#define DCTLINFO_V3_C0_OP BIT(16) + +#define DCTLINFO_V3_W0_QOS_FIELD_H GENMASK(7, 0) +#define DCTLINFO_V3_W0_HW_EXSEQ_MACID GENMASK(14, 8) +#define DCTLINFO_V3_W0_QOS_DATA BIT(15) +#define DCTLINFO_V3_W0_AES_IV_L GENMASK(31, 16) +#define DCTLINFO_V3_W0_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W1_AES_IV_H GENMASK(31, 0) +#define DCTLINFO_V3_W1_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W2_SEQ0 GENMASK(11, 0) +#define DCTLINFO_V3_W2_SEQ1 GENMASK(23, 12) +#define DCTLINFO_V3_W2_AMSDU_MAX_LEN GENMASK(26, 24) +#define DCTLINFO_V3_W2_STA_AMSDU_EN BIT(27) +#define DCTLINFO_V3_W2_CHKSUM_OFLD_EN BIT(28) +#define DCTLINFO_V3_W2_WITH_LLC BIT(29) +#define DCTLINFO_V3_W2_NAT25_EN BIT(30) +#define DCTLINFO_V3_W2_IS_MLD BIT(31) +#define DCTLINFO_V3_W2_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W3_SEQ2 GENMASK(11, 0) +#define DCTLINFO_V3_W3_SEQ3 GENMASK(23, 12) +#define DCTLINFO_V3_W3_TGT_IND GENMASK(27, 24) +#define DCTLINFO_V3_W3_TGT_IND_EN BIT(28) +#define DCTLINFO_V3_W3_HTC_LB GENMASK(31, 29) +#define DCTLINFO_V3_W3_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W4_VLAN_TAG_SEL GENMASK(7, 5) +#define DCTLINFO_V3_W4_HTC_ORDER BIT(8) +#define DCTLINFO_V3_W4_SEC_KEY_ID GENMASK(10, 9) +#define DCTLINFO_V3_W4_VLAN_RX_DYNAMIC_PCP_EN BIT(11) +#define DCTLINFO_V3_W4_VLAN_RX_PKT_DROP BIT(12) +#define DCTLINFO_V3_W4_VLAN_RX_VALID BIT(13) +#define DCTLINFO_V3_W4_VLAN_TX_VALID BIT(14) +#define DCTLINFO_V3_W4_WAPI BIT(15) +#define DCTLINFO_V3_W4_SEC_ENT_MODE GENMASK(17, 16) +#define DCTLINFO_V3_W4_SEC_ENT0_KEYID GENMASK(19, 18) +#define DCTLINFO_V3_W4_SEC_ENT1_KEYID GENMASK(21, 20) +#define DCTLINFO_V3_W4_SEC_ENT2_KEYID GENMASK(23, 22) +#define DCTLINFO_V3_W4_SEC_ENT3_KEYID GENMASK(25, 24) +#define DCTLINFO_V3_W4_SEC_ENT4_KEYID GENMASK(27, 26) +#define DCTLINFO_V3_W4_SEC_ENT5_KEYID GENMASK(29, 28) +#define DCTLINFO_V3_W4_SEC_ENT6_KEYID GENMASK(31, 30) +#define DCTLINFO_V3_W4_ALL GENMASK(31, 5) +#define DCTLINFO_V3_W5_SEC_ENT7_KEYID GENMASK(1, 0) +#define DCTLINFO_V3_W5_SEC_ENT8_KEYID GENMASK(3, 2) +#define DCTLINFO_V3_W5_SEC_ENT_VALID_V1 GENMASK(23, 8) +#define DCTLINFO_V3_W5_ALL (GENMASK(23, 8) | GENMASK(3, 0)) +#define DCTLINFO_V3_W6_SEC_ENT0_V2 GENMASK(8, 0) +#define DCTLINFO_V3_W6_SEC_ENT1_V2 GENMASK(18, 10) +#define DCTLINFO_V3_W6_SEC_ENT2_V2 GENMASK(28, 20) +#define DCTLINFO_V3_W6_ALL GENMASK(28, 0) +#define DCTLINFO_V3_W7_SEC_ENT3_V2 GENMASK(8, 0) +#define DCTLINFO_V3_W7_SEC_ENT4_V2 GENMASK(18, 10) +#define DCTLINFO_V3_W7_SEC_ENT5_V2 GENMASK(28, 20) +#define DCTLINFO_V3_W7_ALL GENMASK(28, 0) +#define DCTLINFO_V3_W8_SEC_ENT6_V2 GENMASK(8, 0) +#define DCTLINFO_V3_W8_SEC_ENT7_V1 GENMASK(18, 10) +#define DCTLINFO_V3_W8_SEC_ENT8_V1 GENMASK(28, 20) +#define DCTLINFO_V3_W8_ALL GENMASK(28, 0) +#define DCTLINFO_V3_W9_MLD_SMA_0_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W9_MLD_SMA_1_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W9_MLD_SMA_2_V2 GENMASK(23, 16) +#define DCTLINFO_V3_W9_MLD_SMA_3_V2 GENMASK(31, 24) +#define DCTLINFO_V3_W9_MLD_SMA_L_V2 GENMASK(31, 0) +#define DCTLINFO_V3_W9_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W10_MLD_SMA_4_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W10_MLD_SMA_5_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W10_MLD_SMA_H_V2 GENMASK(15, 0) +#define DCTLINFO_V3_W10_MLD_TMA_0_V2 GENMASK(23, 16) +#define DCTLINFO_V3_W10_MLD_TMA_1_V2 GENMASK(31, 24) +#define DCTLINFO_V3_W10_MLD_TMA_L_V2 GENMASK(31, 16) +#define DCTLINFO_V3_W10_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W11_MLD_TMA_2_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W11_MLD_TMA_3_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W11_MLD_TMA_4_V2 GENMASK(23, 16) +#define DCTLINFO_V3_W11_MLD_TMA_5_V2 GENMASK(31, 24) +#define DCTLINFO_V3_W11_MLD_TMA_H_V2 GENMASK(31, 0) +#define DCTLINFO_V3_W11_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_0_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_1_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_2_V2 GENMASK(23, 16) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_3_V2 GENMASK(31, 24) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_L_V2 GENMASK(31, 0) +#define DCTLINFO_V3_W12_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W13_MLD_TA_BSSID_4_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W13_MLD_TA_BSSID_5_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W13_MLD_TA_BSSID_H_V2 GENMASK(15, 0) +#define DCTLINFO_V3_W13_HW_EXSEQ_MACID_V1 GENMASK(24, 16) +#define DCTLINFO_V3_W13_ALL GENMASK(24, 0) + int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, @@ -328,6 +453,10 @@ void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v2 *h2c); +void rtw89_cam_fill_dctl_sec_cam_info_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct rtw89_h2c_dctlinfo_ud_v3 *h2c); int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 24077a8095c4..db00a4d52af2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2315,6 +2315,45 @@ int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v2); +int rtw89_fw_h2c_dctl_sec_cam_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) +{ + struct rtw89_h2c_dctlinfo_ud_v3 *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 dctl sec cam\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_dctlinfo_ud_v3 *)skb->data; + + rtw89_cam_fill_dctl_sec_cam_info_v3(rtwdev, rtwvif_link, rtwsta_link, h2c); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_DCTLINFO_UD_V3, 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v3); + int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link) @@ -2370,6 +2409,62 @@ int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v2); +int rtw89_fw_h2c_default_dmac_tbl_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) +{ + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; + struct rtw89_h2c_dctlinfo_ud_v3 *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 dctl v2\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_dctlinfo_ud_v3 *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, DCTLINFO_V3_C0_MACID) | + le32_encode_bits(1, DCTLINFO_V3_C0_OP); + + h2c->m0 = cpu_to_le32(DCTLINFO_V3_W0_ALL); + h2c->m1 = cpu_to_le32(DCTLINFO_V3_W1_ALL); + h2c->m2 = cpu_to_le32(DCTLINFO_V3_W2_ALL); + h2c->m3 = cpu_to_le32(DCTLINFO_V3_W3_ALL); + h2c->m4 = cpu_to_le32(DCTLINFO_V3_W4_ALL); + h2c->m5 = cpu_to_le32(DCTLINFO_V3_W5_ALL); + h2c->m6 = cpu_to_le32(DCTLINFO_V3_W6_ALL); + h2c->m7 = cpu_to_le32(DCTLINFO_V3_W7_ALL); + h2c->m8 = cpu_to_le32(DCTLINFO_V3_W8_ALL); + h2c->m9 = cpu_to_le32(DCTLINFO_V3_W9_ALL); + h2c->m10 = cpu_to_le32(DCTLINFO_V3_W10_ALL); + h2c->m11 = cpu_to_le32(DCTLINFO_V3_W11_ALL); + h2c->m12 = cpu_to_le32(DCTLINFO_V3_W12_ALL); + h2c->m13 = cpu_to_le32(DCTLINFO_V3_W13_ALL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_DCTLINFO_UD_V3, 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v3); + int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 91eaf07f5824..1603b07ec868 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4335,6 +4335,7 @@ enum rtw89_ps_h2c_func { #define H2C_FUNC_MAC_CCTLINFO_UD_V1 0xa #define H2C_FUNC_MAC_DCTLINFO_UD_V2 0xc #define H2C_FUNC_MAC_BCN_UPD_BE 0xd +#define H2C_FUNC_MAC_DCTLINFO_UD_V3 0x10 #define H2C_FUNC_MAC_CCTLINFO_UD_G7 0x11 /* CLASS 6 - Address CAM */ @@ -4877,6 +4878,9 @@ int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_default_dmac_tbl_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); @@ -4911,6 +4915,9 @@ int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_dctl_sec_cam_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); void rtw89_fw_c2h_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev); From c73607b3a8ef537636deccda5eb3619554269350 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:05 +0800 Subject: [PATCH 52/81] wifi: rtw89: fw: add CMAC H2C command to initialize default value for RTL8922D CMAC H2C command is to configure CMAC such as TX retry and padding. Add to reset CMAC function block to default value. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 86 +++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 150 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 12 ++ 3 files changed, 248 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index db00a4d52af2..43c6ec47daa8 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3461,6 +3461,92 @@ int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_g7); +int rtw89_fw_h2c_default_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) +{ + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; + bool preld = rtw89_mac_chk_preload_allow(rtwdev); + struct rtw89_h2c_cctlinfo_ud_be *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 default cmac be\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + h2c->w0 = le32_encode_bits(4, BE_CCTL_INFO_W0_DATARATE); + h2c->m0 = cpu_to_le32(BE_CCTL_INFO_W0_ALL); + + h2c->w1 = le32_encode_bits(4, BE_CCTL_INFO_W1_DATA_RTY_LOWEST_RATE) | + le32_encode_bits(0xa, BE_CCTL_INFO_W1_RTSRATE) | + le32_encode_bits(4, BE_CCTL_INFO_W1_RTS_RTY_LOWEST_RATE); + h2c->m1 = cpu_to_le32(BE_CCTL_INFO_W1_ALL); + + h2c->w1 = le32_encode_bits(preld, BE_CCTL_INFO_W2_PRELOAD_ENABLE); + h2c->m2 = cpu_to_le32(BE_CCTL_INFO_W2_ALL); + + h2c->m3 = cpu_to_le32(BE_CCTL_INFO_W3_ALL); + + h2c->w4 = le32_encode_bits(0xFFFF, BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + h2c->m4 = cpu_to_le32(BE_CCTL_INFO_W4_ALL); + + h2c->w5 = le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING0_V1) | + le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING1_V1) | + le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING2_V1) | + le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING3_V1) | + le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING4_V1); + h2c->m5 = cpu_to_le32(BE_CCTL_INFO_W5_ALL); + + h2c->w6 = le32_encode_bits(0xb, BE_CCTL_INFO_W6_RESP_REF_RATE); + h2c->m6 = cpu_to_le32(BE_CCTL_INFO_W6_ALL); + + h2c->w7 = le32_encode_bits(1, BE_CCTL_INFO_W7_NC) | + le32_encode_bits(1, BE_CCTL_INFO_W7_NR) | + le32_encode_bits(1, BE_CCTL_INFO_W7_CB) | + le32_encode_bits(0x1, BE_CCTL_INFO_W7_CSI_PARA_EN) | + le32_encode_bits(0xb, BE_CCTL_INFO_W7_CSI_FIX_RATE); + h2c->m7 = cpu_to_le32(BE_CCTL_INFO_W7_ALL); + + h2c->m8 = cpu_to_le32(BE_CCTL_INFO_W8_ALL); + + h2c->w14 = le32_encode_bits(0, BE_CCTL_INFO_W14_VO_CURR_RATE) | + le32_encode_bits(0, BE_CCTL_INFO_W14_VI_CURR_RATE) | + le32_encode_bits(0, BE_CCTL_INFO_W14_BE_CURR_RATE_L); + h2c->m14 = cpu_to_le32(BE_CCTL_INFO_W14_ALL); + + h2c->w15 = le32_encode_bits(0, BE_CCTL_INFO_W15_BE_CURR_RATE_H) | + le32_encode_bits(0, BE_CCTL_INFO_W15_BK_CURR_RATE) | + le32_encode_bits(0, BE_CCTL_INFO_W15_MGNT_CURR_RATE); + h2c->m15 = cpu_to_le32(BE_CCTL_INFO_W15_ALL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_be); + static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, struct ieee80211_link_sta *link_sta, u8 *pads) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 1603b07ec868..f25c1d2493af 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1518,6 +1518,153 @@ struct rtw89_h2c_cctlinfo_ud_g7 { #define CCTLINFO_G7_W15_MGNT_CURR_RATE GENMASK(27, 16) #define CCTLINFO_G7_W15_ALL GENMASK(27, 0) +struct rtw89_h2c_cctlinfo_ud_be { + __le32 c0; + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; + __le32 w12; + __le32 w13; + __le32 w14; + __le32 w15; + __le32 m0; + __le32 m1; + __le32 m2; + __le32 m3; + __le32 m4; + __le32 m5; + __le32 m6; + __le32 m7; + __le32 m8; + __le32 m9; + __le32 m10; + __le32 m11; + __le32 m12; + __le32 m13; + __le32 m14; + __le32 m15; +} __packed; + +#define BE_CCTL_INFO_C0_V1_MACID GENMASK(9, 0) +#define BE_CCTL_INFO_C0_V1_OP BIT(10) + +#define BE_CCTL_INFO_W0_DATARATE GENMASK(11, 0) +#define BE_CCTL_INFO_W0_DATA_GI_LTF GENMASK(14, 12) +#define BE_CCTL_INFO_W0_TRYRATE BIT(15) +#define BE_CCTL_INFO_W0_ARFR_CTRL GENMASK(17, 16) +#define BE_CCTL_INFO_W0_DIS_HE1SS_STBC BIT(18) +#define BE_CCTL_INFO_W0_ACQ_RPT_EN BIT(20) +#define BE_CCTL_INFO_W0_MGQ_RPT_EN BIT(21) +#define BE_CCTL_INFO_W0_ULQ_RPT_EN BIT(22) +#define BE_CCTL_INFO_W0_TWTQ_RPT_EN BIT(23) +#define BE_CCTL_INFO_W0_FORCE_TXOP BIT(24) +#define BE_CCTL_INFO_W0_DISRTSFB BIT(25) +#define BE_CCTL_INFO_W0_DISDATAFB BIT(26) +#define BE_CCTL_INFO_W0_NSTR_EN BIT(27) +#define BE_CCTL_INFO_W0_AMPDU_DENSITY GENMASK(31, 28) +#define BE_CCTL_INFO_W0_ALL (GENMASK(31, 20) | GENMASK(18, 0)) +#define BE_CCTL_INFO_W1_DATA_RTY_LOWEST_RATE GENMASK(11, 0) +#define BE_CCTL_INFO_W1_RTS_TXCNT_LMT GENMASK(15, 12) +#define BE_CCTL_INFO_W1_RTSRATE GENMASK(27, 16) +#define BE_CCTL_INFO_W1_RTS_RTY_LOWEST_RATE GENMASK(31, 28) +#define BE_CCTL_INFO_W1_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W2_DATA_TX_CNT_LMT GENMASK(5, 0) +#define BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL BIT(6) +#define BE_CCTL_INFO_W2_MAX_AGG_NUM_SEL BIT(7) +#define BE_CCTL_INFO_W2_RTS_EN BIT(8) +#define BE_CCTL_INFO_W2_CTS2SELF_EN BIT(9) +#define BE_CCTL_INFO_W2_CCA_RTS GENMASK(11, 10) +#define BE_CCTL_INFO_W2_HW_RTS_EN BIT(12) +#define BE_CCTL_INFO_W2_RTS_DROP_DATA_MODE GENMASK(14, 13) +#define BE_CCTL_INFO_W2_PRELOAD_ENABLE BIT(15) +#define BE_CCTL_INFO_W2_AMPDU_MAX_LEN GENMASK(26, 16) +#define BE_CCTL_INFO_W2_UL_MU_DIS BIT(27) +#define BE_CCTL_INFO_W2_AMPDU_MAX_TIME GENMASK(31, 28) +#define BE_CCTL_INFO_W2_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W3_MAX_AGG_NUM GENMASK(7, 0) +#define BE_CCTL_INFO_W3_DATA_BW GENMASK(10, 8) +#define BE_CCTL_INFO_W3_DATA_BW_ER BIT(11) +#define BE_CCTL_INFO_W3_BA_BMAP GENMASK(14, 12) +#define BE_CCTL_INFO_W3_VCS_STBC BIT(15) +#define BE_CCTL_INFO_W3_VO_LFTIME_SEL GENMASK(18, 16) +#define BE_CCTL_INFO_W3_VI_LFTIME_SEL GENMASK(21, 19) +#define BE_CCTL_INFO_W3_BE_LFTIME_SEL GENMASK(24, 22) +#define BE_CCTL_INFO_W3_BK_LFTIME_SEL GENMASK(27, 25) +#define BE_CCTL_INFO_W3_AMPDU_TIME_SEL BIT(28) +#define BE_CCTL_INFO_W3_AMPDU_LEN_SEL BIT(29) +#define BE_CCTL_INFO_W3_RTS_TXCNT_LMT_SEL BIT(30) +#define BE_CCTL_INFO_W3_LSIG_TXOP_EN BIT(31) +#define BE_CCTL_INFO_W3_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W4_MULTI_PORT_ID GENMASK(2, 0) +#define BE_CCTL_INFO_W4_BYPASS_PUNC BIT(3) +#define BE_CCTL_INFO_W4_MBSSID GENMASK(7, 4) +#define BE_CCTL_INFO_W4_TID_DISABLE_V1 GENMASK(15, 8) +#define BE_CCTL_INFO_W4_ACT_SUBCH_CBW GENMASK(31, 16) +#define BE_CCTL_INFO_W4_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W5_ADDR_CAM_INDEX_V1 GENMASK(9, 0) +#define BE_CCTL_INFO_W5_SR_MCS_SU GENMASK(14, 10) +#define BE_CCTL_INFO_W5_A_CTRL_BQR_V1 BIT(15) +#define BE_CCTL_INFO_W5_A_CTRL_BSR_V1 BIT(16) +#define BE_CCTL_INFO_W5_A_CTRL_CAS_V1 BIT(17) +#define BE_CCTL_INFO_W5_DATA_ER_V1 BIT(18) +#define BE_CCTL_INFO_W5_DATA_DCM_V1 BIT(19) +#define BE_CCTL_INFO_W5_DATA_LDPC_V1 BIT(20) +#define BE_CCTL_INFO_W5_DATA_STBC_V1 BIT(21) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING0_V1 GENMASK(23, 22) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING1_V1 GENMASK(25, 24) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING2_V1 GENMASK(27, 26) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING3_V1 GENMASK(29, 28) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING4_V1 GENMASK(31, 30) +#define BE_CCTL_INFO_W5_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W6_AID12_PAID GENMASK(11, 0) +#define BE_CCTL_INFO_W6_RESP_REF_RATE GENMASK(23, 12) +#define BE_CCTL_INFO_W6_ULDL BIT(31) +#define BE_CCTL_INFO_W6_ALL (BIT(31) | GENMASK(23, 0)) +#define BE_CCTL_INFO_W7_NC GENMASK(2, 0) +#define BE_CCTL_INFO_W7_NR GENMASK(5, 3) +#define BE_CCTL_INFO_W7_NG GENMASK(7, 6) +#define BE_CCTL_INFO_W7_CB GENMASK(9, 8) +#define BE_CCTL_INFO_W7_CS GENMASK(11, 10) +#define BE_CCTL_INFO_W7_CSI_STBC_EN BIT(13) +#define BE_CCTL_INFO_W7_CSI_LDPC_EN BIT(14) +#define BE_CCTL_INFO_W7_CSI_PARA_EN BIT(15) +#define BE_CCTL_INFO_W7_CSI_FIX_RATE GENMASK(27, 16) +#define BE_CCTL_INFO_W7_CSI_BW GENMASK(31, 29) +#define BE_CCTL_INFO_W7_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W8_ALL_ACK_SUPPORT_V1 BIT(0) +#define BE_CCTL_INFO_W8_BSR_QUEUE_SIZE_FORMAT_V1 BIT(1) +#define BE_CCTL_INFO_W8_BSR_OM_UPD_EN_V1 BIT(2) +#define BE_CCTL_INFO_W8_MACID_FWD_IDC_V1 BIT(3) +#define BE_CCTL_INFO_W8_AZ_SEC_EN BIT(4) +#define BE_CCTL_INFO_W8_BF_SEC_EN BIT(5) +#define BE_CCTL_INFO_W8_FIX_UL_ADDRCAM_IDX_V1 BIT(6) +#define BE_CCTL_INFO_W8_CTRL_CNT_VLD_V1 BIT(7) +#define BE_CCTL_INFO_W8_CTRL_CNT_V1 GENMASK(11, 8) +#define BE_CCTL_INFO_W8_RESP_SEC_TYPE GENMASK(15, 12) +#define BE_CCTL_INFO_W8_ALL GENMASK(15, 0) +#define BE_CCTL_INFO_W9_EMLSR_TRANS_DLY GENMASK(2, 0) +#define BE_CCTL_INFO_W9_ALL GENMASK(2, 0) +#define BE_CCTL_INFO_W10_SW_EHT_NLTF GENMASK(1, 0) +#define BE_CCTL_INFO_W10_TB_MLO_MODE BIT(2) +#define BE_CCTL_INFO_W10_ALL GENMASK(2, 0) +#define BE_CCTL_INFO_W14_VO_CURR_RATE GENMASK(11, 0) +#define BE_CCTL_INFO_W14_VI_CURR_RATE GENMASK(23, 12) +#define BE_CCTL_INFO_W14_BE_CURR_RATE_L GENMASK(31, 24) +#define BE_CCTL_INFO_W14_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W15_BE_CURR_RATE_H GENMASK(3, 0) +#define BE_CCTL_INFO_W15_BK_CURR_RATE GENMASK(15, 4) +#define BE_CCTL_INFO_W15_MGNT_CURR_RATE GENMASK(27, 16) +#define BE_CCTL_INFO_W15_ALL GENMASK(27, 0) + struct rtw89_h2c_bcn_upd { __le32 w0; __le32 w1; @@ -4875,6 +5022,9 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_default_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 79755032df2c..0d9928f7ac8a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1737,4 +1737,16 @@ void rtw89_tx_rpt_skbs_purge(struct rtw89_dev *rtwdev) rtw89_tx_rpt_tx_status(rtwdev, skbs[i], RTW89_TX_MACID_DROP); } + +static inline bool rtw89_mac_chk_preload_allow(struct rtw89_dev *rtwdev) +{ + if (rtwdev->hci.type != RTW89_HCI_TYPE_PCIE) + return false; + + if (rtwdev->chip->chip_id == RTL8922D && rtwdev->hal.cid == RTL8922D_CID7090) + return true; + + return false; +} + #endif From 96f5ceb44875c3e243a3a62120dca0a78776efac Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:06 +0800 Subject: [PATCH 53/81] wifi: rtw89: fw: add CMAC H2C command for association for RTL8922D CMAC H2C command is to configure CMAC such as TX retry and padding. Add to update CMAC function block according to associated peer. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 128 ++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 3 + 2 files changed, 131 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 43c6ec47daa8..00ab803e6b0c 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3877,6 +3877,134 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_g7); +int rtw89_fw_h2c_assoc_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) +{ + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; + struct rtw89_h2c_cctlinfo_ud_be *h2c; + struct ieee80211_bss_conf *bss_conf; + struct ieee80211_link_sta *link_sta; + u8 pads[RTW89_PPE_BW_NUM]; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u16 lowest_rate; + int ret; + + memset(pads, 0, sizeof(pads)); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for assoc cmac be\n"); + return -ENOMEM; + } + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + + if (rtwsta_link) { + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (link_sta->eht_cap.has_eht) + __get_sta_eht_pkt_padding(rtwdev, link_sta, pads); + else if (link_sta->he_cap.has_he) + __get_sta_he_pkt_padding(rtwdev, link_sta, pads); + } + + if (vif->p2p) + lowest_rate = RTW89_HW_RATE_OFDM6; + else if (chan->band_type == RTW89_BAND_2G) + lowest_rate = RTW89_HW_RATE_CCK1; + else + lowest_rate = RTW89_HW_RATE_OFDM6; + + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + h2c->w0 = le32_encode_bits(1, BE_CCTL_INFO_W0_DISRTSFB) | + le32_encode_bits(1, BE_CCTL_INFO_W0_DISDATAFB); + h2c->m0 = cpu_to_le32(BE_CCTL_INFO_W0_DISRTSFB | + BE_CCTL_INFO_W0_DISDATAFB); + + h2c->w1 = le32_encode_bits(lowest_rate, BE_CCTL_INFO_W1_RTS_RTY_LOWEST_RATE); + h2c->m1 = cpu_to_le32(BE_CCTL_INFO_W1_RTS_RTY_LOWEST_RATE); + + h2c->w2 = le32_encode_bits(0, BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL); + h2c->m2 = cpu_to_le32(BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL); + + h2c->w3 = le32_encode_bits(0, BE_CCTL_INFO_W3_RTS_TXCNT_LMT_SEL); + h2c->m3 = cpu_to_le32(BE_CCTL_INFO_W3_RTS_TXCNT_LMT_SEL); + + h2c->w4 = le32_encode_bits(rtwvif_link->port, BE_CCTL_INFO_W4_MULTI_PORT_ID); + h2c->m4 = cpu_to_le32(BE_CCTL_INFO_W4_MULTI_PORT_ID); + + if (bss_conf->eht_support) { + u16 punct = bss_conf->chanreq.oper.punctured; + + h2c->w4 |= le32_encode_bits(~punct, + BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + h2c->m4 |= cpu_to_le32(BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + } + + h2c->w5 = le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_20], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING0_V1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_40], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING1_V1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_80], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING2_V1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_160], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING3_V1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_320], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING4_V1); + h2c->m5 = cpu_to_le32(BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING0_V1 | + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING1_V1 | + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING2_V1 | + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING3_V1 | + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING4_V1); + + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) { + h2c->w5 |= le32_encode_bits(0, BE_CCTL_INFO_W5_DATA_DCM_V1); + h2c->m5 |= cpu_to_le32(BE_CCTL_INFO_W5_DATA_DCM_V1); + } + + h2c->w6 = le32_encode_bits(vif->cfg.aid, BE_CCTL_INFO_W6_AID12_PAID) | + le32_encode_bits(vif->type == NL80211_IFTYPE_STATION ? 1 : 0, + BE_CCTL_INFO_W6_ULDL); + h2c->m6 = cpu_to_le32(BE_CCTL_INFO_W6_AID12_PAID | BE_CCTL_INFO_W6_ULDL); + + if (rtwsta_link) { + h2c->w8 = le32_encode_bits(link_sta->he_cap.has_he, + BE_CCTL_INFO_W8_BSR_QUEUE_SIZE_FORMAT_V1); + h2c->m8 = cpu_to_le32(BE_CCTL_INFO_W8_BSR_QUEUE_SIZE_FORMAT_V1); + } + + rcu_read_unlock(); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_be); + int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index f25c1d2493af..5da937de06bf 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -5037,6 +5037,9 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_assoc_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); From dfe3dea6b9a2d5756127e7ef9fa06042e2d0c648 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:07 +0800 Subject: [PATCH 54/81] wifi: rtw89: fw: add CMAC H2C command for TX AMPDU for RTL8922D CMAC H2C command is to configure CMAC such as TX retry and padding. Add to update CMAC function block while AMPDU is established. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 66 +++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 3 ++ 2 files changed, 69 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 00ab803e6b0c..1b2b6a66c669 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4071,6 +4071,72 @@ int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_g7); +int rtw89_fw_h2c_ampdu_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) +{ + struct rtw89_sta *rtwsta = rtwsta_link->rtwsta; + struct rtw89_h2c_cctlinfo_ud_be *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u16 agg_num = 0; + u8 ba_bmap = 0; + int ret; + u8 tid; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for ampdu cmac be\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + for_each_set_bit(tid, rtwsta->ampdu_map, IEEE80211_NUM_TIDS) { + if (agg_num == 0) + agg_num = rtwsta->ampdu_params[tid].agg_num; + else + agg_num = min(agg_num, rtwsta->ampdu_params[tid].agg_num); + } + + if (agg_num <= 0x20) + ba_bmap = 3; + else if (agg_num > 0x20 && agg_num <= 0x40) + ba_bmap = 0; + else if (agg_num > 0x40 && agg_num <= 0x80) + ba_bmap = 1; + else if (agg_num > 0x80 && agg_num <= 0x100) + ba_bmap = 2; + else if (agg_num > 0x100 && agg_num <= 0x200) + ba_bmap = 4; + else if (agg_num > 0x200 && agg_num <= 0x400) + ba_bmap = 5; + + h2c->c0 = le32_encode_bits(rtwsta_link->mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + h2c->w3 = le32_encode_bits(ba_bmap, BE_CCTL_INFO_W3_BA_BMAP); + h2c->m3 = cpu_to_le32(BE_CCTL_INFO_W3_BA_BMAP); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_be); + int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 5da937de06bf..b2ad180da68d 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -5043,6 +5043,9 @@ int rtw89_fw_h2c_assoc_cmac_tbl_be(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_ampdu_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txtime_cmac_tbl_g7(struct rtw89_dev *rtwdev, From eccf7b10785b7e9b32b5a7fcbf1f45b6db9a5ac5 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:08 +0800 Subject: [PATCH 55/81] wifi: rtw89: fw: add CMAC H2C command for TX time for RTL8922D CMAC H2C command is to configure CMAC such as TX retry and padding. Add to update CMAC function block when BT-coex want shorter TX time due to timeslot assignment, or when MCC want higher retry time to improve connection rate. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 54 +++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 2 + 2 files changed, 56 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 1b2b6a66c669..9346fb3447db 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4234,6 +4234,60 @@ int rtw89_fw_h2c_txtime_cmac_tbl_g7(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_txtime_cmac_tbl_g7); +int rtw89_fw_h2c_txtime_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) +{ + struct rtw89_h2c_cctlinfo_ud_be *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 txtime_cmac_be\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + h2c->c0 = le32_encode_bits(rtwsta_link->mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + if (rtwsta_link->cctl_tx_time) { + h2c->w3 |= le32_encode_bits(1, BE_CCTL_INFO_W3_AMPDU_TIME_SEL); + h2c->m3 |= cpu_to_le32(BE_CCTL_INFO_W3_AMPDU_TIME_SEL); + + h2c->w2 |= le32_encode_bits(rtwsta_link->ampdu_max_time, + BE_CCTL_INFO_W2_AMPDU_MAX_TIME); + h2c->m2 |= cpu_to_le32(BE_CCTL_INFO_W2_AMPDU_MAX_TIME); + } + if (rtwsta_link->cctl_tx_retry_limit) { + h2c->w2 |= le32_encode_bits(1, BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL) | + le32_encode_bits(rtwsta_link->data_tx_cnt_lmt, + BE_CCTL_INFO_W2_DATA_TX_CNT_LMT); + h2c->m2 |= cpu_to_le32(BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL | + BE_CCTL_INFO_W2_DATA_TX_CNT_LMT); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_txtime_cmac_tbl_be); + int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u16 punctured) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b2ad180da68d..9877c26f33d4 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -5050,6 +5050,8 @@ int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txtime_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_txtime_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u16 punctured); From 1ddebb8f6e0476f335ce951b21bdf63a31d86ac9 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:09 +0800 Subject: [PATCH 56/81] wifi: rtw89: fw: add CMAC H2C command for punctured for RTL8922D CMAC H2C command is to configure CMAC such as TX retry and padding. Add to update CMAC function block while puncturing is changing. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 42 +++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 3 ++ 2 files changed, 45 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 9346fb3447db..5d114c4a7c1e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4331,6 +4331,48 @@ int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_punctured_cmac_tbl_g7); +int rtw89_fw_h2c_punctured_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured) +{ + struct rtw89_h2c_cctlinfo_ud_be *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for punctured cmac be\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + h2c->c0 = le32_encode_bits(rtwvif_link->mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + h2c->w4 = le32_encode_bits(~punctured, BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + h2c->m4 = cpu_to_le32(BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_punctured_cmac_tbl_be); + int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 9877c26f33d4..760730da07eb 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -5055,6 +5055,9 @@ int rtw89_fw_h2c_txtime_cmac_tbl_be(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u16 punctured); +int rtw89_fw_h2c_punctured_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, From 483539d891105195dca519c117895d74e7de7bc9 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:10 +0800 Subject: [PATCH 57/81] wifi: rtw89: fw: consider hardware AID for firmware elements The coming chip RTL8922D has variant of hardware with different AID. Add AID field to header of firmware elements, and compare AID with the value read from hardware. Currently, apply this rule to BB and RF parameters. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 40 ++++++++++++++++--------- drivers/net/wireless/realtek/rtw89/fw.h | 3 +- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 5d114c4a7c1e..03659f07de8c 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1061,42 +1061,47 @@ int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev, const union rtw89_fw_element_arg arg) { struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; - struct rtw89_phy_table *tbl; + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_phy_table *tbl, **pp; struct rtw89_reg2_def *regs; - enum rtw89_rf_path rf_path; + bool radio = false; u32 n_regs, i; + u16 aid; u8 idx; - tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); - if (!tbl) - return -ENOMEM; - switch (le32_to_cpu(elm->id)) { case RTW89_FW_ELEMENT_ID_BB_REG: - elm_info->bb_tbl = tbl; + pp = &elm_info->bb_tbl; break; case RTW89_FW_ELEMENT_ID_BB_GAIN: - elm_info->bb_gain = tbl; + pp = &elm_info->bb_gain; break; case RTW89_FW_ELEMENT_ID_RADIO_A: case RTW89_FW_ELEMENT_ID_RADIO_B: case RTW89_FW_ELEMENT_ID_RADIO_C: case RTW89_FW_ELEMENT_ID_RADIO_D: - rf_path = arg.rf_path; idx = elm->u.reg2.idx; + pp = &elm_info->rf_radio[idx]; - elm_info->rf_radio[idx] = tbl; - tbl->rf_path = rf_path; - tbl->config = rtw89_phy_config_rf_reg_v1; + radio = true; break; case RTW89_FW_ELEMENT_ID_RF_NCTL: - elm_info->rf_nctl = tbl; + pp = &elm_info->rf_nctl; break; default: - kfree(tbl); return -ENOENT; } + aid = le16_to_cpu(elm->aid); + if (aid && aid != hal->aid) + return 1; /* ignore if aid not matched */ + else if (*pp) + return 1; /* ignore if an element is existing */ + + tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); + if (!tbl) + return -ENOMEM; + n_regs = le32_to_cpu(elm->size) / sizeof(tbl->regs[0]); regs = kcalloc(n_regs, sizeof(*regs), GFP_KERNEL); if (!regs) @@ -1110,6 +1115,13 @@ int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev, tbl->n_regs = n_regs; tbl->regs = regs; + if (radio) { + tbl->rf_path = arg.rf_path; + tbl->config = rtw89_phy_config_rf_reg_v1; + } + + *pp = tbl; + return 0; out: diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 760730da07eb..1542634f0146 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4311,7 +4311,8 @@ struct rtw89_fw_element_hdr { __le32 id; /* enum rtw89_fw_element_id */ __le32 size; /* exclude header size */ u8 ver[4]; - __le32 rsvd0; + __le16 aid; /* should match rtw89_hal::aid */ + __le16 rsvd0; __le32 rsvd1; __le32 rsvd2; union { From 5fbc19b0f62b21abfef55c55258146bc014ba3f9 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 6 Jan 2026 11:09:11 +0800 Subject: [PATCH 58/81] wifi: rtw89: fw: set RACK bit every 4 H2C command for WiFi 6 chips only RACK is to ask firmware send received ACK to driver when a H2C command is received. This is necessary for WiFi 6 chips only. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260106030911.15528-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 03659f07de8c..f09387e089a2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1541,11 +1541,12 @@ void rtw89_h2c_pkt_set_hdr(struct rtw89_dev *rtwdev, struct sk_buff *skb, u8 type, u8 cat, u8 class, u8 func, bool rack, bool dack, u32 len) { + const struct rtw89_chip_info *chip = rtwdev->chip; struct fwcmd_hdr *hdr; hdr = (struct fwcmd_hdr *)skb_push(skb, 8); - if (!(rtwdev->fw.h2c_seq % 4)) + if (chip->chip_gen == RTW89_CHIP_AX && !(rtwdev->fw.h2c_seq % 4)) rack = true; hdr->hdr0 = cpu_to_le32(FIELD_PREP(H2C_HDR_DEL_TYPE, type) | FIELD_PREP(H2C_HDR_CAT, cat) | From 95052ab2d7949e5b1b1bee4fe87f059182dbcf11 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:08 +0800 Subject: [PATCH 59/81] wifi: rtw89: coex: make coex scoreboard as chip info The coex scoreboard is to exchange WiFi and BT profiles, and the coming chip 8922D changes the design including extend to two scoreboards and individual register for cfg/get. Follow the changes to abstract current code, but not change logic for existing chips at all. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 8 ++++++++ drivers/net/wireless/realtek/rtw89/mac.c | 16 +++++++++++----- drivers/net/wireless/realtek/rtw89/reg.h | 4 ++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852bt.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 + 9 files changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 40527354c95d..4c39c4dbaf56 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4360,6 +4360,13 @@ struct rtw89_rfkill_regs { struct rtw89_reg3_def mode; }; +struct rtw89_sb_regs { + struct { + u32 cfg; + u32 get; + } n[2]; +}; + struct rtw89_dig_regs { u32 seg0_pd_reg; u32 pd_lower_bound_mask; @@ -4577,6 +4584,7 @@ struct rtw89_chip_info { u32 bss_clr_map_reg; const struct rtw89_rfkill_regs *rfkill_init; struct rtw89_reg_def rfkill_get; + struct rtw89_sb_regs btc_sb; u32 dma_ch_mask; const struct rtw89_edcca_regs *edcca_regs; const struct wiphy_wowlan_support *wowlan_stub; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 1375ab324a8b..1a53824f58b5 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1498,6 +1498,7 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_pwr_cfg * const *cfg_seq; int (*cfg_func)(struct rtw89_dev *rtwdev); + u32 reg = chip->btc_sb.n[0].cfg; int ret; rtw89_mac_power_switch_boot_mode(rtwdev); @@ -1537,14 +1538,14 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) set_bit(RTW89_FLAG_POWERON, rtwdev->flags); set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); - rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_TP_MAJOR); + rtw89_write8(rtwdev, reg + 3, MAC_AX_NOTIFY_TP_MAJOR); } else { clear_bit(RTW89_FLAG_POWERON, rtwdev->flags); clear_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); - rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_PWR_MAJOR); + rtw89_write8(rtwdev, reg + 3, MAC_AX_NOTIFY_PWR_MAJOR); rtw89_set_entity_state(rtwdev, RTW89_PHY_0, false); rtw89_set_entity_state(rtwdev, RTW89_PHY_1, false); } @@ -6413,9 +6414,11 @@ int rtw89_mac_cfg_plt_ax(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) void rtw89_mac_cfg_sb(struct rtw89_dev *rtwdev, u32 val) { + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 reg = chip->btc_sb.n[0].cfg; u32 fw_sb; - fw_sb = rtw89_read32(rtwdev, R_AX_SCOREBOARD); + fw_sb = rtw89_read32(rtwdev, reg); fw_sb = FIELD_GET(B_MAC_AX_SB_FW_MASK, fw_sb); fw_sb = fw_sb & ~B_MAC_AX_BTGS1_NOTIFY; if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) @@ -6426,13 +6429,16 @@ void rtw89_mac_cfg_sb(struct rtw89_dev *rtwdev, u32 val) val = B_AX_TOGGLE | FIELD_PREP(B_MAC_AX_SB_DRV_MASK, val) | FIELD_PREP(B_MAC_AX_SB_FW_MASK, fw_sb); - rtw89_write32(rtwdev, R_AX_SCOREBOARD, val); + rtw89_write32(rtwdev, reg, val); fsleep(1000); /* avoid BT FW loss information */ } u32 rtw89_mac_get_sb(struct rtw89_dev *rtwdev) { - return rtw89_read32(rtwdev, R_AX_SCOREBOARD); + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 reg = chip->btc_sb.n[0].get; + + return rtw89_read32(rtwdev, reg); } int rtw89_mac_cfg_ctrl_path(struct rtw89_dev *rtwdev, bool wl) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 9f963bd85f02..afe13c0c5629 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4220,6 +4220,10 @@ #define B_BE_EF_DSB_EN BIT(11) #define B_BE_EF_DLY_SEL_MASK GENMASK(3, 0) +#define R_BE_SCOREBOARD 0x00AC +#define B_BE_TOGGLE BIT(31) +#define B_BE_DATA_LINE_MASK GENMASK(30, 0) + #define R_BE_PMC_DBG_CTRL2 0x00CC #define B_BE_EFUSE_BURN_GNT_MASK GENMASK(31, 24) #define B_BE_DIS_IOWRAP_TIMEOUT BIT(16) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index e06e70751735..0383d3b5c7bc 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2707,6 +2707,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .rfkill_init = &rtw8851b_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index bb12982afef7..329fc0a7b07b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2394,6 +2394,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP, .rfkill_init = &rtw8852a_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = 0, .edcca_regs = &rtw8852a_edcca_regs, #ifdef CONFIG_PM diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index a138d89bce84..f44674a39e30 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -1041,6 +1041,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .rfkill_init = &rtw8852b_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 7b637483e9b4..ab60ed389ff7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -878,6 +878,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .rfkill_init = &rtw8852bt_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index a82bbe3ec901..d2138be3640d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -3239,6 +3239,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP, .rfkill_init = &rtw8852c_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = 0, .edcca_regs = &rtw8852c_edcca_regs, #ifdef CONFIG_PM diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 041ffec9a327..6d2cd914e16e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -3005,6 +3005,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP_V2, .rfkill_init = &rtw8922a_rfkill_regs, .rfkill_get = {R_BE_GPIO_EXT_CTRL, B_BE_GPIO_IN_9}, + .btc_sb = {{{R_BE_SCOREBOARD, R_BE_SCOREBOARD},}}, .dma_ch_mask = 0, .edcca_regs = &rtw8922a_edcca_regs, #ifdef CONFIG_PM From ed2feda12f36a9c3916c0059c26b8b48cc0a9b6a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:09 +0800 Subject: [PATCH 60/81] wifi: rtw89: coex: update scoreboard value according to power state for two BT Assign timeslot to WiFi if power state is on. Since firmware isn't working at this moment, write scoreboard register to notify BT. Extend the code to support two BT for coming chips. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 1a53824f58b5..be478540f742 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1492,13 +1492,27 @@ static int rtw89_mac_pwr_off_func_for_unplugged(struct rtw89_dev *rtwdev) return 0; } +static void rtw89_mac_update_scoreboard(struct rtw89_dev *rtwdev, u8 val) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 reg; + int i; + + for (i = 0; i < ARRAY_SIZE(chip->btc_sb.n); i++) { + reg = chip->btc_sb.n[i].cfg; + if (!reg) + continue; + + rtw89_write8(rtwdev, reg + 3, val); + } +} + static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_pwr_cfg * const *cfg_seq; int (*cfg_func)(struct rtw89_dev *rtwdev); - u32 reg = chip->btc_sb.n[0].cfg; int ret; rtw89_mac_power_switch_boot_mode(rtwdev); @@ -1538,14 +1552,16 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) set_bit(RTW89_FLAG_POWERON, rtwdev->flags); set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); - rtw89_write8(rtwdev, reg + 3, MAC_AX_NOTIFY_TP_MAJOR); + + rtw89_mac_update_scoreboard(rtwdev, MAC_AX_NOTIFY_TP_MAJOR); } else { clear_bit(RTW89_FLAG_POWERON, rtwdev->flags); clear_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); - rtw89_write8(rtwdev, reg + 3, MAC_AX_NOTIFY_PWR_MAJOR); + + rtw89_mac_update_scoreboard(rtwdev, MAC_AX_NOTIFY_PWR_MAJOR); rtw89_set_entity_state(rtwdev, RTW89_PHY_0, false); rtw89_set_entity_state(rtwdev, RTW89_PHY_1, false); } From 286bb07889c1b8d1a7aaf212841c4472aab85ba7 Mon Sep 17 00:00:00 2001 From: Chia-Yuan Li Date: Thu, 8 Jan 2026 20:03:10 +0800 Subject: [PATCH 61/81] wifi: rtw89: coex: update coex software control for RTL8922D Update software control API due to 8922D PTA hardware changes. Signed-off-by: Chia-Yuan Li Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.h | 2 + drivers/net/wireless/realtek/rtw89/mac_be.c | 59 +++++++++++++++++- drivers/net/wireless/realtek/rtw89/reg.h | 69 +++++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 0d9928f7ac8a..1240e1cc1c10 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1358,6 +1358,8 @@ int rtw89_mac_cfg_gnt_v1(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); int rtw89_mac_cfg_gnt_v2(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); +int rtw89_mac_cfg_gnt_v3(struct rtw89_dev *rtwdev, + const struct rtw89_mac_ax_coex_gnt *gnt_cfg); static inline int rtw89_mac_cfg_plt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 0b29f43b38bd..06538122c57a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2003,12 +2003,65 @@ int rtw89_mac_cfg_gnt_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_mac_cfg_gnt_v2); +int rtw89_mac_cfg_gnt_v3(struct rtw89_dev *rtwdev, + const struct rtw89_mac_ax_coex_gnt *gnt_cfg) +{ + u32 val = 0; + + if (gnt_cfg->band[0].gnt_bt) + val |= B_BE_PTA_GNT_BT0_BB_VAL | B_BE_PTA_GNT_BT0_RX_BB0_VAL | + B_BE_PTA_GNT_BT0_TX_BB0_VAL; + + if (gnt_cfg->band[0].gnt_bt_sw_en) + val |= B_BE_PTA_GNT_BT0_BB_SWCTRL | B_BE_PTA_GNT_BT0_RX_BB0_SWCTRL | + B_BE_PTA_GNT_BT0_TX_BB0_SWCTRL; + + if (gnt_cfg->band[0].gnt_wl) + val |= B_BE_PTA_GNT_WL_BB0_VAL; + + if (gnt_cfg->band[0].gnt_wl_sw_en) + val |= B_BE_PTA_GNT_WL_BB0_SWCTRL; + + if (gnt_cfg->band[1].gnt_bt) + val |= B_BE_PTA_GNT_BT0_BB_VAL | B_BE_PTA_GNT_BT0_RX_BB1_VAL | + B_BE_PTA_GNT_BT0_TX_BB1_VAL; + + if (gnt_cfg->band[1].gnt_bt_sw_en) + val |= B_BE_PTA_GNT_BT0_BB_SWCTRL | B_BE_PTA_GNT_BT0_RX_BB1_SWCTRL | + B_BE_PTA_GNT_BT0_TX_BB1_SWCTRL; + + if (gnt_cfg->band[1].gnt_wl) + val |= B_BE_PTA_GNT_WL_BB1_VAL; + + if (gnt_cfg->band[1].gnt_wl_sw_en) + val |= B_BE_PTA_GNT_WL_BB1_SWCTRL; + + if (gnt_cfg->bt[0].wlan_act_en) + val |= B_BE_PTA_WL_ACT0_SWCTRL | B_BE_PTA_WL_ACT_RX_BT0_SWCTRL | + B_BE_PTA_WL_ACT_TX_BT0_SWCTRL; + if (gnt_cfg->bt[0].wlan_act) + val |= B_BE_PTA_WL_ACT0_VAL | B_BE_PTA_WL_ACT_RX_BT0_VAL | + B_BE_PTA_WL_ACT_TX_BT0_VAL; + if (gnt_cfg->bt[1].wlan_act_en) + val |= B_BE_PTA_WL_ACT1_SWCTRL | B_BE_PTA_WL_ACT_RX_BT1_SWCTRL | + B_BE_PTA_WL_ACT_TX_BT1_SWCTRL; + if (gnt_cfg->bt[1].wlan_act) + val |= B_BE_PTA_WL_ACT1_VAL | B_BE_PTA_WL_ACT_RX_BT1_VAL | + B_BE_PTA_WL_ACT_TX_BT1_VAL; + + rtw89_write32(rtwdev, R_BE_PTA_GNT_SW_CTRL, val); + + return 0; +} +EXPORT_SYMBOL(rtw89_mac_cfg_gnt_v3); + int rtw89_mac_cfg_ctrl_path_v2(struct rtw89_dev *rtwdev, bool wl) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_mac_ax_gnt *g = dm->gnt.band; struct rtw89_mac_ax_wl_act *gbt = dm->gnt.bt; + const struct rtw89_chip_info *chip = rtwdev->chip; int i; if (wl) @@ -2023,7 +2076,11 @@ int rtw89_mac_cfg_ctrl_path_v2(struct rtw89_dev *rtwdev, bool wl) gbt[i].wlan_act_en = 0; } - return rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt); + if (chip->chip_id == RTL8922A) + return rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt); + else + return rtw89_mac_cfg_gnt_v3(rtwdev, &dm->gnt); + } EXPORT_SYMBOL(rtw89_mac_cfg_ctrl_path_v2); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index afe13c0c5629..de36cf5ef1a1 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -6202,6 +6202,75 @@ #define B_BE_GNT_WL_BB_PWR_VAL BIT(1) #define B_BE_GNT_WL_BB_PWR_SWCTRL BIT(0) +#define R_BE_PTA_GNT_SW_CTRL 0x0E348 +#define B_BE_PTA_WL_ACT0_VAL BIT(19) +#define B_BE_PTA_WL_ACT0_SWCTRL BIT(18) +#define B_BE_PTA_GNT_BT0_RX_BB1_VAL BIT(17) +#define B_BE_PTA_GNT_BT0_RX_BB1_SWCTRL BIT(16) +#define B_BE_PTA_GNT_BT0_TX_BB1_VAL BIT(15) +#define B_BE_PTA_GNT_BT0_TX_BB1_SWCTRL BIT(14) +#define B_BE_PTA_GNT_BT0_RX_BB0_VAL BIT(13) +#define B_BE_PTA_GNT_BT0_RX_BB0_SWCTRL BIT(12) +#define B_BE_PTA_GNT_BT0_TX_BB0_VAL BIT(11) +#define B_BE_PTA_GNT_BT0_TX_BB0_SWCTRL BIT(10) +#define B_BE_PTA_GNT_BT0_BB_VAL BIT(9) +#define B_BE_PTA_GNT_BT0_BB_SWCTRL BIT(8) +#define B_BE_PTA_WL_ACT_RX_BT0_VAL BIT(7) +#define B_BE_PTA_WL_ACT_RX_BT0_SWCTRL BIT(6) +#define B_BE_PTA_WL_ACT_TX_BT0_VAL BIT(5) +#define B_BE_PTA_WL_ACT_TX_BT0_SWCTRL BIT(4) +#define B_BE_PTA_GNT_WL_BB1_VAL BIT(3) +#define B_BE_PTA_GNT_WL_BB1_SWCTRL BIT(2) +#define B_BE_PTA_GNT_WL_BB0_VAL BIT(1) +#define B_BE_PTA_GNT_WL_BB0_SWCTRL BIT(0) + +#define R_BE_PTA_GNT_VAL 0x0E34C +#define B_BE_PTA_WL_ACT2 BIT(20) +#define B_BE_PTA_GNT_ZB_TX_BB1 BIT(19) +#define B_BE_PTA_GNT_ZB_TX_BB0 BIT(18) +#define B_BE_PTA_WL_ACT1 BIT(17) +#define B_BE_PTA_GNT_BT1_RX_BB1 BIT(16) +#define B_BE_PTA_GNT_BT1_RX_BB0 BIT(15) +#define B_BE_PTA_GNT_BT1_TX_BB1 BIT(14) +#define B_BE_PTA_GNT_BT1_TX_BB0 BIT(13) +#define B_BE_PTA_WL_ACT_RX_BT1 BIT(12) +#define B_BE_PTA_WL_ACT_TX_BT1 BIT(11) +#define B_BE_PTA_GNT_BT1_BB BIT(10) +#define B_BE_PTA_WL_ACT0 BIT(9) +#define B_BE_PTA_GNT_BT0_RX_BB1 BIT(8) +#define B_BE_PTA_GNT_BT0_TX_BB1 BIT(7) +#define B_BE_PTA_GNT_BT0_RX_BB0 BIT(6) +#define B_BE_PTA_GNT_BT0_TX_BB0 BIT(5) +#define B_BE_PTA_GNT_BT0_BB BIT(4) +#define B_BE_PTA_WL_ACT_RX_BT0 BIT(3) +#define B_BE_PTA_WL_ACT_TX_BT0 BIT(2) +#define B_BE_PTA_GNT_WL_BB1 BIT(1) +#define B_BE_PTA_GNT_WL_BB0 BIT(0) + +#define R_BE_PTA_GNT_ZL_SW_CTRL 0x0E350 +#define B_BE_PTA_WL_ACT2_VAL BIT(21) +#define B_BE_PTA_WL_ACT2_SWCTRL BIT(20) +#define B_BE_PTA_GNT_ZB_TX_BB1_VAL BIT(19) +#define B_BE_PTA_GNT_ZB_TX_BB1_SWCTRL BIT(18) +#define B_BE_PTA_GNT_ZB_TX_BB0_VAL BIT(17) +#define B_BE_PTA_GNT_ZB_TX_BB0_SWCTRL BIT(16) +#define B_BE_PTA_WL_ACT1_VAL BIT(15) +#define B_BE_PTA_WL_ACT1_SWCTRL BIT(14) +#define B_BE_PTA_GNT_BT1_RX_BB1_VAL BIT(13) +#define B_BE_PTA_GNT_BT1_RX_BB1_SWCTRL BIT(12) +#define B_BE_PTA_GNT_BT1_RX_BB0_VAL BIT(11) +#define B_BE_PTA_GNT_BT1_RX_BB0_SWCTRL BIT(10) +#define B_BE_PTA_GNT_BT1_TX_BB1_VAL BIT(9) +#define B_BE_PTA_GNT_BT1_TX_BB1_SWCTRL BIT(8) +#define B_BE_PTA_GNT_BT1_TX_BB0_VAL BIT(7) +#define B_BE_PTA_GNT_BT1_TX_BB0_SWCTRL BIT(6) +#define B_BE_PTA_WL_ACT_RX_BT1_VAL BIT(5) +#define B_BE_PTA_WL_ACT_RX_BT1_SWCTRL BIT(4) +#define B_BE_PTA_WL_ACT_TX_BT1_VAL BIT(3) +#define B_BE_PTA_WL_ACT_TX_BT1_SWCTRL BIT(2) +#define B_BE_PTA_GNT_BT1_BB_VAL BIT(1) +#define B_BE_PTA_GNT_BT1_BB_SWCTRL BIT(0) + #define R_BE_PWR_MACID_PATH_BASE 0x0E500 #define R_BE_PWR_MACID_LMT_BASE 0x0ED00 From 9d6a2a636c9f8609f55f9682a8f875458d823b41 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:11 +0800 Subject: [PATCH 62/81] wifi: rtw89: mac: remove unnecessary return from rtw89_fwdl_secure_idmem_share_mode() The return type of rtw89_fwdl_secure_idmem_share_mode() is void, so no need a return. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 1240e1cc1c10..5a62bbb2cc46 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1625,7 +1625,7 @@ void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode) if (!mac->fwdl_secure_idmem_share_mode) return; - return mac->fwdl_secure_idmem_share_mode(rtwdev, mode); + mac->fwdl_secure_idmem_share_mode(rtwdev, mode); } static inline From 5afb451bb5e0b1c95965975da60c196a6d2ec228 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:12 +0800 Subject: [PATCH 63/81] wifi: rtw89: mac: add dle_mem and ple_{min,max}_qt quota for RTL8922D The quota of DLE and PLE depends on hardware design and consideration of performance and application. Define them accordingly. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 20 ++++++++++++++++++-- drivers/net/wireless/realtek/rtw89/mac.c | 14 ++++++++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 15 +++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 4c39c4dbaf56..a59fba681e85 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4024,13 +4024,14 @@ struct rtw89_dle_size { u16 pge_size; u16 lnk_pge_num; u16 unlnk_pge_num; - /* for WiFi 7 chips below */ + /* for WiFi 7 chips below (suffix v1) */ u32 srt_ofst; }; struct rtw89_wde_quota { u16 hif; u16 wcpu; + /* unused dcpu isn't listed */ u16 pkt_in; u16 cpu_io; }; @@ -4048,8 +4049,10 @@ struct rtw89_ple_quota { u16 wd_rel; u16 cpu_io; u16 tx_rpt; - /* for WiFi 7 chips below */ + /* for WiFi 7 chips below (suffix v1) */ u16 h2d; + /* for WiFi 7 chips after 8922D (suffix v2) */ + u16 snrpt; }; struct rtw89_rsvd_quota { @@ -4070,6 +4073,17 @@ struct rtw89_dle_rsvd_size { u32 size; }; +struct rtw89_dle_input { + u32 tx_ampdu_num_b0; + u32 tx_ampdu_num_b1; + u32 tx_amsdu_size; /* unit: KB */ + u32 h2c_max_size; + u32 rx_amsdu_size; /* unit: KB */ + u32 c2h_max_size; + u32 mpdu_info_tbl_b0; + u32 mpdu_info_tbl_b1; +}; + struct rtw89_dle_mem { enum rtw89_qta_mode mode; const struct rtw89_dle_size *wde_size; @@ -4082,6 +4096,8 @@ struct rtw89_dle_mem { const struct rtw89_rsvd_quota *rsvd_qt; const struct rtw89_dle_rsvd_size *rsvd0_size; const struct rtw89_dle_rsvd_size *rsvd1_size; + /* for WiFi 7 chips after 8922D */ + const struct rtw89_dle_input *dle_input; }; struct rtw89_reg_def { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index be478540f742..b1f313f738b8 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1717,10 +1717,12 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_size7 = {RTW89_WDE_PG_64, 510, 2,}, /* DLFW */ .wde_size9 = {RTW89_WDE_PG_64, 0, 1024,}, + .wde_size16_v1 = {RTW89_WDE_PG_64, 639, 1, 0,}, /* 8852C USB3.0 */ .wde_size17 = {RTW89_WDE_PG_64, 354, 30,}, /* 8852C DLFW */ .wde_size18 = {RTW89_WDE_PG_64, 0, 2048,}, + .wde_size18_v1 = {RTW89_WDE_PG_64, 0, 640, 0,}, /* 8852C PCIE SCC */ .wde_size19 = {RTW89_WDE_PG_64, 3328, 0,}, .wde_size23 = {RTW89_WDE_PG_64, 1022, 2,}, @@ -1747,6 +1749,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_size18 = {RTW89_PLE_PG_128, 2544, 16,}, /* 8852C PCIE SCC */ .ple_size19 = {RTW89_PLE_PG_128, 1904, 16,}, + .ple_size20_v1 = {RTW89_PLE_PG_128, 2554, 182, 40960,}, + .ple_size22_v1 = {RTW89_PLE_PG_128, 2736, 0, 40960,}, /* 8852B USB2.0 SCC */ .ple_size32 = {RTW89_PLE_PG_128, 620, 20,}, /* 8852B USB3.0 SCC */ @@ -1758,6 +1762,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_qt0_v1 = {3302, 6, 0, 20,}, /* 8852A USB */ .wde_qt1 = {512, 196, 0, 60,}, + .wde_qt3 = {0, 0, 0, 0,}, /* DLFW */ .wde_qt4 = {0, 0, 0, 0,}, /* PCIE 64 */ @@ -1770,6 +1775,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_qt17 = {0, 0, 0, 0,}, /* 8852C PCIE SCC */ .wde_qt18 = {3228, 60, 0, 40,}, + .wde_qt19_v1 = {613, 6, 0, 20,}, .wde_qt23 = {958, 48, 0, 16,}, /* 8852B USB2.0/USB3.0 SCC */ .wde_qt25 = {152, 2, 0, 8,}, @@ -1781,6 +1787,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt4 = {264, 0, 16, 20, 26, 13, 356, 0, 32, 40, 8,}, /* PCIE SCC */ .ple_qt5 = {264, 0, 32, 20, 64, 13, 1101, 0, 64, 128, 120,}, + .ple_qt5_v2 = {0, 0, 32, 256, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,}, .ple_qt9 = {0, 0, 32, 256, 0, 0, 0, 0, 0, 0, 1, 0, 0,}, /* DLFW */ .ple_qt13 = {0, 0, 16, 48, 0, 0, 0, 0, 0, 0, 0,}, @@ -1791,8 +1798,10 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt26 = {2654, 0, 1134, 48, 64, 13, 1478, 0, 64, 128, 120, 0,}, /* USB 52C USB3.0 */ .ple_qt42 = {1068, 0, 16, 48, 4, 13, 178, 0, 16, 1, 8, 16, 0,}, + .ple_qt42_v2 = {91, 91, 32, 16, 19, 13, 91, 91, 44, 18, 1, 4, 0, 0,}, /* USB 52C USB3.0 */ .ple_qt43 = {3068, 0, 32, 48, 4, 13, 178, 0, 16, 1, 8, 16, 0,}, + .ple_qt43_v2 = {645, 645, 32, 16, 2062, 2056, 2134, 2134, 2087, 2061, 1, 2047, 0, 0,}, /* DLFW 52C */ .ple_qt44 = {0, 0, 16, 256, 0, 0, 0, 0, 0, 0, 0, 0,}, /* DLFW 52C */ @@ -1826,8 +1835,13 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt_51b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, .ple_rsvd_qt0 = {2, 107, 107, 6, 6, 6, 6, 0, 0, 0,}, .ple_rsvd_qt1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .ple_rsvd_qt9 = {1, 44, 44, 6, 6, 6, 6, 69, 0, 0,}, .rsvd0_size0 = {212992, 0,}, + .rsvd0_size6 = {40960, 0,}, .rsvd1_size0 = {587776, 2048,}, + .rsvd1_size2 = {391168, 2048,}, + .dle_input3 = {0, 0, 0, 16384, 0, 2048, 0, 0,}, + .dle_input18 = {128, 128, 11454, 2048, 0, 2048, 24, 24,}, }; EXPORT_SYMBOL(rtw89_mac_size); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 5a62bbb2cc46..8ecb15f335eb 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -932,8 +932,10 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size wde_size6; const struct rtw89_dle_size wde_size7; const struct rtw89_dle_size wde_size9; + const struct rtw89_dle_size wde_size16_v1; const struct rtw89_dle_size wde_size17; const struct rtw89_dle_size wde_size18; + const struct rtw89_dle_size wde_size18_v1; const struct rtw89_dle_size wde_size19; const struct rtw89_dle_size wde_size23; const struct rtw89_dle_size wde_size25; @@ -949,18 +951,22 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size ple_size17; const struct rtw89_dle_size ple_size18; const struct rtw89_dle_size ple_size19; + const struct rtw89_dle_size ple_size20_v1; + const struct rtw89_dle_size ple_size22_v1; const struct rtw89_dle_size ple_size32; const struct rtw89_dle_size ple_size33; const struct rtw89_dle_size ple_size34; const struct rtw89_wde_quota wde_qt0; const struct rtw89_wde_quota wde_qt1; const struct rtw89_wde_quota wde_qt0_v1; + const struct rtw89_wde_quota wde_qt3; const struct rtw89_wde_quota wde_qt4; const struct rtw89_wde_quota wde_qt6; const struct rtw89_wde_quota wde_qt7; const struct rtw89_wde_quota wde_qt16; const struct rtw89_wde_quota wde_qt17; const struct rtw89_wde_quota wde_qt18; + const struct rtw89_wde_quota wde_qt19_v1; const struct rtw89_wde_quota wde_qt23; const struct rtw89_wde_quota wde_qt25; const struct rtw89_wde_quota wde_qt31; @@ -968,13 +974,16 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt1; const struct rtw89_ple_quota ple_qt4; const struct rtw89_ple_quota ple_qt5; + const struct rtw89_ple_quota ple_qt5_v2; const struct rtw89_ple_quota ple_qt9; const struct rtw89_ple_quota ple_qt13; const struct rtw89_ple_quota ple_qt18; const struct rtw89_ple_quota ple_qt25; const struct rtw89_ple_quota ple_qt26; const struct rtw89_ple_quota ple_qt42; + const struct rtw89_ple_quota ple_qt42_v2; const struct rtw89_ple_quota ple_qt43; + const struct rtw89_ple_quota ple_qt43_v2; const struct rtw89_ple_quota ple_qt44; const struct rtw89_ple_quota ple_qt45; const struct rtw89_ple_quota ple_qt46; @@ -994,8 +1003,14 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt_51b_wow; const struct rtw89_rsvd_quota ple_rsvd_qt0; const struct rtw89_rsvd_quota ple_rsvd_qt1; + const struct rtw89_rsvd_quota ple_rsvd_qt1_v1; + const struct rtw89_rsvd_quota ple_rsvd_qt9; const struct rtw89_dle_rsvd_size rsvd0_size0; + const struct rtw89_dle_rsvd_size rsvd0_size6; const struct rtw89_dle_rsvd_size rsvd1_size0; + const struct rtw89_dle_rsvd_size rsvd1_size2; + const struct rtw89_dle_input dle_input3; + const struct rtw89_dle_input dle_input18; }; extern const struct rtw89_mac_size_set rtw89_mac_size; From 70cd273aae23c1a583efefbf3a86c7a45d4e3c7e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:13 +0800 Subject: [PATCH 64/81] wifi: rtw89: mac: set quota 13 for PLE SNRPT The RTL8922D has additional quota 13 of SNRPT for PLE (payload engine). Set value to the quota according to predefined tables. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac_be.c | 5 +++++ drivers/net/wireless/realtek/rtw89/reg.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 06538122c57a..aff9855f184a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -331,6 +331,11 @@ static void ple_quota_cfg_be(struct rtw89_dev *rtwdev, SET_QUOTA(cpu_io, PLE, 10); SET_QUOTA(tx_rpt, PLE, 11); SET_QUOTA(h2d, PLE, 12); + + if (rtwdev->chip->chip_id == RTL8922A) + return; + + SET_QUOTA(snrpt, PLE, 13); } static void rtw89_mac_hci_func_en_be(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index de36cf5ef1a1..9ac1c169d25c 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -5514,6 +5514,10 @@ #define B_BE_PLE_Q12_MAX_SIZE_MASK GENMASK(27, 16) #define B_BE_PLE_Q12_MIN_SIZE_MASK GENMASK(11, 0) +#define R_BE_PLE_QTA13_CFG 0x9074 +#define B_BE_PLE_Q13_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q13_MIN_SIZE_MASK GENMASK(11, 0) + #define R_BE_PLE_ERRFLAG1_IMR 0x90C0 #define B_BE_PLE_SRCHPG_PGOFST_IMR BIT(26) #define B_BE_PLE_SRCHPG_STRPG_IMR BIT(25) From 9cf039ee49b5d4d7424697227a522b2dd40c2a34 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:14 +0800 Subject: [PATCH 65/81] wifi: rtw89: mac: update MPDU quota according to chip DLE definition MPDU quota is to define number of memory used to handle packets in DLE (Data Link Engine). All chips use the same value before, but the RTL8922D need to use chip specific value. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 1 + drivers/net/wireless/realtek/rtw89/mac_be.c | 12 +++++++++++- drivers/net/wireless/realtek/rtw89/reg.h | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a59fba681e85..0877cb342b94 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4636,6 +4636,7 @@ enum rtw89_hcifc_mode { struct rtw89_dle_info { const struct rtw89_rsvd_quota *rsvd_qt; + const struct rtw89_dle_input *dle_input; enum rtw89_qta_mode qta_mode; u16 ple_pg_size; u16 ple_free_pg; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index b1f313f738b8..35794488a02f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1862,6 +1862,7 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, } mac->dle_info.rsvd_qt = cfg->rsvd_qt; + mac->dle_info.dle_input = cfg->dle_input; mac->dle_info.ple_pg_size = cfg->ple_size->pge_size; mac->dle_info.ple_free_pg = cfg->ple_size->lnk_pge_num; mac->dle_info.qta_mode = mode; diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index aff9855f184a..0327629d2a5d 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -873,7 +873,10 @@ static int sec_eng_init_be(struct rtw89_dev *rtwdev) static int txpktctrl_init_be(struct rtw89_dev *rtwdev) { + struct rtw89_mac_info *mac = &rtwdev->mac; struct rtw89_mac_dle_rsvd_qt_cfg qt_cfg; + const struct rtw89_dle_input *dle_input; + u32 mpdu_info_b1_ofst; u32 val32; int ret; @@ -884,9 +887,16 @@ static int txpktctrl_init_be(struct rtw89_dev *rtwdev) return ret; } + dle_input = mac->dle_info.dle_input; + if (dle_input) + mpdu_info_b1_ofst = DIV_ROUND_UP(dle_input->mpdu_info_tbl_b0, + BIT(MPDU_INFO_TBL_FACTOR)); + else + mpdu_info_b1_ofst = MPDU_INFO_B1_OFST; + val32 = rtw89_read32(rtwdev, R_BE_TXPKTCTL_MPDUINFO_CFG); val32 = u32_replace_bits(val32, qt_cfg.pktid, B_BE_MPDUINFO_PKTID_MASK); - val32 = u32_replace_bits(val32, MPDU_INFO_B1_OFST, B_BE_MPDUINFO_B1_BADDR_MASK); + val32 = u32_replace_bits(val32, mpdu_info_b1_ofst, B_BE_MPDUINFO_B1_BADDR_MASK); val32 |= B_BE_MPDUINFO_FEN; rtw89_write32(rtwdev, R_BE_TXPKTCTL_MPDUINFO_CFG, val32); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 9ac1c169d25c..e41a6c679d59 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -5869,6 +5869,7 @@ #define B_BE_MPDUINFO_PKTID_MASK GENMASK(27, 16) #define B_BE_MPDUINFO_B1_BADDR_MASK GENMASK(5, 0) #define MPDU_INFO_B1_OFST 18 +#define MPDU_INFO_TBL_FACTOR 3 #define R_BE_TXPKTCTL_B0_PRELD_CFG0 0x9F48 #define B_BE_B0_PRELD_FEN BIT(31) From a69c2c9a587d91941fcb041ccb77eef6cb892423 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:15 +0800 Subject: [PATCH 66/81] wifi: rtw89: mac: update WP quota for RTL8922D WP (WiFi payload) quota is to point to payload being transmitting in memory. Assign quota to indicate WP page full. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 5 ++++ drivers/net/wireless/realtek/rtw89/mac.c | 4 +-- drivers/net/wireless/realtek/rtw89/mac_be.c | 27 ++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/reg.h | 5 ++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 0877cb342b94..c008931ccb05 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4000,6 +4000,11 @@ struct rtw89_hfc_prec_cfg { u8 h2c_full_cond; u8 wp_ch07_full_cond; u8 wp_ch811_full_cond; + /* for WiFi 7 chips after 8922D */ + u16 ch011_full_page; + u16 h2c_full_page; + u16 wp_ch07_full_page; + u16 wp_ch811_full_page; }; struct rtw89_hfc_param { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 35794488a02f..a008a1a02fe9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1701,8 +1701,8 @@ static int sys_init_ax(struct rtw89_dev *rtwdev) const struct rtw89_mac_size_set rtw89_mac_size = { .hfc_preccfg_pcie = {2, 40, 0, 0, 1, 0, 0, 0}, - .hfc_prec_cfg_c0 = {2, 32, 0, 0, 0, 0, 0, 0}, - .hfc_prec_cfg_c2 = {0, 256, 0, 0, 0, 0, 0, 0}, + .hfc_prec_cfg_c0 = {2, 32, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0}, + .hfc_prec_cfg_c2 = {0, 256, 0, 0, 0, 0, 0, 0, 0, 256, 0, 0}, /* PCIE 64 */ .wde_size0 = {RTW89_WDE_PG_64, 4095, 1,}, .wde_size0_v1 = {RTW89_WDE_PG_64, 3328, 0, 0,}, diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 0327629d2a5d..5df243cf448e 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -89,6 +89,7 @@ static void hfc_get_mix_info_be(struct rtw89_dev *rtwdev) struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; struct rtw89_hfc_pub_cfg *pub_cfg = ¶m->pub_cfg; struct rtw89_hfc_pub_info *info = ¶m->pub_info; + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val; val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO1); @@ -116,14 +117,23 @@ static void hfc_get_mix_info_be(struct rtw89_dev *rtwdev) val = rtw89_read32(rtwdev, R_BE_CH_PAGE_CTRL); prec_cfg->ch011_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH011_V1_MASK); + if (chip->chip_id == RTL8922D) + prec_cfg->ch011_full_page = u32_get_bits(val, B_BE_FULL_WD_PG_MASK); prec_cfg->h2c_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH12_V1_MASK); val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_CTRL2); pub_cfg->pub_max = u32_get_bits(val, B_BE_PUBPG_ALL_MASK); val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL1); - prec_cfg->wp_ch07_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH07_MASK); - prec_cfg->wp_ch811_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH811_MASK); + if (chip->chip_id == RTL8922D) { + prec_cfg->wp_ch07_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH07_V1_MASK); + prec_cfg->wp_ch07_full_page = u32_get_bits(val, B_BE_FULL_PAGE_WP_CH07_MASK); + prec_cfg->wp_ch811_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH811_V1_MASK); + prec_cfg->wp_ch811_full_page = u32_get_bits(val, B_BE_FULL_PAGE_WP_CH811_MASK); + } else { + prec_cfg->wp_ch07_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH07_MASK); + prec_cfg->wp_ch811_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH811_MASK); + } val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL2); pub_cfg->wp_thrd = u32_get_bits(val, B_BE_WP_THRD_MASK); @@ -148,17 +158,26 @@ static void hfc_mix_cfg_be(struct rtw89_dev *rtwdev) struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; const struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; const struct rtw89_hfc_pub_cfg *pub_cfg = ¶m->pub_cfg; + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val; val = u32_encode_bits(prec_cfg->ch011_prec, B_BE_PREC_PAGE_CH011_V1_MASK) | u32_encode_bits(prec_cfg->h2c_prec, B_BE_PREC_PAGE_CH12_V1_MASK); + if (chip->chip_id == RTL8922D) + val = u32_replace_bits(val, prec_cfg->ch011_full_page, B_BE_FULL_WD_PG_MASK); rtw89_write32(rtwdev, R_BE_CH_PAGE_CTRL, val); val = u32_encode_bits(pub_cfg->pub_max, B_BE_PUBPG_ALL_MASK); rtw89_write32(rtwdev, R_BE_PUB_PAGE_CTRL2, val); - val = u32_encode_bits(prec_cfg->wp_ch07_prec, B_BE_PREC_PAGE_WP_CH07_MASK) | - u32_encode_bits(prec_cfg->wp_ch811_prec, B_BE_PREC_PAGE_WP_CH811_MASK); + if (chip->chip_id == RTL8922D) + val = u32_encode_bits(prec_cfg->wp_ch07_prec, B_BE_PREC_PAGE_WP_CH07_V1_MASK) | + u32_encode_bits(prec_cfg->wp_ch07_full_page, B_BE_FULL_PAGE_WP_CH07_MASK) | + u32_encode_bits(prec_cfg->wp_ch811_prec, B_BE_PREC_PAGE_WP_CH811_V1_MASK) | + u32_encode_bits(prec_cfg->wp_ch811_full_page, B_BE_FULL_PAGE_WP_CH811_MASK); + else + val = u32_encode_bits(prec_cfg->wp_ch07_prec, B_BE_PREC_PAGE_WP_CH07_MASK) | + u32_encode_bits(prec_cfg->wp_ch811_prec, B_BE_PREC_PAGE_WP_CH811_MASK); rtw89_write32(rtwdev, R_BE_WP_PAGE_CTRL1, val); val = u32_replace_bits(rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL), diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index e41a6c679d59..79c976c25de5 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -6117,6 +6117,7 @@ #define R_BE_CH_PAGE_CTRL 0xB704 #define B_BE_PREC_PAGE_CH12_V1_MASK GENMASK(21, 16) +#define B_BE_FULL_WD_PG_MASK GENMASK(15, 8) #define B_BE_PREC_PAGE_CH011_V1_MASK GENMASK(5, 0) #define R_BE_CH0_PAGE_CTRL 0xB718 @@ -6149,6 +6150,10 @@ #define R_BE_WP_PAGE_CTRL1 0xB7A4 #define B_BE_PREC_PAGE_WP_CH811_MASK GENMASK(24, 16) #define B_BE_PREC_PAGE_WP_CH07_MASK GENMASK(8, 0) +#define B_BE_FULL_PAGE_WP_CH811_MASK GENMASK(31, 24) +#define B_BE_PREC_PAGE_WP_CH811_V1_MASK GENMASK(23, 16) +#define B_BE_FULL_PAGE_WP_CH07_MASK GENMASK(15, 8) +#define B_BE_PREC_PAGE_WP_CH07_V1_MASK GENMASK(7, 0) #define R_BE_WP_PAGE_CTRL2 0xB7A8 #define B_BE_WP_THRD_MASK GENMASK(12, 0) From 7ded59e69ab31ff91fafaa6820caaf17f464e291 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:16 +0800 Subject: [PATCH 67/81] wifi: rtw89: mac: define preload_init for generations The preload_init is to define preload size from memory to transmitting buffer. The different generations should call its callback respectively but suddenly it is missed. However, the register definitions of WiFi 6/7 are the same, things are well. For the coming RTL8922D, settings are different, so abstract it. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 8 +++++--- drivers/net/wireless/realtek/rtw89/mac.h | 2 ++ drivers/net/wireless/realtek/rtw89/mac_be.c | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index a008a1a02fe9..5bf81ef0313b 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -2283,8 +2283,8 @@ int rtw89_mac_dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, return ret; } -static int preload_init_set(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, - enum rtw89_qta_mode mode) +static int preload_init_set_ax(struct rtw89_dev *rtwdev, u8 mac_idx, + enum rtw89_qta_mode mode) { u32 reg, max_preld_size, min_rsvd_size; @@ -2312,13 +2312,14 @@ static bool is_qta_poh(struct rtw89_dev *rtwdev) int rtw89_mac_preload_init(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, enum rtw89_qta_mode mode) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev) || !is_qta_poh(rtwdev)) return 0; - return preload_init_set(rtwdev, mac_idx, mode); + return mac->preload_init(rtwdev, mac_idx, mode); } static bool dle_is_txq_empty(struct rtw89_dev *rtwdev) @@ -7287,6 +7288,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .check_mac_en = rtw89_mac_check_mac_en_ax, .sys_init = sys_init_ax, .trx_init = trx_init_ax, + .preload_init = preload_init_set_ax, .err_imr_ctrl = err_imr_ctrl_ax, .hci_func_en = rtw89_mac_hci_func_en_ax, .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 8ecb15f335eb..815e12de0853 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1037,6 +1037,8 @@ struct rtw89_mac_gen_def { enum rtw89_mac_hwmod_sel sel); int (*sys_init)(struct rtw89_dev *rtwdev); int (*trx_init)(struct rtw89_dev *rtwdev); + int (*preload_init)(struct rtw89_dev *rtwdev, u8 mac_idx, + enum rtw89_qta_mode mode); void (*err_imr_ctrl)(struct rtw89_dev *rtwdev, bool en); void (*hci_func_en)(struct rtw89_dev *rtwdev); void (*dmac_func_pre_en)(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 5df243cf448e..475d941d41a7 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2832,6 +2832,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .check_mac_en = rtw89_mac_check_mac_en_be, .sys_init = sys_init_be, .trx_init = trx_init_be, + .preload_init = preload_init_be, .err_imr_ctrl = err_imr_ctrl_be, .hci_func_en = rtw89_mac_hci_func_en_be, .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_be, From baf38631460b741ff21ee74246e5a17772290510 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:17 +0800 Subject: [PATCH 68/81] wifi: rtw89: mac: configure DMA_STOP1 by predefined mask For coming chip 8922DE, the DMA channel set is different from existing one, so use predefined mask to handle the difference. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac_be.c | 14 +++++++----- drivers/net/wireless/realtek/rtw89/pci.h | 25 --------------------- drivers/net/wireless/realtek/rtw89/pci_be.c | 4 ++++ drivers/net/wireless/realtek/rtw89/reg.h | 12 ++++++++++ 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 475d941d41a7..a0e5c99abb17 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -365,6 +365,8 @@ static void rtw89_mac_hci_func_en_be(struct rtw89_dev *rtwdev) static void rtw89_mac_dmac_func_pre_en_be(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 mask; u32 val; val = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); @@ -388,12 +390,12 @@ static void rtw89_mac_dmac_func_pre_en_be(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); - rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, - B_BE_STOP_CH0 | B_BE_STOP_CH1 | B_BE_STOP_CH2 | - B_BE_STOP_CH3 | B_BE_STOP_CH4 | B_BE_STOP_CH5 | - B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 | - B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11 | - B_BE_STOP_CH12 | B_BE_STOP_CH13 | B_BE_STOP_CH14); + if (chip->chip_id == RTL8922A) + mask = B_BE_TX_STOP1_MASK; + else + mask = B_BE_TX_STOP1_MASK_V1; + + rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, mask); rtw89_write32_set(rtwdev, R_BE_DMAC_TABLE_CTRL, B_BE_DMAC_ADDR_MODE); } diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 16dfb0e79d77..64c080053fd1 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -767,31 +767,6 @@ #define R_AX_WP_ADDR_H_SEL8_11 0x133C #define R_AX_WP_ADDR_H_SEL12_15 0x1340 -#define R_BE_HAXI_DMA_STOP1 0xB010 -#define B_BE_STOP_WPDMA BIT(31) -#define B_BE_STOP_CH14 BIT(14) -#define B_BE_STOP_CH13 BIT(13) -#define B_BE_STOP_CH12 BIT(12) -#define B_BE_STOP_CH11 BIT(11) -#define B_BE_STOP_CH10 BIT(10) -#define B_BE_STOP_CH9 BIT(9) -#define B_BE_STOP_CH8 BIT(8) -#define B_BE_STOP_CH7 BIT(7) -#define B_BE_STOP_CH6 BIT(6) -#define B_BE_STOP_CH5 BIT(5) -#define B_BE_STOP_CH4 BIT(4) -#define B_BE_STOP_CH3 BIT(3) -#define B_BE_STOP_CH2 BIT(2) -#define B_BE_STOP_CH1 BIT(1) -#define B_BE_STOP_CH0 BIT(0) -#define B_BE_TX_STOP1_MASK (B_BE_STOP_CH0 | B_BE_STOP_CH1 | \ - B_BE_STOP_CH2 | B_BE_STOP_CH3 | \ - B_BE_STOP_CH4 | B_BE_STOP_CH5 | \ - B_BE_STOP_CH6 | B_BE_STOP_CH7 | \ - B_BE_STOP_CH8 | B_BE_STOP_CH9 | \ - B_BE_STOP_CH10 | B_BE_STOP_CH11 | \ - B_BE_STOP_CH12) - #define R_BE_CH0_TXBD_NUM_V1 0xB030 #define R_BE_CH1_TXBD_NUM_V1 0xB032 #define R_BE_CH2_TXBD_NUM_V1 0xB034 diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 95efb1094b6c..148cce0df058 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -322,6 +322,7 @@ static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool enable) { + const struct rtw89_pci_info *info = rtwdev->pci_info; u32 mask_all; u32 val; @@ -330,6 +331,9 @@ static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool enable) B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 | B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11; + /* mask out unsupported channels for certains chips */ + mask_all &= info->dma_stop1.mask; + val = rtw89_read32(rtwdev, R_BE_HAXI_DMA_STOP1); val |= B_BE_STOP_CH13 | B_BE_STOP_CH14; diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 79c976c25de5..bfb1ebcc9fc2 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -6065,6 +6065,18 @@ #define B_BE_STOP_CH2 BIT(2) #define B_BE_STOP_CH1 BIT(1) #define B_BE_STOP_CH0 BIT(0) +#define B_BE_TX_STOP1_MASK (B_BE_STOP_CH0 | B_BE_STOP_CH1 | \ + B_BE_STOP_CH2 | B_BE_STOP_CH3 | \ + B_BE_STOP_CH4 | B_BE_STOP_CH5 | \ + B_BE_STOP_CH6 | B_BE_STOP_CH7 | \ + B_BE_STOP_CH8 | B_BE_STOP_CH9 | \ + B_BE_STOP_CH10 | B_BE_STOP_CH11 | \ + B_BE_STOP_CH12 | B_BE_STOP_CH13 | \ + B_BE_STOP_CH14) +#define B_BE_TX_STOP1_MASK_V1 (B_BE_STOP_CH0 | B_BE_STOP_CH2 | \ + B_BE_STOP_CH4 | B_BE_STOP_CH6 | \ + B_BE_STOP_CH8 | B_BE_STOP_CH10 | \ + B_BE_STOP_CH12) #define R_BE_HAXI_MST_WDT_TIMEOUT_SEL_V1 0xB02C #define B_BE_HAXI_MST_WDT_TIMEOUT_SEL_MASK GENMASK(4, 0) From c16673247b404ad4a004268fc079737531078fcb Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:18 +0800 Subject: [PATCH 69/81] wifi: rtw89: mac: separate functions of CMAC power and function enable To enable/disable CMAC function somewhere, separate controls of CMAC power and function into individual functions. Also correct the hardware settings by the way. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 + drivers/net/wireless/realtek/rtw89/mac.c | 2 + drivers/net/wireless/realtek/rtw89/mac_be.c | 97 ++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/reg.h | 15 ++-- 4 files changed, 100 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c008931ccb05..8d5655138ded 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5160,6 +5160,8 @@ enum rtw89_flags { RTW89_FLAG_DMAC_FUNC, RTW89_FLAG_CMAC0_FUNC, RTW89_FLAG_CMAC1_FUNC, + RTW89_FLAG_CMAC0_PWR, + RTW89_FLAG_CMAC1_PWR, RTW89_FLAG_FW_RDY, RTW89_FLAG_RUNNING, RTW89_FLAG_PROBE_DONE, diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 5bf81ef0313b..f142d3f80e95 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1559,6 +1559,8 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) clear_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); + clear_bit(RTW89_FLAG_CMAC0_PWR, rtwdev->flags); + clear_bit(RTW89_FLAG_CMAC1_PWR, rtwdev->flags); clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); rtw89_mac_update_scoreboard(rtwdev, MAC_AX_NOTIFY_PWR_MAJOR); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index a0e5c99abb17..ef4de64d8661 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -754,28 +754,91 @@ static int dmac_func_en_be(struct rtw89_dev *rtwdev) return 0; } +static int cmac_pwr_en_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) +{ + if (mac_idx > RTW89_MAC_1) + return -EINVAL; + + if (mac_idx == RTW89_MAC_0) { + if (en == test_bit(RTW89_FLAG_CMAC0_PWR, rtwdev->flags)) + return 0; + + if (en) { + rtw89_write32_set(rtwdev, R_BE_AFE_CTRL1, + B_BE_R_SYM_WLCMAC0_ALL_EN); + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_R_SYM_ISO_CMAC02PP); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_CMAC0_FEN); + + set_bit(RTW89_FLAG_CMAC0_PWR, rtwdev->flags); + } else { + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_CMAC0_FEN); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_R_SYM_ISO_CMAC02PP); + rtw89_write32_clr(rtwdev, R_BE_AFE_CTRL1, + B_BE_R_SYM_WLCMAC0_ALL_EN); + + clear_bit(RTW89_FLAG_CMAC0_PWR, rtwdev->flags); + } + } else { + if (en == test_bit(RTW89_FLAG_CMAC1_PWR, rtwdev->flags)) + return 0; + + if (en) { + rtw89_write32_set(rtwdev, R_BE_AFE_CTRL1, + B_BE_R_SYM_WLCMAC1_ALL_EN); + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_R_SYM_ISO_CMAC12PP); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_CMAC1_FEN); + + set_bit(RTW89_FLAG_CMAC1_PWR, rtwdev->flags); + } else { + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_CMAC1_FEN); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_R_SYM_ISO_CMAC12PP); + rtw89_write32_clr(rtwdev, R_BE_AFE_CTRL1, + B_BE_R_SYM_WLCMAC1_ALL_EN); + + clear_bit(RTW89_FLAG_CMAC1_PWR, rtwdev->flags); + } + } + + return 0; +} + static int cmac_func_en_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) { + enum rtw89_flags pwr_flag, func_flag; u32 reg; if (mac_idx > RTW89_MAC_1) return -EINVAL; - if (mac_idx == RTW89_MAC_0) + if (mac_idx == RTW89_MAC_0) { + pwr_flag = RTW89_FLAG_CMAC0_PWR; + func_flag = RTW89_FLAG_CMAC0_FUNC; + } else { + pwr_flag = RTW89_FLAG_CMAC1_PWR; + func_flag = RTW89_FLAG_CMAC1_FUNC; + } + + if (!test_bit(pwr_flag, rtwdev->flags)) { + rtw89_warn(rtwdev, "CMAC %u power cut did not release\n", mac_idx); return 0; + } if (en) { - rtw89_write32_set(rtwdev, R_BE_AFE_CTRL1, B_BE_AFE_CTRL1_SET); - rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL_EXTEND, B_BE_R_SYM_ISO_CMAC12PP); - rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_CMAC1_FEN); - reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CK_EN, mac_idx); rtw89_write32_set(rtwdev, reg, B_BE_CK_EN_SET); reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx); rtw89_write32_set(rtwdev, reg, B_BE_CMAC_FUNC_EN_SET); - set_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); + set_bit(func_flag, rtwdev->flags); } else { reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx); rtw89_write32_clr(rtwdev, reg, B_BE_CMAC_FUNC_EN_SET); @@ -783,11 +846,7 @@ static int cmac_func_en_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CK_EN, mac_idx); rtw89_write32_clr(rtwdev, reg, B_BE_CK_EN_SET); - rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_CMAC1_FEN); - rtw89_write32_set(rtwdev, R_BE_SYS_ISO_CTRL_EXTEND, B_BE_R_SYM_ISO_CMAC12PP); - rtw89_write32_clr(rtwdev, R_BE_AFE_CTRL1, B_BE_AFE_CTRL1_SET); - - clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); + clear_bit(func_flag, rtwdev->flags); } return 0; @@ -806,6 +865,10 @@ static int sys_init_be(struct rtw89_dev *rtwdev) if (ret) return ret; + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_0, true); + if (ret) + return ret; + ret = cmac_func_en_be(rtwdev, RTW89_MAC_0, true); if (ret) return ret; @@ -1814,6 +1877,12 @@ static int band1_enable_be(struct rtw89_dev *rtwdev) return ret; } + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_1, true); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d pwr en %d\n", RTW89_MAC_1, ret); + return ret; + } + ret = cmac_func_en_be(rtwdev, RTW89_MAC_1, true); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d func en %d\n", RTW89_MAC_1, ret); @@ -1857,6 +1926,12 @@ static int band1_disable_be(struct rtw89_dev *rtwdev) return ret; } + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_1, false); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d pwr dis %d\n", RTW89_MAC_1, ret); + return ret; + } + ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode, false); if (ret) { rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index bfb1ebcc9fc2..8233841bb8ff 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3943,6 +3943,11 @@ #define B_BE_R_SYM_WLCMAC0_P2_PC_EN BIT(26) #define B_BE_R_SYM_WLCMAC0_P1_PC_EN BIT(25) #define B_BE_R_SYM_WLCMAC0_PC_EN BIT(24) +#define B_BE_R_SYM_WLCMAC0_ALL_EN (B_BE_R_SYM_WLCMAC0_PC_EN | \ + B_BE_R_SYM_WLCMAC0_P1_PC_EN | \ + B_BE_R_SYM_WLCMAC0_P2_PC_EN | \ + B_BE_R_SYM_WLCMAC0_P3_PC_EN | \ + B_BE_R_SYM_WLCMAC0_P4_PC_EN) #define B_BE_DATAMEM_PC3_EN BIT(23) #define B_BE_DATAMEM_PC2_EN BIT(22) #define B_BE_DATAMEM_PC1_EN BIT(21) @@ -3964,11 +3969,11 @@ #define B_BE_R_SYM_WLCMAC1_P2_PC_EN BIT(2) #define B_BE_R_SYM_WLCMAC1_P1_PC_EN BIT(1) #define B_BE_R_SYM_WLCMAC1_PC_EN BIT(0) -#define B_BE_AFE_CTRL1_SET (B_BE_R_SYM_WLCMAC1_PC_EN | \ - B_BE_R_SYM_WLCMAC1_P1_PC_EN | \ - B_BE_R_SYM_WLCMAC1_P2_PC_EN | \ - B_BE_R_SYM_WLCMAC1_P3_PC_EN | \ - B_BE_R_SYM_WLCMAC1_P4_PC_EN) +#define B_BE_R_SYM_WLCMAC1_ALL_EN (B_BE_R_SYM_WLCMAC1_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P1_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P2_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P3_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P4_PC_EN) #define R_BE_EFUSE_CTRL 0x0030 #define B_BE_EF_MODE_SEL_MASK GENMASK(31, 30) From 6996a4c97ad6c7bf8a8672924444fb623869cdd3 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:19 +0800 Subject: [PATCH 70/81] wifi: rtw89: mac: add an entry to enable MAC function in preinit The preinit is to initialize partial MAC hardware needed before downloading firmware, and then does post-init after firmware runs. For RTL8922D, initialize some DMAC and CMAC at this step. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-13-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 8 +++ drivers/net/wireless/realtek/rtw89/mac.h | 1 + drivers/net/wireless/realtek/rtw89/mac_be.c | 73 +++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index f142d3f80e95..f484e81d6595 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4223,12 +4223,19 @@ int rtw89_mac_partial_init(struct rtw89_dev *rtwdev, bool include_bb) int rtw89_mac_preinit(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; ret = rtw89_mac_pwr_on(rtwdev); if (ret) return ret; + if (mac->mac_func_en) { + ret = mac->mac_func_en(rtwdev); + if (ret) + return ret; + } + return 0; } @@ -7292,6 +7299,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .trx_init = trx_init_ax, .preload_init = preload_init_set_ax, .err_imr_ctrl = err_imr_ctrl_ax, + .mac_func_en = NULL, .hci_func_en = rtw89_mac_hci_func_en_ax, .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_ax, .dle_func_en = dle_func_en_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 815e12de0853..894303c7145e 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1040,6 +1040,7 @@ struct rtw89_mac_gen_def { int (*preload_init)(struct rtw89_dev *rtwdev, u8 mac_idx, enum rtw89_qta_mode mode); void (*err_imr_ctrl)(struct rtw89_dev *rtwdev, bool en); + int (*mac_func_en)(struct rtw89_dev *rtwdev); void (*hci_func_en)(struct rtw89_dev *rtwdev); void (*dmac_func_pre_en)(struct rtw89_dev *rtwdev); void (*dle_func_en)(struct rtw89_dev *rtwdev, bool enable); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index ef4de64d8661..35c16bcca3b7 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -751,6 +751,37 @@ static int rtw89_fwdl_check_path_ready_be(struct rtw89_dev *rtwdev, static int dmac_func_en_be(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->chip_id == RTL8922A) + return 0; + + rtw89_write32_set(rtwdev, R_BE_DMAC_FUNC_EN, + B_BE_MAC_FUNC_EN | B_BE_DMAC_FUNC_EN | + B_BE_MPDU_PROC_EN | B_BE_WD_RLS_EN | + B_BE_DLE_WDE_EN | B_BE_TXPKT_CTRL_EN | + B_BE_STA_SCH_EN | B_BE_DLE_PLE_EN | + B_BE_PKT_BUF_EN | B_BE_DMAC_TBL_EN | + B_BE_PKT_IN_EN | B_BE_DLE_CPUIO_EN | + B_BE_DISPATCHER_EN | B_BE_BBRPT_EN | + B_BE_MAC_SEC_EN | B_BE_H_AXIDMA_EN | + B_BE_DMAC_MLO_EN | B_BE_PLRLS_EN | + B_BE_P_AXIDMA_EN | B_BE_DLE_DATACPUIO_EN); + + return 0; +} + +static int cmac_share_func_en_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->chip_id == RTL8922A) + return 0; + + rtw89_write32_set(rtwdev, R_BE_CMAC_SHARE_FUNC_EN, + B_BE_CMAC_SHARE_EN | B_BE_RESPBA_EN | + B_BE_ADDRSRCH_EN | B_BE_BTCOEX_EN); + return 0; } @@ -865,6 +896,10 @@ static int sys_init_be(struct rtw89_dev *rtwdev) if (ret) return ret; + ret = cmac_share_func_en_be(rtwdev); + if (ret) + return ret; + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_0, true); if (ret) return ret; @@ -880,6 +915,43 @@ static int sys_init_be(struct rtw89_dev *rtwdev) return ret; } +static int mac_func_en_be(struct rtw89_dev *rtwdev) +{ + u32 val; + int ret; + + ret = dmac_func_en_be(rtwdev); + if (ret) + return ret; + + ret = cmac_share_func_en_be(rtwdev); + if (ret) + return ret; + + val = rtw89_read32(rtwdev, R_BE_FEN_RST_ENABLE); + if (val & B_BE_CMAC0_FEN) { + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_0, true); + if (ret) + return ret; + + ret = cmac_func_en_be(rtwdev, RTW89_MAC_0, true); + if (ret) + return ret; + } + + if (val & B_BE_CMAC1_FEN) { + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_1, true); + if (ret) + return ret; + + ret = cmac_func_en_be(rtwdev, RTW89_MAC_1, true); + if (ret) + return ret; + } + + return 0; +} + static int sta_sch_init_be(struct rtw89_dev *rtwdev) { u32 p_val; @@ -2911,6 +2983,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .trx_init = trx_init_be, .preload_init = preload_init_be, .err_imr_ctrl = err_imr_ctrl_be, + .mac_func_en = mac_func_en_be, .hci_func_en = rtw89_mac_hci_func_en_be, .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_be, .dle_func_en = dle_func_en_be, From 40714b8a21377817529e584130715ff97da8fccf Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 8 Jan 2026 20:03:20 +0800 Subject: [PATCH 71/81] wifi: rtw89: mac: set EDCCA configurations for RTL8922D Update EDCCA settings of MAC part for RTL8922D to consider EDCCA state signaled by BB circuit. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260108120320.2217402-14-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 1 + drivers/net/wireless/realtek/rtw89/mac.h | 27 +++ drivers/net/wireless/realtek/rtw89/mac_be.c | 60 +++++++ drivers/net/wireless/realtek/rtw89/reg.h | 184 ++++++++++++++++++++ 5 files changed, 273 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index d8c3474da4b4..4cc5e32d778c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -5818,6 +5818,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) rtw89_phy_dm_init(rtwdev); + rtw89_mac_set_edcca_mode_bands(rtwdev, true); rtw89_mac_cfg_ppdu_status_bands(rtwdev, true); rtw89_mac_cfg_phy_rpt_bands(rtwdev, true); rtw89_mac_update_rts_threshold(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index f484e81d6595..3b9c6f9b7f5a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -7309,6 +7309,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .typ_fltr_opt = rtw89_mac_typ_fltr_opt_ax, .cfg_ppdu_status = rtw89_mac_cfg_ppdu_status_ax, .cfg_phy_rpt = NULL, + .set_edcca_mode = NULL, .dle_mix_cfg = dle_mix_cfg_ax, .chk_dle_rdy = chk_dle_rdy_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 894303c7145e..14fffb660a29 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1055,6 +1055,7 @@ struct rtw89_mac_gen_def { u8 mac_idx); int (*cfg_ppdu_status)(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable); void (*cfg_phy_rpt)(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable); + void (*set_edcca_mode)(struct rtw89_dev *rtwdev, u8 mac_idx, bool normal); int (*dle_mix_cfg)(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg); int (*chk_dle_rdy)(struct rtw89_dev *rtwdev, bool wde_or_ple); @@ -1129,6 +1130,14 @@ u32 rtw89_mac_reg_by_idx(struct rtw89_dev *rtwdev, u32 reg_base, u8 band) return band == 0 ? reg_base : (reg_base + mac->band1_offset); } +static inline void +rtw89_write16_idx(struct rtw89_dev *rtwdev, u32 addr, u16 data, u8 band) +{ + addr = rtw89_mac_reg_by_idx(rtwdev, addr, band); + + rtw89_write16(rtwdev, addr, data); +} + static inline u32 rtw89_mac_reg_by_port(struct rtw89_dev *rtwdev, u32 base, u8 port, u8 mac_idx) { @@ -1364,6 +1373,24 @@ int rtw89_mac_cfg_ppdu_status_bands(struct rtw89_dev *rtwdev, bool enable) return rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_1, enable); } +static inline +void rtw89_mac_set_edcca_mode(struct rtw89_dev *rtwdev, u8 mac_idx, bool normal) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + if (!mac->set_edcca_mode) + return; + + mac->set_edcca_mode(rtwdev, mac_idx, normal); +} + +static inline +void rtw89_mac_set_edcca_mode_bands(struct rtw89_dev *rtwdev, bool normal) +{ + rtw89_mac_set_edcca_mode(rtwdev, RTW89_MAC_0, normal); + rtw89_mac_set_edcca_mode(rtwdev, RTW89_MAC_1, normal); +} + void rtw89_mac_set_rx_fltr(struct rtw89_dev *rtwdev, u8 mac_idx, u32 rx_fltr); void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev); void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 35c16bcca3b7..58135864786f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2391,6 +2391,65 @@ void rtw89_mac_cfg_phy_rpt_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) } EXPORT_SYMBOL(rtw89_mac_cfg_phy_rpt_be); +static +void rtw89_mac_set_edcca_mode_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool normal) +{ + u16 resp_ack, resp_rts, resp_rts_punc, resp_normal, resp_normal_punc; + + if (rtwdev->chip->chip_id == RTL8922A) + return; + + resp_ack = RESP_ACK_CFG_BE; + resp_rts = RESP_RTS_CFG_BE; + resp_rts_punc = RESP_RTS_PUNC_CFG_BE; + resp_normal = RESP_NORMAL_CFG_BE; + resp_normal_punc = RESP_NORMAL_PUNC_CFG_BE; + + if (normal) { + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_LEGACY, + resp_ack, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_HE, + resp_ack, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC, + resp_ack, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_RTS_RESP_LEGACY, + resp_rts, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_RTS_RESP_LEGACY_PUNC, + resp_rts_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_MURTS_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_MURTS_RESP_LEGACY_PUNC, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_HE, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_EHT_LEG_PUNC, + resp_normal_punc, mac_idx); + } else { + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_HE, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_RTS_RESP_LEGACY, + resp_rts, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_RTS_RESP_LEGACY_PUNC, + resp_rts_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_MURTS_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_MURTS_RESP_LEGACY_PUNC, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_HE, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_EHT_LEG_PUNC, + resp_normal_punc, mac_idx); + } +} + static int rtw89_mac_cfg_ppdu_status_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) { @@ -2993,6 +3052,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .typ_fltr_opt = rtw89_mac_typ_fltr_opt_be, .cfg_ppdu_status = rtw89_mac_cfg_ppdu_status_be, .cfg_phy_rpt = rtw89_mac_cfg_phy_rpt_be, + .set_edcca_mode = rtw89_mac_set_edcca_mode_be, .dle_mix_cfg = dle_mix_cfg_be, .chk_dle_rdy = chk_dle_rdy_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 8233841bb8ff..0555d2c0dee9 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7488,6 +7488,8 @@ #define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA20 BIT(2) #define B_BE_ACK_BA_RESP_LEGACY_CHK_EDCCA BIT(1) #define B_BE_ACK_BA_RESP_LEGACY_CHK_CCA BIT(0) +#define RESP_ACK_CFG_BE (B_BE_ACK_BA_RESP_LEGACY_CHK_BTCCA | \ + B_BE_ACK_BA_RESP_LEGACY_CHK_TX_NAV) #define R_BE_WMAC_ACK_BA_RESP_HE 0x11204 #define R_BE_WMAC_ACK_BA_RESP_HE_C1 0x15204 @@ -7529,6 +7531,188 @@ #define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_EDCCA BIT(1) #define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_CCA BIT(0) +#define R_BE_WMAC_RX_RTS_RESP_LEGACY 0x1120C +#define R_BE_WMAC_RX_RTS_RESP_LEGACY_C1 0x1520C +#define B_BE_RX_RTS_RESP_LEGACY_CHK_NSTR BIT(16) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV BIT(15) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_INTRA_NAV BIT(14) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV BIT(13) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA BIT(12) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA160 BIT(5) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA80 BIT(4) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA40 BIT(3) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA20 BIT(2) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA BIT(1) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_CCA BIT(0) +#define RESP_RTS_CFG_BE (B_BE_RX_RTS_RESP_LEGACY_CHK_CCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA20 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA40 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA80 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA160 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA20 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA40 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA80 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA160 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_INTRA_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV) +#define RESP_RTS_PUNC_CFG_BE (B_BE_RX_RTS_RESP_LEGACY_CHK_CCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_CCA_PER20_BMP | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA_PER20_BMP | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_INTRA_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV) +#define RESP_NORMAL_CFG_BE (B_BE_RX_RTS_RESP_LEGACY_CHK_CCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA20 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA40 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA80 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA160 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA20 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA40 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA80 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA160 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV) +#define RESP_NORMAL_PUNC_CFG_BE (B_BE_RX_RTS_RESP_LEGACY_CHK_CCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_CCA_PER20_BMP | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA_PER20_BMP | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV) + +#define R_BE_WMAC_RX_RTS_RESP_LEGACY_PUNC 0x11210 +#define R_BE_WMAC_RX_RTS_RESP_LEGACY_PUNC_C1 0x15210 +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_NSTR BIT(16) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_TX_NAV BIT(15) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_INTRA_NAV BIT(14) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_BASIC_NAV BIT(13) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_BTCCA BIT(12) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_CCA160 BIT(5) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_CCA80 BIT(4) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_CCA40 BIT(3) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_CCA20 BIT(2) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_EDCCA BIT(1) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_CCA BIT(0) + +#define R_BE_WMAC_RX_MURTS_RESP_LEGACY 0x11214 +#define R_BE_WMAC_RX_MURTS_RESP_LEGACY_C1 0x15214 +#define B_BE_MURTS_RESP_LEGACY_CHK_NSTR BIT(16) +#define B_BE_MURTS_RESP_LEGACY_CHK_TX_NAV BIT(15) +#define B_BE_MURTS_RESP_LEGACY_CHK_INTRA_NAV BIT(14) +#define B_BE_MURTS_RESP_LEGACY_CHK_BASIC_NAV BIT(13) +#define B_BE_MURTS_RESP_LEGACY_CHK_BTCCA BIT(12) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_MURTS_RESP_LEGACY_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_MURTS_RESP_LEGACY_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_CCA160 BIT(5) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_CCA80 BIT(4) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_CCA40 BIT(3) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_CCA20 BIT(2) +#define B_BE_MURTS_RESP_LEGACY_CHK_EDCCA BIT(1) +#define B_BE_MURTS_RESP_LEGACY_CHK_CCA BIT(0) + +#define R_BE_WMAC_RX_MURTS_RESP_LEGACY_PUNC 0x11218 +#define R_BE_WMAC_RX_MURTS_RESP_LEGACY_PUNC_C1 0x15218 +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_NSTR BIT(16) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_TX_NAV BIT(15) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_INTRA_NAV BIT(14) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_BASIC_NAV BIT(13) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_BTCCA BIT(12) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_CCA160 BIT(5) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_CCA80 BIT(4) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_CCA40 BIT(3) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_CCA20 BIT(2) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_EDCCA BIT(1) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_CCA BIT(0) + +#define R_BE_WMAC_OTHERS_RESP_LEGACY 0x1121C +#define R_BE_WMAC_OTHERS_RESP_LEGACY_C1 0x1521C +#define B_BE_OTHERS_RESP_LEGACY_CHK_NSTR BIT(16) +#define B_BE_OTHERS_RESP_LEGACY_CHK_TX_NAV BIT(15) +#define B_BE_OTHERS_RESP_LEGACY_CHK_INTRA_NAV BIT(14) +#define B_BE_OTHERS_RESP_LEGACY_CHK_BASIC_NAV BIT(13) +#define B_BE_OTHERS_RESP_LEGACY_CHK_BTCCA BIT(12) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_OTHERS_RESP_LEGACY_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_OTHERS_RESP_LEGACY_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_CCA160 BIT(5) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_CCA80 BIT(4) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_CCA40 BIT(3) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_CCA20 BIT(2) +#define B_BE_OTHERS_RESP_LEGACY_CHK_EDCCA BIT(1) +#define B_BE_OTHERS_RESP_LEGACY_CHK_CCA BIT(0) + +#define R_BE_WMAC_OTHERS_RESP_HE 0x11220 +#define R_BE_WMAC_OTHERS_RESP_HE_C1 0x15220 +#define B_BE_OTHERS_RESP_HE_CHK_NSTR BIT(16) +#define B_BE_OTHERS_RESP_HE_CHK_TX_NAV BIT(15) +#define B_BE_OTHERS_RESP_HE_CHK_INTRA_NAV BIT(14) +#define B_BE_OTHERS_RESP_HE_CHK_BASIC_NAV BIT(13) +#define B_BE_OTHERS_RESP_HE_CHK_BTCCA BIT(12) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_OTHERS_RESP_HE_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_OTHERS_RESP_HE_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_CCA160 BIT(5) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_CCA80 BIT(4) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_CCA40 BIT(3) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_CCA20 BIT(2) +#define B_BE_OTHERS_RESP_HE_CHK_EDCCA BIT(1) +#define B_BE_OTHERS_RESP_HE_CHK_CCA BIT(0) + +#define R_BE_WMAC_OTHERS_RESP_EHT_LEG_PUNC 0x11224 +#define R_BE_WMAC_OTHERS_RESP_EHT_LEG_PUNC_C1 0x15224 +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_NSTR BIT(16) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_TX_NAV BIT(15) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_INTRA_NAV BIT(14) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_BASIC_NAV BIT(13) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_BTCCA BIT(12) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_CCA160 BIT(5) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_CCA80 BIT(4) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_CCA40 BIT(3) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_CCA20 BIT(2) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_EDCCA BIT(1) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_CCA BIT(0) + #define R_BE_RCR 0x11400 #define R_BE_RCR_C1 0x15400 #define B_BE_BUSY_CHKSN BIT(15) From 3116f287b81fe777a00b93ab07ec3c270093b185 Mon Sep 17 00:00:00 2001 From: Zenm Chen Date: Mon, 12 Jan 2026 08:43:58 +0800 Subject: [PATCH 72/81] wifi: rtw89: Add support for MSI AX1800 Nano (GUAX18N) Add the ID 0db0:f0c8 to the table to support an additional RTL8832BU adapter: MSI AX1800 Nano (GUAX18N). Compile tested only. Link: https://github.com/morrownr/rtl8852bu-20250826/pull/2 Signed-off-by: Zenm Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260112004358.5516-1-zenmchen@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8852bu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c index 980d17ef68d0..84cd3ec971f9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c @@ -54,6 +54,8 @@ static const struct usb_device_id rtw_8852bu_id_table[] = { .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x0db0, 0x6931, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0db0, 0xf0c8, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3327, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6121, 0xff, 0xff, 0xff), From 292c0bc8acb687de7e83fc454bb98af19187b6bf Mon Sep 17 00:00:00 2001 From: Zenm Chen Date: Mon, 12 Jan 2026 08:47:59 +0800 Subject: [PATCH 73/81] wifi: rtw89: Add support for D-Link VR Air Bridge (DWA-F18) Add the ID 2001:3323 to the table to support an additional RTL8832AU adapter: D-Link VR Air Bridge (DWA-F18). Compile tested only. Link: https://github.com/morrownr/rtw89/pull/44 Signed-off-by: Zenm Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260112004759.6028-1-zenmchen@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8852au.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c index 74a976c984ad..ccdbcc178c2a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c @@ -52,6 +52,8 @@ static const struct usb_device_id rtw_8852au_id_table[] = { .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3321, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3323, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x332c, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x013f, 0xff, 0xff, 0xff), From 957eda596c7665f2966970fd1dcc35fe299b38e8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 10 Jan 2026 10:20:12 +0800 Subject: [PATCH 74/81] wifi: rtw89: pci: validate sequence number of TX release report Hardware rarely reports abnormal sequence number in TX release report, which will access out-of-bounds of wd_ring->pages array, causing NULL pointer dereference. BUG: kernel NULL pointer dereference, address: 0000000000000000 #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: 1085 Comm: irq/129-rtw89_p Tainted: G S U 6.1.145-17510-g2f3369c91536 #1 (HASH:69e8 1) Call Trace: rtw89_pci_release_tx+0x18f/0x300 [rtw89_pci (HASH:4c83 2)] rtw89_pci_napi_poll+0xc2/0x190 [rtw89_pci (HASH:4c83 2)] net_rx_action+0xfc/0x460 net/core/dev.c:6578 net/core/dev.c:6645 net/core/dev.c:6759 handle_softirqs+0xbe/0x290 kernel/softirq.c:601 ? rtw89_pci_interrupt_threadfn+0xc5/0x350 [rtw89_pci (HASH:4c83 2)] __local_bh_enable_ip+0xeb/0x120 kernel/softirq.c:499 kernel/softirq.c:423 rtw89_pci_interrupt_threadfn+0xf8/0x350 [rtw89_pci (HASH:4c83 2)] ? irq_thread+0xa7/0x340 kernel/irq/manage.c:0 irq_thread+0x177/0x340 kernel/irq/manage.c:1205 kernel/irq/manage.c:1314 ? thaw_kernel_threads+0xb0/0xb0 kernel/irq/manage.c:1202 ? irq_forced_thread_fn+0x80/0x80 kernel/irq/manage.c:1220 kthread+0xea/0x110 kernel/kthread.c:376 ? synchronize_irq+0x1a0/0x1a0 kernel/irq/manage.c:1287 ? kthread_associate_blkcg+0x80/0x80 kernel/kthread.c:331 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295 To prevent crash, validate rpp_info.seq before using. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260110022019.2254969-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index a66fcdb0293b..093960d7279f 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -604,11 +604,16 @@ static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev, void *rpp) info->parse_rpp(rtwdev, rpp, &rpp_info); - if (rpp_info.txch == RTW89_TXCH_CH12) { + if (unlikely(rpp_info.txch == RTW89_TXCH_CH12)) { rtw89_warn(rtwdev, "should no fwcmd release report\n"); return; } + if (unlikely(rpp_info.seq >= RTW89_PCI_TXWD_NUM_MAX)) { + rtw89_warn(rtwdev, "invalid seq %d\n", rpp_info.seq); + return; + } + tx_ring = &rtwpci->tx.rings[rpp_info.txch]; wd_ring = &tx_ring->wd_ring; txwd = &wd_ring->pages[rpp_info.seq]; From 2fd8f953f25173d14981d8736b6f5bfcd757e51b Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Sat, 10 Jan 2026 10:20:13 +0800 Subject: [PATCH 75/81] wifi: rtw89: wow: add reason codes for disassociation in WoWLAN mode Some APs disconnect clients by sending a Disassociation frame rather than a Deauthentication frame. Since these frames use different reason codes in WoWLAN mode, this commit adds support for handling Disassociation to prevent missed disconnection events. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260110022019.2254969-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/wow.c | 4 ++++ drivers/net/wireless/realtek/rtw89/wow.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 8224f0e3fb9a..5d3227e2b3e4 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -809,6 +809,10 @@ static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) reason = rtw89_read8(rtwdev, wow_reason_reg); switch (reason) { + case RTW89_WOW_RSN_RX_DISASSOC: + wakeup.disconnect = true; + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx disassoc\n"); + break; case RTW89_WOW_RSN_RX_DEAUTH: wakeup.disconnect = true; rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx deauth\n"); diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h index d2ba6cebc2a6..71e07f482174 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -33,6 +33,7 @@ enum rtw89_wake_reason { RTW89_WOW_RSN_RX_PTK_REKEY = 0x1, RTW89_WOW_RSN_RX_GTK_REKEY = 0x2, + RTW89_WOW_RSN_RX_DISASSOC = 0x4, RTW89_WOW_RSN_RX_DEAUTH = 0x8, RTW89_WOW_RSN_DISCONNECT = 0x10, RTW89_WOW_RSN_RX_MAGIC_PKT = 0x21, From 432b26382db2163b88db557ce91d20c18724be8a Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Sat, 10 Jan 2026 10:20:14 +0800 Subject: [PATCH 76/81] wifi: rtw89: support EHT GI/LTF setting Add support for fixed EHT GI/LTF via nl80211. The command example: iw wlan0 set bitrates eht-gi-6 0.8 eht-ltf-6 2 Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260110022019.2254969-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 38 ++++++++++++++---------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index d29fbc9cb5ac..0b72d3dcf666 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -281,8 +281,7 @@ static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev, struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask; u8 band = chan->band_type; enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band); - u8 he_ltf = mask->control[nl_band].he_ltf; - u8 he_gi = mask->control[nl_band].he_gi; + u8 ltf, gi; *fix_giltf_en = true; @@ -293,22 +292,31 @@ static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev, else *fix_giltf = RTW89_GILTF_2XHE08; - if (!(rtwsta_link->use_cfg_mask && link_sta->he_cap.has_he)) + if (!rtwsta_link->use_cfg_mask) return; - if (he_ltf == 2 && he_gi == 2) { - *fix_giltf = RTW89_GILTF_LGI_4XHE32; - } else if (he_ltf == 2 && he_gi == 0) { - *fix_giltf = RTW89_GILTF_SGI_4XHE08; - } else if (he_ltf == 1 && he_gi == 1) { - *fix_giltf = RTW89_GILTF_2XHE16; - } else if (he_ltf == 1 && he_gi == 0) { - *fix_giltf = RTW89_GILTF_2XHE08; - } else if (he_ltf == 0 && he_gi == 1) { - *fix_giltf = RTW89_GILTF_1XHE16; - } else if (he_ltf == 0 && he_gi == 0) { - *fix_giltf = RTW89_GILTF_1XHE08; + if (link_sta->eht_cap.has_eht) { + ltf = mask->control[nl_band].eht_ltf; + gi = mask->control[nl_band].eht_gi; + } else if (link_sta->he_cap.has_he) { + ltf = mask->control[nl_band].he_ltf; + gi = mask->control[nl_band].he_gi; + } else { + return; } + + if (ltf == 2 && gi == 2) + *fix_giltf = RTW89_GILTF_LGI_4XHE32; + else if (ltf == 2 && gi == 0) + *fix_giltf = RTW89_GILTF_SGI_4XHE08; + else if (ltf == 1 && gi == 1) + *fix_giltf = RTW89_GILTF_2XHE16; + else if (ltf == 1 && gi == 0) + *fix_giltf = RTW89_GILTF_2XHE08; + else if (ltf == 0 && gi == 1) + *fix_giltf = RTW89_GILTF_1XHE16; + else if (ltf == 0 && gi == 0) + *fix_giltf = RTW89_GILTF_1XHE08; } static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, From 7fd36ffedeedc97c44a10249a3f12d471bb2dc26 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 10 Jan 2026 10:20:15 +0800 Subject: [PATCH 77/81] wifi: rtw89: disable EHT protocol by chip capabilities For certain chip models, EHT protocol is disabled, and driver must follow the capabilities. Otherwise, chips become unusable. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260110022019.2254969-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 2 +- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.h | 4 ++++ drivers/net/wireless/realtek/rtw89/mac.c | 5 +++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 4cc5e32d778c..6e77522bcd8f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -5395,7 +5395,7 @@ static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev, u8 val, val_mcs13; int sts = 8; - if (chip->chip_gen == RTW89_CHIP_AX) + if (chip->chip_gen == RTW89_CHIP_AX || hal->no_eht) return; if (hal->no_mcs_12_13) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 8d5655138ded..29625c4fe4e9 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5130,6 +5130,7 @@ struct rtw89_hal { bool support_cckpd; bool support_igi; bool no_mcs_12_13; + bool no_eht; atomic_t roc_chanctx_idx; u8 roc_link_index; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 1542634f0146..018b3bed57d2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -42,6 +42,10 @@ struct rtw89_c2hreg_phycap { #define RTW89_C2HREG_PHYCAP_W0_BW GENMASK(31, 24) #define RTW89_C2HREG_PHYCAP_W1_TX_NSS GENMASK(7, 0) #define RTW89_C2HREG_PHYCAP_W1_PROT GENMASK(15, 8) +#define RTW89_C2HREG_PHYCAP_W1_PROT_11N 1 +#define RTW89_C2HREG_PHYCAP_W1_PROT_11AC 2 +#define RTW89_C2HREG_PHYCAP_W1_PROT_11AX 3 +#define RTW89_C2HREG_PHYCAP_W1_PROT_11BE 4 #define RTW89_C2HREG_PHYCAP_W1_NIC GENMASK(23, 16) #define RTW89_C2HREG_PHYCAP_W1_WL_FUNC GENMASK(31, 24) #define RTW89_C2HREG_PHYCAP_W2_HW_TYPE GENMASK(7, 0) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 3b9c6f9b7f5a..1435e4c664b6 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -3116,6 +3116,7 @@ static int rtw89_mac_setup_phycap_part0(struct rtw89_dev *rtwdev) struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw89_mac_c2h_info c2h_info = {}; struct rtw89_hal *hal = &rtwdev->hal; + u8 protocol; u8 tx_nss; u8 rx_nss; u8 tx_ant; @@ -3163,6 +3164,10 @@ static int rtw89_mac_setup_phycap_part0(struct rtw89_dev *rtwdev) rtw89_debug(rtwdev, RTW89_DBG_FW, "TX path diversity=%d\n", hal->tx_path_diversity); rtw89_debug(rtwdev, RTW89_DBG_FW, "Antenna diversity=%d\n", hal->ant_diversity); + protocol = u32_get_bits(phycap->w1, RTW89_C2HREG_PHYCAP_W1_PROT); + if (protocol < RTW89_C2HREG_PHYCAP_W1_PROT_11BE) + hal->no_eht = true; + return 0; } From 91fb4007018f5b59d810d894cc1d73c2af312f66 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 10 Jan 2026 10:20:16 +0800 Subject: [PATCH 78/81] wifi: rtw89: align CUSTID defined by firmware Firmware does customized features by CUSTID, so align the ID definition to have expected features enabled. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260110022019.2254969-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 29625c4fe4e9..1abd09d9d29c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -5193,13 +5193,15 @@ enum rtw89_quirks { }; enum rtw89_custid { - RTW89_CUSTID_NONE, - RTW89_CUSTID_ACER, - RTW89_CUSTID_AMD, - RTW89_CUSTID_ASUS, - RTW89_CUSTID_DELL, - RTW89_CUSTID_HP, - RTW89_CUSTID_LENOVO, + RTW89_CUSTID_NONE = 0, + RTW89_CUSTID_HP = 1, + RTW89_CUSTID_ASUS = 2, + RTW89_CUSTID_ACER = 3, + RTW89_CUSTID_LENOVO = 4, + RTW89_CUSTID_NEC = 5, + RTW89_CUSTID_AMD = 6, + RTW89_CUSTID_FUJITSU = 7, + RTW89_CUSTID_DELL = 8, }; enum rtw89_pkt_drop_sel { From aa2a44d0d22d45d659b9f01638809b1735e46cff Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 10 Jan 2026 10:20:17 +0800 Subject: [PATCH 79/81] wifi: rtw89: mac: correct page number for CSI response For beamforming procedure, hardware reserve memory page for CSI response. The unit of register is (value - 1), so add one accordingly as expected. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260110022019.2254969-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac_be.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 58135864786f..7c4ad59338d3 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -1486,7 +1486,7 @@ static int resp_pktctl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RESP_CSI_RESERVED_PAGE, mac_idx); rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_START_PAGE_MASK, qt_cfg.pktid); - rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_PAGE_NUM_MASK, qt_cfg.pg_num); + rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_PAGE_NUM_MASK, qt_cfg.pg_num + 1); return 0; } From 8e47ae0786933d467ed89a803501da9e7c781325 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 10 Jan 2026 10:20:18 +0800 Subject: [PATCH 80/81] wifi: rtw89: mac: consider RTL8922D in MAC common flow The MAC settings are different from RTL8922A to RTL8922D, including scheduler, DLE, DCPU, MLO, NAV, TMAC, TX/RX protocol, RMAC, IMR, host RPT, AMSDU. Update them accordingly. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260110022019.2254969-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac_be.c | 180 ++++++++++++++-- drivers/net/wireless/realtek/rtw89/reg.h | 217 ++++++++++++++++++++ 2 files changed, 376 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 7c4ad59338d3..142e892f85c4 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -219,6 +219,9 @@ static void dle_func_en_be(struct rtw89_dev *rtwdev, bool enable) static void dle_clk_en_be(struct rtw89_dev *rtwdev, bool enable) { + if (rtwdev->chip->chip_id != RTL8922A) + return; + if (enable) rtw89_write32_set(rtwdev, R_BE_DMAC_CLK_EN, B_BE_DLE_WDE_CLK_EN | B_BE_DLE_PLE_CLK_EN); @@ -605,7 +608,8 @@ static void rtw89_mac_disable_cpu_be(struct rtw89_dev *rtwdev) val32 &= B_BE_RUN_ENV_MASK; rtw89_write32(rtwdev, R_BE_WCPU_FW_CTRL, val32); - rtw89_write32_set(rtwdev, R_BE_DCPU_PLATFORM_ENABLE, B_BE_DCPU_PLATFORM_EN); + if (rtwdev->chip->chip_id == RTL8922A) + rtw89_write32_set(rtwdev, R_BE_DCPU_PLATFORM_ENABLE, B_BE_DCPU_PLATFORM_EN); rtw89_write32(rtwdev, R_BE_UDM0, 0); rtw89_write32(rtwdev, R_BE_HALT_C2H, 0); @@ -957,6 +961,11 @@ static int sta_sch_init_be(struct rtw89_dev *rtwdev) u32 p_val; int ret; + if (rtwdev->chip->chip_id == RTL8922D) { + rtw89_write32_set(rtwdev, R_BE_SS_LITE_TXL_MACID, B_BE_RPT_OTHER_BAND_EN); + return 0; + } + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); if (ret) return ret; @@ -986,14 +995,16 @@ static int mpdu_proc_init_be(struct rtw89_dev *rtwdev) return ret; rtw89_write32_set(rtwdev, R_BE_MPDU_PROC, B_BE_APPEND_FCS); - rtw89_write32(rtwdev, R_BE_CUT_AMSDU_CTRL, TRXCFG_MPDU_PROC_CUT_CTRL); + rtw89_write32(rtwdev, R_BE_CUT_AMSDU_CTRL, TRXCFG_MPDU_PROC_CUT_CTRL | + B_BE_CA_CHK_ADDRCAM_EN); val32 = rtw89_read32(rtwdev, R_BE_HDR_SHCUT_SETTING); val32 |= (B_BE_TX_HW_SEQ_EN | B_BE_TX_HW_ACK_POLICY_EN | B_BE_TX_MAC_MPDU_PROC_EN); val32 &= ~B_BE_TX_ADDR_MLD_TO_LIK; rtw89_write32_set(rtwdev, R_BE_HDR_SHCUT_SETTING, val32); - rtw89_write32(rtwdev, R_BE_RX_HDRTRNS, TRXCFG_MPDU_PROC_RX_HDR_CONV); + rtw89_write32(rtwdev, R_BE_RX_HDRTRNS, TRXCFG_MPDU_PROC_RX_HDR_CONV | + B_BE_HC_ADDR_HIT_EN); val32 = rtw89_read32(rtwdev, R_BE_DISP_FWD_WLAN_0); val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_0_DATA_MASK); @@ -1061,7 +1072,9 @@ static int txpktctrl_init_be(struct rtw89_dev *rtwdev) static int mlo_init_be(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val32; + u32 reg; int ret; val32 = rtw89_read32(rtwdev, R_BE_MLO_INIT_CTL); @@ -1077,7 +1090,12 @@ static int mlo_init_be(struct rtw89_dev *rtwdev) if (ret) rtw89_err(rtwdev, "[MLO]%s: MLO init polling timeout\n", __func__); - rtw89_write32_set(rtwdev, R_BE_SS_CTRL, B_BE_MLO_HW_CHGLINK_EN); + if (chip->chip_id == RTL8922A) + reg = R_BE_SS_CTRL; + else + reg = R_BE_SS_CTRL_V1; + + rtw89_write32_set(rtwdev, reg, B_BE_MLO_HW_CHGLINK_EN); rtw89_write32_set(rtwdev, R_BE_CMAC_SHARE_ACQCHK_CFG_0, B_BE_R_MACID_ACQ_CHK_EN); return ret; @@ -1140,6 +1158,7 @@ static int dmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) static int scheduler_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val32; u32 reg; int ret; @@ -1148,6 +1167,11 @@ static int scheduler_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) if (ret) return ret; + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_SCH_EXT_CTRL, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_CWCNT_PLUS_MODE); + } + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_HE_CTN_CHK_CCA_NAV, mac_idx); val32 = B_BE_HE_CTN_CHK_CCA_P20 | B_BE_HE_CTN_CHK_EDCCA_P20 | B_BE_HE_CTN_CHK_CCA_BITMAP | B_BE_HE_CTN_CHK_EDCCA_BITMAP | @@ -1181,6 +1205,11 @@ static int scheduler_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write32_mask(rtwdev, reg, B_BE_BCNQ_CW_MASK, 0x32); rtw89_write32_mask(rtwdev, reg, B_BE_BCNQ_AIFS_MASK, BCN_IFS_25US); + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_SCH_EDCA_RST_CFG, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_TX_NAV_RST_EDCA_EN); + } + return 0; } @@ -1296,6 +1325,9 @@ static int nav_ctrl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write32(rtwdev, reg, val32); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_SPECIAL_TX_SETTING, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_BMC_NAV_PROTECT); + return 0; } @@ -1319,14 +1351,22 @@ static int spatial_reuse_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) static int tmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 reg; reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TB_PPDU_CTRL, mac_idx); rtw89_write32_clr(rtwdev, reg, B_BE_QOSNULL_UPD_MUEDCA_EN); - reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMTX_TCR_BE_4, mac_idx); - rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_4XLTF_ZLD_USTIMER_MASK, 0x12); - rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_2XLTF_ZLD_USTIMER_MASK, 0xe); + if (chip->chip_id == RTL8922A) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMTX_TCR_BE_4, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_4XLTF_ZLD_USTIMER_MASK, 0x12); + rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_2XLTF_ZLD_USTIMER_MASK, 0xe); + } + + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_COMMON_PHYINTF_CTRL_0, mac_idx); + rtw89_write32_clr(rtwdev, reg, CLEAR_DTOP_DIS); + } return 0; } @@ -1351,6 +1391,15 @@ static int trxptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) val32 &= ~B_BE_MACLBK_EN; rtw89_write32(rtwdev, reg, val32); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_PHYINTF_EN); + + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_PLCP_EXT_OPTION_2, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_PLCP_PHASE_B_CRC_CHK_EN | + B_BE_PLCP_PHASE_A_CRC_CHK_EN); + } + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_0, mac_idx); val32 = rtw89_read32(rtwdev, reg); val32 = u32_replace_bits(val32, WMAC_SPEC_SIFS_CCK, @@ -1420,6 +1469,7 @@ static int rst_bacam_be(struct rtw89_dev *rtwdev) static int rmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 rx_min_qta, rx_max_len, rx_max_pg; u16 val16; u32 reg; @@ -1463,6 +1513,17 @@ static int rmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_PLCP_EXT_OPTION_1, mac_idx); rtw89_write16_set(rtwdev, reg, B_BE_PLCP_SU_PSDU_LEN_SRC); + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_BSR_UPD_CTRL, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_QSIZE_RULE); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RXGCK_CTRL, mac_idx); + rtw89_write16_mask(rtwdev, reg, B_BE_RXGCK_GCK_RATE_LIMIT_MASK, RX_GCK_LEGACY); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PLCP_HDR_FLTR, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_DIS_CHK_MIN_LEN); + } + return 0; } @@ -1521,6 +1582,7 @@ static int cmac_com_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) static int ptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val32; u8 val8; u32 reg; @@ -1535,8 +1597,9 @@ static int ptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) val32 = rtw89_read32(rtwdev, reg); val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_1K, B_BE_HW_CTS2SELF_PKT_LEN_TH_MASK); - val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_SEC_256B, - B_BE_HW_CTS2SELF_PKT_LEN_TH_TWW_MASK); + if (chip->chip_id == RTL8922A) + val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_SEC_256B, + B_BE_HW_CTS2SELF_PKT_LEN_TH_TWW_MASK); val32 |= B_BE_HW_CTS2SELF_EN; rtw89_write32(rtwdev, reg, val32); @@ -1557,7 +1620,46 @@ static int ptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write8(rtwdev, reg, val8); reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AMPDU_AGG_LIMIT, mac_idx); - rtw89_write32_mask(rtwdev, reg, B_BE_AMPDU_MAX_TIME_MASK, AMPDU_MAX_TIME); + if (chip->chip_id == RTL8922A) + val32 = AMPDU_MAX_TIME; + else + val32 = AMPDU_MAX_TIME_V1; + rtw89_write32_mask(rtwdev, reg, B_BE_AMPDU_MAX_TIME_MASK, val32); + + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AGG_BK_0, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_WDBK_CFG | B_BE_EN_RTY_BK | + B_BE_EN_RTY_BK_COD); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AMPDU_AGG_LIMIT, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_MAX_AGG_NUM_MASK, + MAX_TX_AMPDU_NUM_V1 - 1); + } + + if (rtw89_mac_chk_preload_allow(rtwdev)) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AGG_BK_0, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_PRELD_MGQ0_EN | + B_BE_PRELD_HIQ_P4_EN | + B_BE_PRELD_HIQ_P3_EN | + B_BE_PRELD_HIQ_P2_EN | + B_BE_PRELD_HIQ_P1_EN | + B_BE_PRELD_HIQ_P0MB15_EN | + B_BE_PRELD_HIQ_P0MB14_EN | + B_BE_PRELD_HIQ_P0MB13_EN | + B_BE_PRELD_HIQ_P0MB12_EN | + B_BE_PRELD_HIQ_P0MB11_EN | + B_BE_PRELD_HIQ_P0MB10_EN | + B_BE_PRELD_HIQ_P0MB9_EN | + B_BE_PRELD_HIQ_P0MB8_EN | + B_BE_PRELD_HIQ_P0MB7_EN | + B_BE_PRELD_HIQ_P0MB6_EN | + B_BE_PRELD_HIQ_P0MB5_EN | + B_BE_PRELD_HIQ_P0MB4_EN | + B_BE_PRELD_HIQ_P0MB3_EN | + B_BE_PRELD_HIQ_P0MB2_EN | + B_BE_PRELD_HIQ_P0MB1_EN | + B_BE_PRELD_HIQ_P0_EN); + } return 0; } @@ -1844,22 +1946,22 @@ static int dle_quota_change_be(struct rtw89_dev *rtwdev, bool band1_en) static int preload_init_be(struct rtw89_dev *rtwdev, u8 mac_idx, enum rtw89_qta_mode mode) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 max_preld_size, min_rsvd_size; + u8 preld_acq, preld_miscq; u32 val32; u32 reg; + if (!(chip->chip_id == RTL8922A || rtw89_mac_chk_preload_allow(rtwdev))) + return 0; + max_preld_size = mac_idx == RTW89_MAC_0 ? PRELD_B0_ENT_NUM : PRELD_B1_ENT_NUM; + if (chip->chip_id == RTL8922D) + max_preld_size = PRELD_B01_ENT_NUM_8922D; max_preld_size *= PRELD_AMSDU_SIZE; + min_rsvd_size = PRELD_NEXT_MIN_SIZE; - reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG0 : - R_BE_TXPKTCTL_B1_PRELD_CFG0; - val32 = rtw89_read32(rtwdev, reg); - val32 = u32_replace_bits(val32, max_preld_size, B_BE_B0_PRELD_USEMAXSZ_MASK); - val32 |= B_BE_B0_PRELD_FEN; - rtw89_write32(rtwdev, reg, val32); - - min_rsvd_size = PRELD_AMSDU_SIZE; reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG1 : R_BE_TXPKTCTL_B1_PRELD_CFG1; val32 = rtw89_read32(rtwdev, reg); @@ -1867,6 +1969,24 @@ static int preload_init_be(struct rtw89_dev *rtwdev, u8 mac_idx, val32 = u32_replace_bits(val32, min_rsvd_size, B_BE_B0_PRELD_NXT_RSVMINSZ_MASK); rtw89_write32(rtwdev, reg, val32); + reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG0 : + R_BE_TXPKTCTL_B1_PRELD_CFG0; + if (chip->chip_id == RTL8922D) { + preld_acq = PRELD_ACQ_ENT_NUM_8922D; + preld_miscq = PRELD_MISCQ_ENT_NUM_8922D; + } else { + preld_acq = mac_idx == RTW89_MAC_0 ? PRELD_B0_ACQ_ENT_NUM_8922A : + PRELD_B1_ACQ_ENT_NUM_8922A; + preld_miscq = PRELD_MISCQ_ENT_NUM_8922A; + } + + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, preld_acq, B_BE_B0_PRELD_CAM_G0ENTNUM_MASK); + val32 = u32_replace_bits(val32, preld_miscq, B_BE_B0_PRELD_CAM_G1ENTNUM_MASK); + val32 = u32_replace_bits(val32, max_preld_size, B_BE_B0_PRELD_USEMAXSZ_MASK); + val32 |= B_BE_B0_PRELD_FEN; + rtw89_write32(rtwdev, reg, val32); + return 0; } @@ -1899,6 +2019,10 @@ static int enable_imr_be(struct rtw89_dev *rtwdev, u8 mac_idx, else return -EINVAL; + if (chip->chip_id == RTL8922D) + rtw89_write32_mask(rtwdev, R_BE_NO_RX_ERR_CFG, + B_BE_NO_RX_ERR_TO_MASK, 0); + for (i = 0; i < table->n_regs; i++) { reg = &table->regs[i]; addr = rtw89_mac_reg_by_idx(rtwdev, reg->addr, mac_idx); @@ -2054,26 +2178,40 @@ static int dbcc_enable_be(struct rtw89_dev *rtwdev, bool enable) static int set_host_rpr_be(struct rtw89_dev *rtwdev) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val32; u32 mode; u32 fltr; + u32 qid; bool poh; poh = is_qta_poh(rtwdev); if (poh) { mode = RTW89_RPR_MODE_POH; - fltr = S_BE_WDRLS_FLTR_TXOK | S_BE_WDRLS_FLTR_RTYLMT | - S_BE_WDRLS_FLTR_LIFTIM | S_BE_WDRLS_FLTR_MACID; + qid = WDRLS_DEST_QID_POH; } else { mode = RTW89_RPR_MODE_STF; fltr = 0; + qid = WDRLS_DEST_QID_STF; + } + + if (chip_id == RTL8922A) { + fltr = S_BE_WDRLS_FLTR_TXOK | S_BE_WDRLS_FLTR_RTYLMT | + S_BE_WDRLS_FLTR_LIFTIM | S_BE_WDRLS_FLTR_MACID; + } else { + fltr = S_BE_WDRLS_FLTR_TXOK_V1 | S_BE_WDRLS_FLTR_RTYLMT_V1 | + S_BE_WDRLS_FLTR_LIFTIM_V1 | S_BE_WDRLS_FLTR_MACID_V1; } rtw89_write32_mask(rtwdev, R_BE_WDRLS_CFG, B_BE_WDRLS_MODE_MASK, mode); + rtw89_write32_mask(rtwdev, R_BE_RLSRPT0_CFG0, B_BE_RLSRPT0_QID_MASK, qid); val32 = rtw89_read32(rtwdev, R_BE_RLSRPT0_CFG1); - val32 = u32_replace_bits(val32, fltr, B_BE_RLSRPT0_FLTR_MAP_MASK); + if (chip_id == RTL8922A) + val32 = u32_replace_bits(val32, fltr, B_BE_RLSRPT0_FLTR_MAP_MASK); + else + val32 = u32_replace_bits(val32, fltr, B_BE_RLSRPT0_FLTR_MAP_V1_MASK); val32 = u32_replace_bits(val32, 30, B_BE_RLSRPT0_AGGNUM_MASK); val32 = u32_replace_bits(val32, 255, B_BE_RLSRPT0_TO_MASK); rtw89_write32(rtwdev, R_BE_RLSRPT0_CFG1, val32); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 0555d2c0dee9..66794ecbaaa9 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -1967,7 +1967,9 @@ #define B_AX_B0_PRELD_FEN BIT(31) #define B_AX_B0_PRELD_USEMAXSZ_MASK GENMASK(25, 16) #define PRELD_B0_ENT_NUM 10 +#define PRELD_B01_ENT_NUM_8922D 2 #define PRELD_AMSDU_SIZE 52 +#define PRELD_NEXT_MIN_SIZE 255 #define B_AX_B0_PRELD_CAM_G1ENTNUM_MASK GENMASK(12, 8) #define B_AX_B0_PRELD_CAM_G0ENTNUM_MASK GENMASK(4, 0) @@ -4647,6 +4649,10 @@ #define R_BE_LTR_LATENCY_IDX2_V1 0x361C #define R_BE_LTR_LATENCY_IDX3_V1 0x3620 +#define R_BE_HCI_BUF_IMR 0x6018 +#define B_BE_HCI_BUF_IMR_CLR 0xC0000303 +#define B_BE_HCI_BUF_IMR_SET 0xC0000301 + #define R_BE_H2CREG_DATA0 0x7140 #define R_BE_H2CREG_DATA1 0x7144 #define R_BE_H2CREG_DATA2 0x7148 @@ -4741,6 +4747,9 @@ #define B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK GENMASK(27, 16) #define B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK GENMASK(11, 0) +#define R_BE_NO_RX_ERR_CFG 0x841C +#define B_BE_NO_RX_ERR_TO_MASK GENMASK(31, 29) + #define R_BE_DMAC_TABLE_CTRL 0x8420 #define B_BE_HWAMSDU_PADDING_MODE BIT(31) #define B_BE_MACID_MPDU_PROCESSOR_OFFSET_MASK GENMASK(26, 16) @@ -5074,6 +5083,8 @@ B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN | \ B_BE_STF_OQT_OVERFLOW_ERR_INT_EN | \ B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN) +#define B_BE_DISP_OTHER_IMR_CLR_V1 0xFFFFFFFF +#define B_BE_DISP_OTHER_IMR_SET_V1 0x3F002000 #define R_BE_DISP_HOST_IMR 0x8874 #define B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN BIT(31) @@ -5151,6 +5162,8 @@ B_BE_HR_DMA_PROCESS_ERR_INT_EN | \ B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN | \ B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN) +#define B_BE_DISP_HOST_IMR_CLR_V1 0xFBFFFFFF +#define B_BE_DISP_HOST_IMR_SET_V1 0xC8B3E579 #define R_BE_DISP_CPU_IMR 0x8878 #define B_BE_CR_PLD_LEN_ERR_INT_EN BIT(30) @@ -5225,6 +5238,8 @@ B_BE_CR_DMA_PROCESS_ERR_INT_EN | \ B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN | \ B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN) +#define B_BE_DISP_CPU_IMR_CLR_V1 0x7DFFFFFD +#define B_BE_DISP_CPU_IMR_SET_V1 0x34F938FD #define R_BE_RX_STOP 0x8914 #define B_BE_CPU_RX_STOP BIT(17) @@ -5580,7 +5595,21 @@ B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN | \ B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN) +#define R_BE_RLSRPT0_CFG0 0x9440 +#define B_BE_RLSRPT0_FWRLS BIT(31) +#define B_BE_RLSRPT0_FWD_TRGT_MASK GENMASK(23, 16) +#define B_BE_RLSRPT0_PID_MASK GENMASK(10, 8) +#define B_BE_RLSRPT0_QID_MASK GENMASK(5, 0) +#define WDRLS_DEST_QID_POH 1 +#define WDRLS_DEST_QID_STF 0 + #define R_BE_RLSRPT0_CFG1 0x9444 +#define B_BE_RLSRPT0_FLTR_MAP_V1_MASK GENMASK(28, 24) +#define S_BE_WDRLS_FLTR_TXOK_V1 BIT(0) +#define S_BE_WDRLS_FLTR_RTYLMT_V1 BIT(1) +#define S_BE_WDRLS_FLTR_LIFTIM_V1 BIT(2) +#define S_BE_WDRLS_FLTR_MACID_V1 BIT(3) +#define S_BE_WDRLS_FLTR_RELINK_V1 BIT(4) #define B_BE_RLSRPT0_FLTR_MAP_MASK GENMASK(27, 24) #define S_BE_WDRLS_FLTR_TXOK 1 #define S_BE_WDRLS_FLTR_RTYLMT 2 @@ -5880,7 +5909,12 @@ #define B_BE_B0_PRELD_FEN BIT(31) #define B_BE_B0_PRELD_USEMAXSZ_MASK GENMASK(25, 16) #define B_BE_B0_PRELD_CAM_G1ENTNUM_MASK GENMASK(12, 8) +#define PRELD_MISCQ_ENT_NUM_8922A 2 +#define PRELD_MISCQ_ENT_NUM_8922D 1 #define B_BE_B0_PRELD_CAM_G0ENTNUM_MASK GENMASK(4, 0) +#define PRELD_B0_ACQ_ENT_NUM_8922A 8 +#define PRELD_B1_ACQ_ENT_NUM_8922A 2 +#define PRELD_ACQ_ENT_NUM_8922D 1 #define R_BE_TXPKTCTL_B0_PRELD_CFG1 0x9F4C #define B_BE_B0_PRELD_NXT_TXENDWIN_MASK GENMASK(11, 8) @@ -5992,6 +6026,7 @@ #define B_BE_PLRLS_CTL_FRZTO_ISR BIT(0) #define R_BE_SS_CTRL 0xA310 +#define R_BE_SS_CTRL_V1 0xA610 #define B_BE_SS_INIT_DONE BIT(31) #define B_BE_WDE_STA_DIS BIT(30) #define B_BE_WARM_INIT BIT(29) @@ -6031,6 +6066,24 @@ #define B_BE_RPT_TIMEOUT_ISR BIT(1) #define B_BE_SEARCH_TIMEOUT_ISR BIT(0) +#define R_BE_PLRLS_ERR_IMR_V1 0xA518 +#define B_BE_PLRLS_DUMMY_ISR6 BIT(7) +#define B_BE_PLRLS_DUMMY_ISR5 BIT(6) +#define B_BE_PLRLS_DUMMY_ISR4 BIT(5) +#define B_BE_PLRLS_DUMMY_ISR3 BIT(4) +#define B_BE_PLRLS_DUMMY_ISR2 BIT(3) +#define B_BE_PLRLS_DUMMY_ISR1 BIT(2) +#define B_BE_PLRLS_DUMMY_ISR0 BIT(1) +#define B_BE_PLRLS_ERR_IMR_V1_CLR 0x1 +#define B_BE_PLRLS_ERR_IMR_V1_SET 0x1 + +#define R_BE_SS_LITE_TXL_MACID 0xA790 +#define B_BE_RPT_OTHER_BAND_EN BIT(31) +#define B_BE_TXL_CMD_EN BIT(30) +#define B_BE_TXL_READ_MACID_MASK GENMASK(29, 20) +#define B_BE_TXL_MACID_1_MASK GENMASK(19, 10) +#define B_BE_TXL_MACID_0_MASK GENMASK(9, 0) + #define R_BE_HAXI_INIT_CFG1 0xB000 #define B_BE_CFG_WD_PERIOD_IDLE_MASK GENMASK(31, 28) #define B_BE_CFG_WD_PERIOD_ACTIVE_MASK GENMASK(27, 24) @@ -6396,6 +6449,21 @@ #define B_BE_RSC_MASK GENMASK(7, 6) #define B_BE_RRSR_CCK_MASK GENMASK(3, 0) +#define R_BE_COMMON_PHYINTF_CTRL_0 0x100B8 +#define R_BE_COMMON_PHYINTF_CTRL_0_C1 0x140B8 +#define B_BE_SEQ_EN_GUARD_CYE_MASK GENMASK(23, 20) +#define B_BE_PARA_FIFO_CRC_EN BIT(18) +#define B_BE_SEQ_FIFO_TO_EN BIT(17) +#define B_BE_PARA_FIFO_TO_EN BIT(16) +#define B_BE_SEQ_FIFO_CLR_EN BIT(6) +#define B_BE_PARA_FIFO_CLR_EN_V1 BIT(5) +#define B_BE_CSI_FIFO_CLR_EN_V1 BIT(4) +#define B_BE_FTM_FIFO_CLR_EN_V1 BIT(3) +#define B_BE_RXD_FIFO_CLR_EN_V1 BIT(2) +#define B_BE_TXD_FIFO_CLR_EN_V1 BIT(1) +#define B_BE_TXUID_FIFO_CLR_EN_V1 BIT(0) +#define CLEAR_DTOP_DIS (BIT(1) | BIT(5) | BIT(6)) + #define R_BE_CMAC_ERR_IMR 0x10160 #define R_BE_CMAC_ERR_IMR_C1 0x14160 #define B_BE_CMAC_FW_ERR_IDCT_EN BIT(16) @@ -6488,6 +6556,25 @@ #define B_BE_P0_SYNC_PORT_SRC_SEL_MASK GENMASK(26, 24) #define B_BE_P0_TSFTR_SYNC_OFFSET_MASK GENMASK(18, 0) +#define R_BE_SCH_EDCA_RST_CFG 0x102E4 +#define R_BE_SCH_EDCA_RST_CFG_C1 0x142E4 +#define B_BE_EDCCA_S160_RST_EDCA_EN BIT(23) +#define B_BE_EDCCA_S80_RST_EDCA_EN BIT(22) +#define B_BE_EDCCA_S40_RST_EDCA_EN BIT(21) +#define B_BE_EDCCA_S20_RST_EDCA_EN BIT(20) +#define B_BE_OFDM_CCA_S160_RST_EDCA_EN BIT(19) +#define B_BE_CCA_PEB_BE_BITMAP_RST_EDCA_EN BIT(18) +#define B_BE_RX_INTRA_NAV_RST_EDCA_EN BIT(15) +#define B_BE_RX_BASIC_NAV_RST_EDCA_EN BIT(14) +#define B_BE_EDCCA_PER20_BITMAP_SIFS_RST_EDCA_EN BIT(10) +#define B_BE_TX_NAV_RST_EDCA_EN BIT(7) +#define B_BE_NO_GNT_WL_RST_EDCA_EN BIT(5) +#define B_BE_EDCCA_P20_RST_EDCA_EN BIT(4) +#define B_BE_OFDM_CCA_S80_RST_EDCA_EN BIT(3) +#define B_BE_OFDM_CCA_S40_RST_EDCA_EN BIT(2) +#define B_BE_OFDM_CCA_S20_RST_EDCA_EN BIT(1) +#define B_BE_CCA_P20_RST_EDCA_EN BIT(0) + #define R_BE_EDCA_BCNQ_PARAM 0x10324 #define R_BE_EDCA_BCNQ_PARAM_C1 0x14324 #define B_BE_BCNQ_CW_MASK GENMASK(31, 24) @@ -6778,6 +6865,34 @@ #define B_BE_CMAC_TX_MODE_1 BIT(1) #define B_BE_CMAC_TX_MODE_0 BIT(0) +#define R_BE_AGG_BK_0 0x10804 +#define R_BE_AGG_BK_0_C1 0x14804 +#define B_BE_DIS_SAMPDU_TXIME_SR_CHECK BIT(24) +#define B_BE_TX_PAIR_MACID_LEN_EN BIT(23) +#define B_BE_DIS_SND_STS_CHECK_SU BIT(22) +#define B_BE_MAX_AGG_NUM_FIX_MODE_EN_V1 BIT(21) +#define B_BE_DIS_SIFS_BK_AGG_AMPDU BIT(20) +#define B_BE_EN_MU2SU_CHK_PROTECT_PPDU BIT(19) +#define B_BE_RPT_TXOP_START_PROTECT BIT(18) +#define B_BE_RANDOM_GEN_CMD_ABORT_EN BIT(17) +#define B_BE_PHYTXON_ENDPS_RESP_CHK BIT(16) +#define B_BE_CTN_CHK_SEQ_REQ_EN BIT(15) +#define B_BE_PTCL_RLS_ALLFAIL_EN BIT(14) +#define B_BE_DIS_MURU_PRI_Q_EMPTY_CHK BIT(13) +#define B_BE_DIS_MURU_SEC_Q_EMPTY_CHK BIT(12) +#define B_BE_EN_SAMPDU_TXIME_TWT_CHECK BIT(11) +#define B_BE_DIS_SAMPDU_TXIME_P2P_CHECK BIT(10) +#define B_BE_DIS_SAMPDU_TXIME_BCN_CHECK BIT(9) +#define B_BE_DIS_UL_SEQ_ABORT_CHECK BIT(8) +#define B_BE_DIS_SND_STS_CHECK BIT(7) +#define B_BE_NAV_PAUS_PHB_EN BIT(6) +#define B_BE_TXOP_SHT_PHB_EN BIT(5) +#define B_BE_AGG_BRK_PHB_EN BIT(4) +#define B_BE_DIS_SSN_CHK BIT(3) +#define B_BE_WDBK_CFG BIT(2) +#define B_BE_EN_RTY_BK BIT(1) +#define B_BE_EN_RTY_BK_COD BIT(0) + #define R_BE_TB_PPDU_CTRL 0x1080C #define R_BE_TB_PPDU_CTRL_C1 0x1480C #define B_BE_TB_PPDU_BK_DIS BIT(15) @@ -6792,9 +6907,11 @@ #define R_BE_AMPDU_AGG_LIMIT_C1 0x14810 #define B_BE_AMPDU_MAX_TIME_MASK GENMASK(31, 24) #define AMPDU_MAX_TIME 0x9E +#define AMPDU_MAX_TIME_V1 0xA4 #define B_BE_RA_TRY_RATE_AGG_LMT_MASK GENMASK(23, 16) #define B_BE_RTS_MAX_AGG_NUM_MASK GENMASK(15, 8) #define B_BE_MAX_AGG_NUM_MASK GENMASK(7, 0) +#define MAX_TX_AMPDU_NUM_V1 128 #define R_BE_AGG_LEN_HT_0 0x10814 #define R_BE_AGG_LEN_HT_0_C1 0x14814 @@ -6802,6 +6919,20 @@ #define B_BE_RTS_TXTIME_TH_MASK GENMASK(15, 8) #define B_BE_RTS_LEN_TH_MASK GENMASK(7, 0) +#define R_BE_SPECIAL_TX_SETTING 0x10820 +#define R_BE_SPECIAL_TX_SETTING_C1 0x14820 +#define B_BE_TRI_PADDING_EXTEND BIT(31) +#define B_BE_TX_SN_BYPASS_EN BIT(30) +#define B_BE_USE_DATA_BW BIT(29) +#define B_BE_BW_SIGTA_MASK GENMASK(28, 27) +#define B_BE_BMC_NAV_PROTECT BIT(26) +#define B_BE_F2P_KEEP_NON_SR_CMD BIT(25) +#define B_BE_F2P_SU_FIXRATE_OVER_WD BIT(24) +#define B_BE_BAR_TXRATE_FOR_NULL_WD_MASK GENMASK(23, 20) +#define B_BE_STBC_CFEND_MASK GENMASK(19, 18) +#define B_BE_STBC_CFEND_RATE_MASK GENMASK(17, 9) +#define B_BE_BASIC_CFEND_RATE_MASK GENMASK(8, 0) + #define R_BE_SIFS_SETTING 0x10824 #define R_BE_SIFS_SETTING_C1 0x14824 #define B_BE_HW_CTS2SELF_PKT_LEN_TH_MASK GENMASK(31, 24) @@ -6835,6 +6966,44 @@ #define B_BE_PORT_DROP_4_0_MASK GENMASK(20, 16) #define B_BE_MBSSID_DROP_15_0_MASK GENMASK(15, 0) +#define R_BE_PTCL_PRELD_CTRL 0x10868 +#define R_BE_PTCL_PRELD_CTRL_C1 0x14868 +#define B_BE_PRELD_MGQ2_EN BIT(22) +#define B_BE_PRELD_MGQ1_EN BIT(21) +#define B_BE_PRELD_MGQ0_EN BIT(20) +#define B_BE_PRELD_HIQ_P4_EN BIT(19) +#define B_BE_PRELD_HIQ_P3_EN BIT(18) +#define B_BE_PRELD_HIQ_P2_EN BIT(17) +#define B_BE_PRELD_HIQ_P1_EN BIT(16) +#define B_BE_PRELD_HIQ_P0MB15_EN BIT(15) +#define B_BE_PRELD_HIQ_P0MB14_EN BIT(14) +#define B_BE_PRELD_HIQ_P0MB13_EN BIT(13) +#define B_BE_PRELD_HIQ_P0MB12_EN BIT(12) +#define B_BE_PRELD_HIQ_P0MB11_EN BIT(11) +#define B_BE_PRELD_HIQ_P0MB10_EN BIT(10) +#define B_BE_PRELD_HIQ_P0MB9_EN BIT(9) +#define B_BE_PRELD_HIQ_P0MB8_EN BIT(8) +#define B_BE_PRELD_HIQ_P0MB7_EN BIT(7) +#define B_BE_PRELD_HIQ_P0MB6_EN BIT(6) +#define B_BE_PRELD_HIQ_P0MB5_EN BIT(5) +#define B_BE_PRELD_HIQ_P0MB4_EN BIT(4) +#define B_BE_PRELD_HIQ_P0MB3_EN BIT(3) +#define B_BE_PRELD_HIQ_P0MB2_EN BIT(2) +#define B_BE_PRELD_HIQ_P0MB1_EN BIT(1) +#define B_BE_PRELD_HIQ_P0_EN BIT(0) +#define B_BE_PRELD_HIQ_ALL_EN (B_BE_PRELD_HIQ_P0_EN | B_BE_PRELD_HIQ_P1_EN | \ + B_BE_PRELD_HIQ_P2_EN | B_BE_PRELD_HIQ_P3_EN | \ + B_BE_PRELD_HIQ_P4_EN) +#define B_BE_PRELD_HIQ_P0MB_ALL_EN \ + (B_BE_PRELD_HIQ_P0_EN | B_BE_PRELD_HIQ_P0MB1_EN | \ + B_BE_PRELD_HIQ_P0MB2_EN | B_BE_PRELD_HIQ_P0MB3_EN | \ + B_BE_PRELD_HIQ_P0MB4_EN | B_BE_PRELD_HIQ_P0MB5_EN | \ + B_BE_PRELD_HIQ_P0MB6_EN | B_BE_PRELD_HIQ_P0MB7_EN | \ + B_BE_PRELD_HIQ_P0MB8_EN | B_BE_PRELD_HIQ_P0MB9_EN | \ + B_BE_PRELD_HIQ_P0MB10_EN | B_BE_PRELD_HIQ_P0MB11_EN | \ + B_BE_PRELD_HIQ_P0MB12_EN | B_BE_PRELD_HIQ_P0MB13_EN | \ + B_BE_PRELD_HIQ_P0MB14_EN | B_BE_PRELD_HIQ_P0MB15_EN) + #define R_BE_BT_PLT 0x1087C #define R_BE_BT_PLT_C1 0x1487C #define B_BE_BT_PLT_PKT_CNT_MASK GENMASK(31, 16) @@ -7075,6 +7244,8 @@ B_BE_RX_RU1_FSM_HANG_ERROR_IMR | \ B_BE_RX_RU0_FSM_HANG_ERROR_IMR | \ B_BE_RX_GET_NULL_PKT_ERROR_IMR) +#define B_BE_RX_ERROR_FLAG_IMR_CLR_V1 0x7FFFFFF8 +#define B_BE_RX_ERROR_FLAG_IMR_SET_V1 0x7FFFFF38 #define R_BE_RX_CTRL_1 0x10C0C #define R_BE_RX_CTRL_1_C1 0x14C0C @@ -7750,6 +7921,17 @@ #define B_BE_CCK_SIG_CHK BIT(1) #define B_BE_CCK_CRC_CHK BIT(0) +#define R_BE_RXGCK_CTRL 0x11406 +#define R_BE_RXGCK_CTRL_C1 0x15406 +#define B_BE_RXGCK_BCNPRS_DISGCLK BIT(12) +#define B_BE_RXGCK_GCK_RATE_LIMIT_MASK GENMASK(9, 8) +#define RX_GCK_LEGACY 2 +#define B_BE_RXGCK_DISREG_GCLK BIT(7) +#define B_BE_RXGCK_ENTRY_DELAY_MASK GENMASK(6, 4) +#define B_BE_RXGCK_GCK_CYCLE_MASK GENMASK(3, 2) +#define B_BE_RXGCK_CCA_EN BIT(1) +#define B_BE_DISGCLK BIT(0) + #define R_BE_RX_FLTR_OPT 0x11420 #define R_BE_RX_FLTR_OPT_C1 0x15420 #define B_BE_UID_FILTER_MASK GENMASK(31, 24) @@ -7844,6 +8026,11 @@ #define B_BE_CSIPRT_HESU_AID_EN BIT(25) #define B_BE_CSIPRT_VHTSU_AID_EN BIT(24) +#define R_BE_BSR_UPD_CTRL 0x11468 +#define R_BE_BSR_UPD_CTRL_C1 0x15468 +#define B_BE_QSIZE_RULE BIT(1) +#define B_BE_QSIZE_UPD BIT(0) + #define R_BE_DRV_INFO_OPTION 0x11470 #define R_BE_DRV_INFO_OPTION_C1 0x15470 #define B_BE_DRV_INFO_PHYRPT_EN BIT(0) @@ -7909,11 +8096,35 @@ #define B_BE_PLCP_CH20_WIDATA_SRC BIT(1) #define B_BE_PLCP_PPDU_TYPE_SRC BIT(0) +#define R_BE_RX_PLCP_EXT_OPTION_2 0x11518 +#define R_BE_RX_PLCP_EXT_OPTION_2_C1 0x15518 +#define B_BE_PLCP_PHASE_B_CRC_CHK_EN BIT(17) +#define B_BE_PLCP_PHASE_A_CRC_CHK_EN BIT(16) +#define B_BE_EHTTB_EHTSIG_CRC_CHK_EN BIT(3) +#define B_BE_EHTTB_USIG_CRC_CHK_EN BIT(2) +#define B_BE_EHTMU_EHTSIG_CRC_CHK_EN BIT(1) +#define B_BE_EHTMU_USIG_CRC_CHK_EN BIT(0) + #define R_BE_RESP_CSI_RESERVED_PAGE 0x11810 #define R_BE_RESP_CSI_RESERVED_PAGE_C1 0x15810 #define B_BE_CSI_RESERVED_PAGE_NUM_MASK GENMASK(27, 16) #define B_BE_CSI_RESERVED_START_PAGE_MASK GENMASK(11, 0) +#define R_BE_RESP_IMR1 0x11878 +#define R_BE_RESP_IMR1_C1 0x15878 +#define B_BE_RESP_IMR_1_MASK GENMASK(31, 9) +#define B_BE_FSM_TIMEOUT_ERR_IMR BIT(8) +#define B_BE_SEC_DOUBLE_HIT_ERR_IMR BIT(7) +#define B_BE_WRPTR_ERR_IMR BIT(6) +#define B_BE_SMR_TOO_MANY_PLD_ERR_IMR BIT(5) +#define B_BE_LMR_TOO_MANY_PLD_ERR_IMR BIT(4) +#define B_BE_CSI_TOO_MANY_PLD_ERR_IMR BIT(3) +#define B_BE_FTM_LMR_PLDID_READY_ERR_IMR BIT(2) +#define B_BE_SMR_PLDID_READY_ERR_IMR BIT(1) +#define B_BE_CSI_PLDID_READY_ERR_IMR BIT(0) +#define B_BE_RESP_IMR1_CLR 0x1FF +#define B_BE_RESP_IMR1_SET 0xFF + #define R_BE_RESP_IMR 0x11884 #define R_BE_RESP_IMR_C1 0x15884 #define B_BE_RESP_TBL_FLAG_ERR_ISR_EN BIT(17) @@ -7958,6 +8169,8 @@ B_BE_RESP_PLDID_RDY_ERR_ISR_EN | \ B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN | \ B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN) +#define B_BE_RESP_IMR_CLR_V1 0xFFFFFFFF +#define B_BE_RESP_IMR_SET_V1 0xFFFFFFFF #define R_BE_PWR_MODULE 0x11900 #define R_BE_PWR_MODULE_C1 0x15900 @@ -8036,6 +8249,10 @@ #define R_BE_TXPWR_ERR_FLAG_C1 0x158E4 #define R_BE_TXPWR_ERR_IMR_C1 0x158E0 +#define R_BE_SCH_EXT_CTRL 0x103FC +#define R_BE_SCH_EXT_CTRL_C1 0x143FC +#define B_BE_CWCNT_PLUS_MODE BIT(31) + #define CMAC1_START_ADDR_BE 0x14000 #define CMAC1_END_ADDR_BE 0x17FFF From 5e632c7ca9e15a1bc1e114bcfd5210add909e7a4 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 10 Jan 2026 10:20:19 +0800 Subject: [PATCH 81/81] wifi: rtw89: pci: consider RTL8922D in PCI common flow Clear TX/RX ring index, PCI operating mode, SER setting, PCI LTR and preinit settings. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260110022019.2254969-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.h | 31 +++++ drivers/net/wireless/realtek/rtw89/pci_be.c | 125 +++++++++++++++++--- drivers/net/wireless/realtek/rtw89/reg.h | 14 +++ 3 files changed, 151 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 64c080053fd1..b0081b694046 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -55,6 +55,8 @@ #define B_AX_CALIB_EN BIT(13) #define B_AX_DIV GENMASK(15, 14) #define RAC_SET_PPR_V1 0x31 +#define RAC_ANA41 0x41 +#define PHY_ERR_FLAG_EN BIT(6) #define R_AX_DBI_FLAG 0x1090 #define B_AX_DBI_RFLAG BIT(17) @@ -145,6 +147,11 @@ #define R_RAC_DIRECT_OFFSET_BE_LANE0_G2 0x3900 #define R_RAC_DIRECT_OFFSET_BE_LANE1_G2 0x3980 +#define RAC_DIRECT_OFFESET_L0_G1 0x3800 +#define RAC_DIRECT_OFFESET_L1_G1 0x3900 +#define RAC_DIRECT_OFFESET_L0_G2 0x3A00 +#define RAC_DIRECT_OFFESET_L1_G2 0x3B00 + #define RTW89_PCI_WR_RETRY_CNT 20 /* Interrupts */ @@ -296,6 +303,10 @@ #define B_BE_PCIE_EN_AUX_CLK BIT(0) #define R_BE_PCIE_PS_CTRL 0x3008 +#define B_BE_ASPM_L11_EN BIT(19) +#define B_BE_ASPM_L12_EN BIT(18) +#define B_BE_PCIPM_L11_EN BIT(17) +#define B_BE_PCIPM_L12_EN BIT(16) #define B_BE_RSM_L0S_EN BIT(8) #define B_BE_CMAC_EXIT_L1_EN BIT(7) #define B_BE_DMAC0_EXIT_L1_EN BIT(6) @@ -949,6 +960,12 @@ #define R_BE_PCIE_CRPWM 0x30C4 #define R_BE_L1_2_CTRL_HCILDO 0x3110 +#define B_BE_PM_CLKREQ_EXT_RB BIT(11) +#define B_BE_PCIE_DIS_RTK_PRST_N_L1_2 BIT(10) +#define B_BE_PCIE_PRST_IN_L1_2_RB BIT(9) +#define B_BE_PCIE_PRST_SEL_RB_V1 BIT(8) +#define B_BE_PCIE_DIS_L2_CTRL_APHY_SUSB BIT(7) +#define B_BE_PCIE_DIS_L1_2_CTRL_APHY_SUSB BIT(6) #define B_BE_PCIE_DIS_L1_2_CTRL_HCILDO BIT(0) #define R_BE_PL1_DBG_INFO 0x3120 @@ -998,9 +1015,11 @@ #define B_BE_PL1_SER_PL1_EN BIT(31) #define B_BE_PL1_IGNORE_HOT_RST BIT(30) #define B_BE_PL1_TIMER_UNIT_MASK GENMASK(19, 17) +#define PCIE_SER_TIMER_UNIT 0x2 #define B_BE_PL1_TIMER_CLEAR BIT(0) #define R_BE_REG_PL1_MASK 0x34B0 +#define B_BE_SER_LTSSM_UNSTABLE_MASK BIT(6) #define B_BE_SER_PCLKREQ_ACK_MASK BIT(5) #define B_BE_SER_PM_CLK_MASK BIT(4) #define B_BE_SER_LTSSM_IMR BIT(3) @@ -1030,6 +1049,18 @@ #define B_BE_CLR_CH2_IDX BIT(2) #define B_BE_CLR_CH1_IDX BIT(1) #define B_BE_CLR_CH0_IDX BIT(0) +#define B_BE_CLR_ALL_IDX_MASK (B_BE_CLR_CH0_IDX | B_BE_CLR_CH1_IDX | \ + B_BE_CLR_CH2_IDX | B_BE_CLR_CH3_IDX | \ + B_BE_CLR_CH4_IDX | B_BE_CLR_CH5_IDX | \ + B_BE_CLR_CH6_IDX | B_BE_CLR_CH7_IDX | \ + B_BE_CLR_CH8_IDX | B_BE_CLR_CH9_IDX | \ + B_BE_CLR_CH10_IDX | B_BE_CLR_CH11_IDX | \ + B_BE_CLR_CH12_IDX | B_BE_CLR_CH13_IDX | \ + B_BE_CLR_CH14_IDX) +#define B_BE_CLR_ALL_IDX_MASK_V1 (B_BE_CLR_CH0_IDX | B_BE_CLR_CH2_IDX | \ + B_BE_CLR_CH4_IDX | B_BE_CLR_CH6_IDX | \ + B_BE_CLR_CH8_IDX | B_BE_CLR_CH10_IDX | \ + B_BE_CLR_CH12_IDX) #define R_BE_RXBD_RWPTR_CLR1_V1 0xB018 #define B_BE_CLR_ROQ1_IDX_V1 BIT(5) diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 148cce0df058..33bdd3e66bf6 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -46,6 +46,14 @@ static void rtw89_pci_aspm_set_be(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_l1ss_set_be(struct rtw89_dev *rtwdev, bool enable) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + struct rtw89_hal *hal = &rtwdev->hal; + + if (enable && chip_id == RTL8922D && hal->cid == RTL8922D_CID7090) + rtw89_write32_set(rtwdev, R_BE_PCIE_PS_CTRL, + B_BE_ASPM_L11_EN | B_BE_ASPM_L12_EN | + B_BE_PCIPM_L11_EN | B_BE_PCIPM_L12_EN); + if (enable) rtw89_write32_set(rtwdev, R_BE_PCIE_MIX_CFG, B_BE_L1SUB_ENABLE); @@ -154,7 +162,7 @@ static void rtw89_pci_ctrl_trxdma_pcie_be(struct rtw89_dev *rtwdev, rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); - if (io_en == MAC_AX_PCIE_ENABLE) + if (io_en == MAC_AX_PCIE_ENABLE && rtwdev->chip->chip_id == RTL8922A) rtw89_write32_mask(rtwdev, R_BE_HAXI_MST_WDT_TIMEOUT_SEL_V1, B_BE_HAXI_MST_WDT_TIMEOUT_SEL_MASK, 4); } @@ -162,14 +170,15 @@ static void rtw89_pci_ctrl_trxdma_pcie_be(struct rtw89_dev *rtwdev, static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_pci_rx_ring *rx_ring; u32 val; - val = B_BE_CLR_CH0_IDX | B_BE_CLR_CH1_IDX | B_BE_CLR_CH2_IDX | - B_BE_CLR_CH3_IDX | B_BE_CLR_CH4_IDX | B_BE_CLR_CH5_IDX | - B_BE_CLR_CH6_IDX | B_BE_CLR_CH7_IDX | B_BE_CLR_CH8_IDX | - B_BE_CLR_CH9_IDX | B_BE_CLR_CH10_IDX | B_BE_CLR_CH11_IDX | - B_BE_CLR_CH12_IDX | B_BE_CLR_CH13_IDX | B_BE_CLR_CH14_IDX; + if (chip->chip_id == RTL8922A) + val = B_BE_CLR_ALL_IDX_MASK; + else + val = B_BE_CLR_ALL_IDX_MASK_V1; + rtw89_write32(rtwdev, R_BE_TXBD_RWPTR_CLR1, val); rtw89_write32(rtwdev, R_BE_RXBD_RWPTR_CLR1_V1, @@ -226,20 +235,24 @@ static int rtw89_pci_poll_dma_all_idle_be(struct rtw89_dev *rtwdev) static void rtw89_pci_mode_op_be(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val32_init1, val32_rxapp, val32_exp; val32_init1 = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); - val32_rxapp = rtw89_read32(rtwdev, R_BE_RX_APPEND_MODE); + if (chip->chip_id == RTL8922A) + val32_rxapp = rtw89_read32(rtwdev, R_BE_RX_APPEND_MODE); val32_exp = rtw89_read32(rtwdev, R_BE_HAXI_EXP_CTRL_V1); - if (info->rxbd_mode == MAC_AX_RXBD_PKT) { - val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_NORM, - B_BE_RXQ_RXBD_MODE_MASK); - } else if (info->rxbd_mode == MAC_AX_RXBD_SEP) { - val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_SEP, - B_BE_RXQ_RXBD_MODE_MASK); - val32_rxapp = u32_replace_bits(val32_rxapp, 0, - B_BE_APPEND_LEN_MASK); + if (chip->chip_id == RTL8922A) { + if (info->rxbd_mode == MAC_AX_RXBD_PKT) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_NORM, + B_BE_RXQ_RXBD_MODE_MASK); + } else if (info->rxbd_mode == MAC_AX_RXBD_SEP) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_SEP, + B_BE_RXQ_RXBD_MODE_MASK); + val32_rxapp = u32_replace_bits(val32_rxapp, 0, + B_BE_APPEND_LEN_MASK); + } } val32_init1 = u32_replace_bits(val32_init1, info->tx_burst, @@ -254,7 +267,8 @@ static void rtw89_pci_mode_op_be(struct rtw89_dev *rtwdev) B_BE_CFG_WD_PERIOD_ACTIVE_MASK); rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val32_init1); - rtw89_write32(rtwdev, R_BE_RX_APPEND_MODE, val32_rxapp); + if (chip->chip_id == RTL8922A) + rtw89_write32(rtwdev, R_BE_RX_APPEND_MODE, val32_rxapp); rtw89_write32(rtwdev, R_BE_HAXI_EXP_CTRL_V1, val32_exp); } @@ -280,6 +294,10 @@ static void rtw89_pci_debounce_be(struct rtw89_dev *rtwdev) static void rtw89_pci_ldo_low_pwr_be(struct rtw89_dev *rtwdev) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + struct rtw89_hal *hal = &rtwdev->hal; + u32 clr; + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_PSUS_OFF_CAPC_EN); rtw89_write32_set(rtwdev, R_BE_SYS_PAGE_CLK_GATED, B_BE_SOP_OFFPOOBS_PC | B_BE_CPHY_AUXCLK_OP | @@ -287,7 +305,16 @@ static void rtw89_pci_ldo_low_pwr_be(struct rtw89_dev *rtwdev) rtw89_write32_clr(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_PCIE_FORCE_IBX_EN | B_BE_PCIE_DIS_L2_RTK_PERST | B_BE_PCIE_DIS_L2__CTRL_LDO_HCI); - rtw89_write32_clr(rtwdev, R_BE_L1_2_CTRL_HCILDO, B_BE_PCIE_DIS_L1_2_CTRL_HCILDO); + + if (chip_id == RTL8922D && hal->cid == RTL8922D_CID7090) + clr = B_BE_PCIE_DIS_L1_2_CTRL_HCILDO | + B_BE_PCIE_DIS_L1_2_CTRL_APHY_SUSB | + B_BE_PCIE_DIS_RTK_PRST_N_L1_2 | + B_BE_PCIE_DIS_L2_CTRL_APHY_SUSB; + else + clr = B_BE_PCIE_DIS_L1_2_CTRL_HCILDO; + + rtw89_write32_clr(rtwdev, R_BE_L1_2_CTRL_HCILDO, clr); } static void rtw89_pci_pcie_setting_be(struct rtw89_dev *rtwdev) @@ -303,11 +330,25 @@ static void rtw89_pci_pcie_setting_be(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL); rtw89_write32_set(rtwdev, R_BE_PCIE_LAT_CTRL, B_BE_SYM_AUX_CLK_SEL); + + if (chip->chip_id != RTL8922D) + return; + + rtw89_write32_set(rtwdev, R_BE_RSV_CTRL, B_BE_R_SYM_PRST_CPHY_RST); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_USUS_OFFCAPC_EN); } static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + struct rtw89_hal *hal = &rtwdev->hal; u32 val32; + int ret; + + if (chip_id == RTL8922D) + goto be2_chips; + else if (chip_id != RTL8922A) + return; rtw89_write32(rtwdev, R_BE_PL1_DBG_INFO, 0x0); rtw89_write32_set(rtwdev, R_BE_FWS1IMR, B_BE_PCIE_SER_TIMEOUT_INDIC_EN); @@ -318,6 +359,43 @@ static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) val32 |= B_BE_SER_PMU_IMR | B_BE_SER_L1SUB_IMR | B_BE_SER_PM_MASTER_IMR | B_BE_SER_LTSSM_IMR | B_BE_SER_PM_CLK_MASK | B_BE_SER_PCLKREQ_ACK_MASK; rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32); + + return; + +be2_chips: + rtw89_write32_clr(rtwdev, R_BE_PCIE_SER_DBG, B_BE_PCIE_SER_FLUSH_RSTB); + rtw89_write32_set(rtwdev, R_BE_PCIE_SER_DBG, B_BE_PCIE_SER_FLUSH_RSTB); + + rtw89_write16_clr(rtwdev, RAC_DIRECT_OFFESET_L0_G1 + + RAC_ANA41 * RAC_MULT, PHY_ERR_FLAG_EN); + rtw89_write16_clr(rtwdev, RAC_DIRECT_OFFESET_L0_G2 + + RAC_ANA41 * RAC_MULT, PHY_ERR_FLAG_EN); + rtw89_write16_set(rtwdev, RAC_DIRECT_OFFESET_L0_G1 + + RAC_ANA41 * RAC_MULT, PHY_ERR_FLAG_EN); + rtw89_write16_set(rtwdev, RAC_DIRECT_OFFESET_L0_G2 + + RAC_ANA41 * RAC_MULT, PHY_ERR_FLAG_EN); + + val32 = rtw89_read32(rtwdev, R_BE_SER_PL1_CTRL); + val32 &= ~B_BE_PL1_SER_PL1_EN; + rtw89_write32(rtwdev, R_BE_SER_PL1_CTRL, val32); + + ret = read_poll_timeout_atomic(rtw89_read32, val32, !val32, + 1, 1000, false, rtwdev, R_BE_REG_PL1_ISR); + if (ret) + rtw89_warn(rtwdev, "[ERR] PCIE SER clear poll fail\n"); + + val32 = rtw89_read32(rtwdev, R_BE_REG_PL1_MASK); + val32 |= B_BE_SER_PMU_IMR | B_BE_SER_L1SUB_IMR | B_BE_SER_PM_MASTER_IMR | + B_BE_SER_LTSSM_IMR | B_BE_SER_PM_CLK_MASK | B_BE_SER_PCLKREQ_ACK_MASK | + B_BE_SER_LTSSM_UNSTABLE_MASK; + rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32); + + rtw89_write32_mask(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_TIMER_UNIT_MASK, + PCIE_SER_TIMER_UNIT); + rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); + + if (hal->cid == RTL8922D_CID7090) + rtw89_write32_set(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_SER_DETECT_EN); } static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool enable) @@ -416,6 +494,7 @@ static int rtw89_pci_ops_mac_pre_deinit_be(struct rtw89_dev *rtwdev) int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en) { u32 ctrl0, cfg0, cfg1, dec_ctrl, idle_ltcy, act_ltcy, dis_ltcy; + u32 ltr_idle_lat_ctrl, ltr_act_lat_ctrl; ctrl0 = rtw89_read32(rtwdev, R_BE_LTR_CTRL_0); if (rtw89_pci_ltr_is_err_reg_val(ctrl0)) @@ -458,8 +537,16 @@ int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en) cfg0 = u32_replace_bits(cfg0, 3, B_BE_LTR_IDX_IDLE_MASK); dec_ctrl = u32_replace_bits(dec_ctrl, 0, B_BE_LTR_IDX_DISABLE_V1_MASK); - rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1, 0x90039003); - rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1, 0x880b880b); + if (rtwdev->chip->chip_id == RTL8922A) { + ltr_idle_lat_ctrl = 0x90039003; + ltr_act_lat_ctrl = 0x880b880b; + } else { + ltr_idle_lat_ctrl = 0x90019001; + ltr_act_lat_ctrl = 0x88018801; + } + + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1, ltr_idle_lat_ctrl); + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1, ltr_act_lat_ctrl); rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1, 0); rtw89_write32(rtwdev, R_BE_LTR_DECISION_CTRL_V1, dec_ctrl); rtw89_write32(rtwdev, R_BE_LTR_CFG_0, cfg0); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 66794ecbaaa9..efeb4507b1a9 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3831,6 +3831,7 @@ #define B_BE_EN_WLON BIT(16) #define B_BE_APDM_HPDN BIT(15) #define B_BE_PSUS_OFF_CAPC_EN BIT(14) +#define B_BE_USUS_OFFCAPC_EN BIT(13) #define B_BE_AFSM_PCIE_SUS_EN BIT(12) #define B_BE_AFSM_WLSUS_EN BIT(11) #define B_BE_APFM_SWLPS BIT(10) @@ -3899,6 +3900,8 @@ #define B_BE_SYM_PADPDN_WL_RFC0_1P3 BIT(5) #define R_BE_RSV_CTRL 0x001C +#define B_BE_R_SYM_PRST_CPHY_RST BIT(25) +#define B_BE_R_SYM_PRST_PDN_EN BIT(24) #define B_BE_HR_BE_DBG GENMASK(23, 12) #define B_BE_R_SYM_DIS_PCIE_FLR BIT(9) #define B_BE_R_EN_HRST_PWRON BIT(8) @@ -4038,6 +4041,7 @@ #define R_BE_SYS_SDIO_CTRL 0x0070 #define B_BE_MCM_FLASH_EN BIT(28) +#define B_BE_SER_DETECT_EN BIT(26) #define B_BE_PCIE_SEC_LOAD BIT(26) #define B_BE_PCIE_SER_RSTB BIT(25) #define B_BE_PCIE_SEC_LOAD_CLR BIT(24) @@ -4497,6 +4501,16 @@ #define B_BE_WL_XTAL_SI_DATA_MASK GENMASK(15, 8) #define B_BE_WL_XTAL_SI_ADDR_MASK GENMASK(7, 0) +#define R_BE_PCIE_SER_DBG 0x02FC +#define B_BE_PCIE_SER_DBG_MASK GENMASK(31, 10) +#define B_BE_PCIE_SER_PHY_PROTECT BIT(9) +#define B_BE_PCIE_SER_MAC_PROTECT BIT(8) +#define B_BE_PCIE_SER_FLUSH_RSTB BIT(4) +#define B_BE_PCIE_AXI_BRG_FLUSH_EN BIT(3) +#define B_BE_PCIE_SER_AUXCLK_RDY BIT(2) +#define B_BE_PCIE_SER_FRZ_REG_RST BIT(1) +#define B_BE_PCIE_SER_FRZ_CFG_SPC_RST BIT(0) + #define R_BE_IC_PWR_STATE 0x03F0 #define B_BE_WHOLE_SYS_PWR_STE_MASK GENMASK(25, 16) #define MAC_AX_SYS_ACT 0x220