* [BUG] QCA9377 (168c:0042): recurring PCIe AER RxErr/BadDLLP errors with ASPM enabled
From: Rakesh @ 2026-07-24 17:08 UTC (permalink / raw)
To: linux-pci, linux-wireless
Hello,
I would like to report what appears to be a reproducible PCIe
ASPM-related issue affecting the Qualcomm Atheros QCA9377 wireless
adapter.
Hardware:
Dell Latitude 3500
BIOS 1.37.0
Intel PCIe Root Port: 8086:9db1
Qualcomm Atheros QCA9377 (168c:0042), subsystem 1028:1810
Driver: ath10k_pci
Observed behavior:
With ASPM enabled, the system repeatedly reports correctable PCIe AER
errors, including RxErr and BadDLLP. The issue has been reproduced on
Ubuntu 20.04 (Linux 5.15.x) and a recent Ubuntu development kernel
(7.0.0-14).
Workaround:
Booting with:
pcie_aspm=off
eliminates the errors completely.
Additional observations:
ASPM L1 is enabled on the link.
L1.1/L1.2 substates are enabled on both the root port and endpoint.
The ath10k_pci driver temporarily disables ASPM during initialization
before restoring it.
I did not find an existing QCA9377-specific ASPM/AER quirk during my
investigation.
I have filed a Bugzilla report containing the full description, logs,
and supporting information:
https://bugzilla.kernel.org/show_bug.cgi?id=221784
If additional diagnostics or testing would be helpful, I would be
happy to provide them.
Thank you for your time.
Best regards,
Alasyam Rakesh
^ permalink raw reply
* Re: [PATCH v8 5/9] block: implement NVMEM provider
From: Loic Poulain @ 2026-07-24 16:19 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi, linux-mmc,
devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Bartosz Golaszewski
In-Reply-To: <amNkX6HV7c_8jRUa@infradead.org>
On Fri, Jul 24, 2026 at 3:11 PM Christoph Hellwig <hch@infradead.org> wrote:
>
> On Fri, Jul 24, 2026 at 11:10:58AM +0200, Loic Poulain wrote:
> > Right, I was planning to add partition support in a follow-up series.
> > But since this is really supposed to be a block-agnostic feature,
> > whether it's a disk or a partition, I'll include partition in v8.
>
> Please include the partitions, as including them or not matters for
> the interfaces. What is holding that support back now? fwnode
> magic?
Yes, there is a bit of fwnode magic involved in partitions of/core,
but adding it is fairly straightforward.
>
> > > Also once you register the whole devices as nvmem provider, we really
> > > should keep it from being used a block device, shouldn't we?
> >
> >
> > I'm not sure, the whole concept is block backed NVMEM, so we still
> > need to add that block as base layer, though we could discuss
> > suppressing uevent for it. Preventing block usage would make the
> > feature much more intrusive than other NVMEM providers like MTD, where
> > the underlying device stays accessible. And we may genuinely still
> > want to write the disk (e.g. for factory provisioning), updating the
> > very data the cells point to, etc. There's also the layering aspect,
> > if a disk (e.g. mmcblk0) has logical partitions on top (mmcblk0pX), we
> > still register/expose the whole disk mmcblk0 as a block device
> > regardless. So if a disk contains NVMEM cells, I think it should still
> > be exposed as a block device as well.
>
> So we now get two unsynchronized ways to access the same device?
> At least we need to prevent exclusive openers on the block device
> side. And document the side channel very well.
Yes, effectively, so the simpler is to open it exclusively per read
in reg_read with a holder (exclusive). This gives us proper exclusion
against other holders, but only transiently for the duration of the read.
It's the simpler solution if acceptable.
Another option would be to claim the device for the whole NVMEM
lifetime, but currently we can't bdev/open the block device from
nvmem_register(). That path runs early, while the disk/partition setup
already holds disk->open_mutex. So that would require a larger change.
Regards,
Loic
^ permalink raw reply
* [PATCH ath-next v2 2/2] wifi: ath11k: fix overreads in ath11k_wmi_process_csa_switch_count_event()
From: Jeff Johnson @ 2026-07-24 15:56 UTC (permalink / raw)
To: Jeff Johnson
Cc: linux-wireless, ath12k, linux-kernel, ath11k,
Rameshkumar Sundaram, Baochen Qiang, Jeff Johnson
In-Reply-To: <20260724-ath12k_wmi_process_csa_switch_count_event-cleanup-v2-0-02a45d7246c0@oss.qualcomm.com>
There is no policy entry for WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT, so
the parse infrastructure does not enforce a minimum length for the event
struct. Additionally, the num_vdevs field is taken directly from firmware
and used as a loop bound over the vdev_ids array without checking that it
fits within the TLV payload. Either condition can cause an out-of-bounds
read.
Add a TLV policy entry for WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT so
the parse infrastructure enforces a minimum length for the fixed-size event
struct. Add a helper ath11k_wmi_tlv_data_len() to recover the payload
length of a parsed TLV from the header preceding its data pointer. Use it
in ath11k_wmi_process_csa_switch_count_event() to bound num_vdevs before
the loop.
Compile tested only.
Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Assisted-by: Claude:claude-sonnet-4-6
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath11k/wmi.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index dca6e011cc40..feb0a0b29c81 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -159,6 +159,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
.min_len = sizeof(struct ath11k_wmi_p2p_noa_info) },
[WMI_TAG_P2P_NOA_EVENT] = {
.min_len = sizeof(struct wmi_p2p_noa_event) },
+ [WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT] = {
+ .min_len = sizeof(struct wmi_pdev_csa_switch_ev) },
};
#define PRIMAP(_hw_mode_) \
@@ -262,6 +264,13 @@ const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab,
return tb;
}
+static u32 ath11k_wmi_tlv_data_len(const void *data)
+{
+ const struct wmi_tlv *tlv = (const struct wmi_tlv *)data - 1;
+
+ return FIELD_GET(WMI_TLV_LEN, tlv->header);
+}
+
static int ath11k_wmi_cmd_send_nowait(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
u32 cmd_id)
{
@@ -8353,15 +8362,23 @@ ath11k_wmi_process_csa_switch_count_event(struct ath11k_base *ab,
const struct wmi_pdev_csa_switch_ev *ev,
const u32 *vdev_ids)
{
- int i;
+ u32 vdev_ids_len = ath11k_wmi_tlv_data_len(vdev_ids);
+ u32 num_vdevs = ev->num_vdevs;
struct ath11k_vif *arvif;
+ int i;
/* Finish CSA once the switch count becomes NULL */
if (ev->current_switch_count)
return;
+ if (num_vdevs > vdev_ids_len / sizeof(*vdev_ids)) {
+ ath11k_warn(ab, "csa switch count num_vdevs %u exceeds tlv array length %u\n",
+ num_vdevs, vdev_ids_len);
+ return;
+ }
+
rcu_read_lock();
- for (i = 0; i < ev->num_vdevs; i++) {
+ for (i = 0; i < num_vdevs; i++) {
arvif = ath11k_mac_get_arvif_by_vdev_id(ab, vdev_ids[i]);
if (!arvif) {
--
2.43.0
^ permalink raw reply related
* [PATCH ath-next v2 1/2] wifi: ath12k: fix overreads in ath12k_wmi_process_csa_switch_count_event()
From: Jeff Johnson @ 2026-07-24 15:56 UTC (permalink / raw)
To: Jeff Johnson
Cc: linux-wireless, ath12k, linux-kernel, ath11k,
Rameshkumar Sundaram, Baochen Qiang, Jeff Johnson
In-Reply-To: <20260724-ath12k_wmi_process_csa_switch_count_event-cleanup-v2-0-02a45d7246c0@oss.qualcomm.com>
There is no policy entry for WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT, so
the parse infrastructure does not enforce a minimum length for the event
struct. Additionally, the num_vdevs field is taken directly from firmware
and used as a loop bound over the vdev_ids array without checking that it
fits within the TLV payload. Either condition can cause an out-of-bounds
read.
Add a TLV policy entry for WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT so
the parse infrastructure enforces a minimum length for the fixed-size event
struct. Add a helper ath12k_wmi_tlv_data_len() to recover the payload
length of a parsed TLV from the header preceding its data pointer. Use it
in ath12k_wmi_process_csa_switch_count_event() to bound num_vdevs before
the loop.
Compile tested only.
Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
Assisted-by: Claude:claude-sonnet-4-6
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/wmi.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index ad739bffcf88..62a86f2069f3 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -207,6 +207,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
.min_len = sizeof(struct wmi_per_chain_rssi_stat_params) },
[WMI_TAG_OBSS_COLOR_COLLISION_EVT] = {
.min_len = sizeof(struct wmi_obss_color_collision_event) },
+ [WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT] = {
+ .min_len = sizeof(struct ath12k_wmi_pdev_csa_event) },
};
__le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len)
@@ -374,6 +376,13 @@ ath12k_wmi_tlv_parse(struct ath12k_base *ab, struct sk_buff *skb)
return tb;
}
+static u32 ath12k_wmi_tlv_data_len(const void *data)
+{
+ const struct wmi_tlv *tlv = (const struct wmi_tlv *)data - 1;
+
+ return le32_get_bits(tlv->header, WMI_TLV_LEN);
+}
+
static int ath12k_wmi_cmd_send_nowait(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb,
u32 cmd_id)
{
@@ -9057,12 +9066,19 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,
const u32 *vdev_ids)
{
u32 current_switch_count = le32_to_cpu(ev->current_switch_count);
+ u32 vdev_ids_len = ath12k_wmi_tlv_data_len(vdev_ids);
u32 num_vdevs = le32_to_cpu(ev->num_vdevs);
struct ieee80211_bss_conf *conf;
struct ath12k_link_vif *arvif;
struct ath12k_vif *ahvif;
int i;
+ if (num_vdevs > vdev_ids_len / sizeof(*vdev_ids)) {
+ ath12k_warn(ab, "csa switch count num_vdevs %u exceeds tlv array length %u\n",
+ num_vdevs, vdev_ids_len);
+ return;
+ }
+
rcu_read_lock();
for (i = 0; i < num_vdevs; i++) {
arvif = ath12k_mac_get_arvif_by_vdev_id(ab, vdev_ids[i]);
--
2.43.0
^ permalink raw reply related
* [PATCH ath-next v2 0/2] wifi: ath: Fix buffer overreads in CSA switch count event processing
From: Jeff Johnson @ 2026-07-24 15:56 UTC (permalink / raw)
To: Jeff Johnson
Cc: linux-wireless, ath12k, linux-kernel, ath11k,
Rameshkumar Sundaram, Baochen Qiang, Jeff Johnson
Both ath11k and ath12k fail to properly sanitize the CSA switch count
event.
---
Changes in v2:
- Add Fixes: tags to both patches
- Carry forward the Reviewed-by: tags
- Link to v1: https://patch.msgid.link/20260723-ath12k_wmi_process_csa_switch_count_event-cleanup-v1-0-c01ef10bc6a3@oss.qualcomm.com
---
Jeff Johnson (2):
wifi: ath12k: fix overreads in ath12k_wmi_process_csa_switch_count_event()
wifi: ath11k: fix overreads in ath11k_wmi_process_csa_switch_count_event()
drivers/net/wireless/ath/ath11k/wmi.c | 21 +++++++++++++++++++--
drivers/net/wireless/ath/ath12k/wmi.c | 16 ++++++++++++++++
2 files changed, 35 insertions(+), 2 deletions(-)
---
base-commit: 0ceb105245b5e57f803bdc0e79dc077fc06ff384
change-id: 20260716-ath12k_wmi_process_csa_switch_count_event-cleanup-7fb191b7d7d3
^ permalink raw reply
* Re: [PATCH v8 0/9] Support for block device NVMEM providers
From: Ulf Hansson @ 2026-07-24 15:35 UTC (permalink / raw)
To: Srinivas Kandagatla
Cc: Loic Poulain, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Konrad Dybcio, Jens Axboe,
Johannes Berg, Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Heiner Kallweit, Russell King,
Saravana Kannan, Christian Marangi, linux-mmc, devicetree,
linux-kernel, linux-arm-msm, linux-block, linux-wireless, ath10k,
linux-bluetooth, netdev, daniel, Bartosz Golaszewski,
Krzysztof Kozlowski, Piotr Kwapulinski, Konrad Dybcio
In-Reply-To: <3d954cdd-6dde-4be6-84c9-2f2f7d008f5b@kernel.org>
On Wed, Jul 22, 2026 at 3:56 PM Srinivas Kandagatla <srini@kernel.org> wrote:
>
>
>
> On 7/3/26 2:45 PM, Loic Poulain wrote:
> > On embedded devices, it is common for factory provisioning to store
> > device-specific information, such as Ethernet or WiFi MAC addresses,
> > in a dedicated area of an eMMC partition. This avoids the need for
> > and additional EEPROM/OTP and leverages the persistence of eMMC.
> >
> > One example is the Arduino UNO-Q, where the WiFi MAC address and the
> > Bluetooth Device address are stored in the eMMC Boot1 partition.
> >
> > Until now, accessing this information required a custom bootloader
> > to read the data and inject it into the Device Tree before handing
> > control over to the kernel. This approach is fragile and leads to
> > device-specific workarounds.
> >
> > Rather than adding a new NVMEM provider specifically to the eMMC
> > subsystem, the new support operates at the block layer, allowing any
> > block device to behave like other non-volatile memories such as EEPROM
> > or OTP.
> >
> > This series builds on earlier work by Daniel Golle that enables block
> > devices to act as NVMEM providers:
> > https://lore.kernel.org/all/6061aa4201030b9bb2f8d03ef32a564fdb786ed1.1709667858.git.daniel@makrotopia.org/
> >
> > It also introduces an NVMEM layout description for the Arduino UNO-Q,
> > allowing device-specific data stored in the eMMC Boot1 partition to
> > be accessed in a standard way.
> >
> > WiFi and Ethernet already support retrieving MAC addresses from NVMEM.
> > Bluetooth requires similar support, which is also addressed.
> >
> > Note that this is currently limited to MMC-backed block devices, as
> > only the MMC core associates a firmware node with the block device
> > (add_disk_fwnode). This can be easily extended in the future to
> > support additional block drivers.
> >
> > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
>
> What is the merge strategy here, Am happy to take it via nvmem tree if
> all the non nvmem patches are acked or reviewed-by.
I am planning to pick up patch1 (dt), but waiting until all the
complete series is ready to go.
[...]
Kind regards
Uffe
^ permalink raw reply
* hang during shutdown in next-20260722+ with MT7925
From: Bert Karwatzki @ 2026-07-24 15:14 UTC (permalink / raw)
To: Nicolas Cavallari
Cc: Bert Karwatzki, linux-kernel, linux-next, linux-wireless,
Felix Fietkau, ryder.lee, lorenzo, legale.legale, sean.wang,
shayne.chen
In-Reply-To: <20260708144615.24092-1-nicolas.cavallari@green-communications.fr>
Since next-20260722 my debian sid system hangs when shutting down or
rebooting (No error message when monitoring the shutdown process via
netconsole). I bisected the error to commit
13b7e6a96a00 ("wifi: mt76: Disable napi when removing device")
and reverting this commit in next-20260723 makes shutting down or
rebooting work normally again.
Wifi device:
09:00.0 Network controller [0280]: MEDIATEK Corp. MT7925 802.11be 160MHz 2x2 PCIe Wireless Network Adapter [Filogic 360] [14c3:7925]
Cpu:
$ cat /proc/cpuinfo
processor : 0
vendor_id : AuthenticAMD
cpu family : 26
model : 68
model name : AMD Ryzen 9 9950X 16-Core Processor
stepping : 0
microcode : 0xb404035
cpu MHz : 624.194
cache size : 1024 KB
physical id : 0
siblings : 32
core id : 0
cpu cores : 16
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 16
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good amd_lbr_v2 nopl xtopology nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpuid_fault cpb cat_l3 cdp_l3 hw_pstate ssbd mba perfmon_v2 ibrs ibpb stibp ibrs_enhanced vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local user_shstk avx_vnni avx512_bf16 clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif x2avic v_spec_ctrl vnmi avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid bus_lock_detect movdiri movdir64b overflow_recov succor smca fsrm avx512_vp2intersect flush_l1d amd_lbr_pmc_freeze
bugs : sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass srso spectre_v2_user vmscape
bogomips : 8599.52
TLB size : 192 4K pages
clflush size : 64
cache_alignment : 64
address sizes : 48 bits physical, 48 bits virtual
power management: ts ttp tm hwpstate cpb eff_freq_ro [13] [14]
Other pci hardware:
$ lspci
00:00.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Root Complex
00:00.2 IOMMU: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge IOMMU
00:01.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge
00:01.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge GPP Bridge
00:01.2 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge GPP Bridge
00:02.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge
00:02.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge GPP Bridge
00:03.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge
00:04.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge
00:08.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge
00:08.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Internal GPP Bridge to Bus [C:A]
00:08.3 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Internal GPP Bridge to Bus [C:A]
00:14.0 SMBus: Advanced Micro Devices, Inc. [AMD] FCH SMBus Controller (rev 71)
00:14.3 ISA bridge: Advanced Micro Devices, Inc. [AMD] FCH LPC Bridge (rev 51)
00:18.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 0
00:18.1 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 1
00:18.2 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 2
00:18.3 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 3
00:18.4 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 4
00:18.5 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 5
00:18.6 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 6
00:18.7 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 7
01:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Upstream Port of PCI Express Switch (rev 25)
02:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Downstream Port of PCI Express Switch (rev 25)
03:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Navi 44 [Radeon RX 9060 XT] (rev c0)
03:00.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Navi 48 HDMI/DP Audio Controller
04:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD 9100 PRO [PM9E1]
05:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Upstream Port (rev 01)
06:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01)
06:06.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01)
06:07.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01)
06:08.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01)
06:0c.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01)
06:0d.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01)
08:00.0 Ethernet controller: Intel Corporation Ethernet Controller I226-V (rev 06)
09:00.0 Network controller: MEDIATEK Corp. MT7925 802.11be 160MHz 2x2 PCIe Wireless Network Adapter [Filogic 360]
0b:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] 800 Series Chipset USB 3.x XHCI Controller (rev 01)
0c:00.0 SATA controller: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset SATA Controller (rev 01)
0d:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge PCIe Dummy Function (rev c1)
0d:00.2 Encryption controller: Advanced Micro Devices, Inc. [AMD] Family 19h PSP/CCP
0d:00.3 USB controller: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge USB 3.1 xHCI
0d:00.4 USB controller: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge USB 3.1 xHCI
0e:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge USB 2.0 xHCI
Bert Karwatzki
^ permalink raw reply
* [PATCH rtw-next 3/3] wifi: rtw89: change scan offload format to V3 for WiFi 7 IC
From: Ping-Ke Shih @ 2026-07-24 14:22 UTC (permalink / raw)
To: linux-wireless; +Cc: dian_syuan0116, phhuang
In-Reply-To: <20260724142246.3195274-1-pkshih@realtek.com>
From: Po-Hao Huang <phhuang@realtek.com>
Adapt H2C formt to fit firmware version after 0.35.113.2, which
only supports active scanning with a provided SSID list.
Keep original style also to support older firmwares.
Signed-off-by: Po-Hao Huang <phhuang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.h | 4 +
drivers/net/wireless/realtek/rtw89/fw.c | 118 ++++++++++++++++++++--
drivers/net/wireless/realtek/rtw89/fw.h | 1 +
3 files changed, 116 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 7573f1965c98..9e6e0b2b47da 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -5700,6 +5700,7 @@ enum rtw89_fw_feature {
RTW89_FW_FEATURE_MACID_PAUSE_SLEEP,
RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V0,
RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V1,
+ RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V2,
RTW89_FW_FEATURE_WOW_REASON_V1,
RTW89_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY,
RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0,
@@ -6894,6 +6895,9 @@ struct rtw89_hw_scan_info {
struct list_head chan_list;
struct rtw89_chan op_chan;
struct rtw89_hw_scan_extra_op extra_op;
+ u8 wildcard_pkt_id[NUM_NL80211_BANDS];
+ u16 ssid_total_len;
+ int n_ssids;
bool connected;
bool abort;
u16 delay; /* in unit of ms */
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 7d68ee870ed5..52ea1282f26e 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -934,6 +934,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 100, 0, SER_POST_RECOVER_DMAC),
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 108, 0, SIM_SER_L0L1_BY_HALT_H2C),
__CFG_FW_FEAT(RTL8922A, lt, 0, 35, 109, 1, SCAN_OFFLOAD_BE_V1),
+ __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 113, 2, SCAN_OFFLOAD_BE_V2),
__CFG_FW_FEAT(RTL8922D, ge, 0, 0, 0, 0, MACID_PAUSE_SLEEP),
__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 75, 2, SCAN_OFFLOAD),
__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 75, 2, BEACON_FILTER),
@@ -949,6 +950,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 108, 0, SIM_SER_L0L1_BY_HALT_H2C),
__CFG_FW_FEAT(RTL8922D, lt, 0, 35, 109, 1, SCAN_OFFLOAD_BE_V1),
__CFG_FW_FEAT(RTL8922D, lt, 0, 35, 113, 0, RFK_TXIQK_V0),
+ __CFG_FW_FEAT(RTL8922D, lt, 0, 35, 113, 2, SCAN_OFFLOAD_BE_V2),
};
static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
@@ -7365,6 +7367,7 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
struct rtw89_h2c_chinfo_elem_be *elem;
struct rtw89_mac_chinfo_be *ch_info;
struct rtw89_h2c_chinfo_be *h2c;
+ bool wildcard_by_drv;
struct sk_buff *skb;
unsigned int cond;
u8 ver = U8_MAX;
@@ -7383,6 +7386,10 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
if (RTW89_CHK_FW_FEATURE(CH_INFO_BE_V0, &rtwdev->fw))
ver = 0;
+ wildcard_by_drv = !(RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw) ||
+ RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V1, &rtwdev->fw) ||
+ RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V2, &rtwdev->fw));
+
skb_put(skb, sizeof(*h2c));
h2c = (struct rtw89_h2c_chinfo_be *)skb->data;
@@ -7392,6 +7399,8 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK);
list_for_each_entry(ch_info, chan_list, list) {
+ bool with_probe_id = ch_info->probe_id != RTW89_SCANOFLD_PKT_NONE;
+
elem = (struct rtw89_h2c_chinfo_elem_be *)skb_put(skb, sizeof(*elem));
elem->w0 = le32_encode_bits(ch_info->dwell_time, RTW89_H2C_CHINFO_BE_W0_DWELL) |
@@ -7409,7 +7418,7 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
RTW89_H2C_CHINFO_BE_W1_RANDOM) |
le32_encode_bits(ch_info->notify_action,
RTW89_H2C_CHINFO_BE_W1_NOTIFY) |
- le32_encode_bits(ch_info->probe_id != 0xff ? 1 : 0,
+ le32_encode_bits(wildcard_by_drv || with_probe_id,
RTW89_H2C_CHINFO_BE_W1_PROBE) |
le32_encode_bits(ch_info->leave_crit,
RTW89_H2C_CHINFO_BE_W1_EARLY_LEAVE_CRIT) |
@@ -7574,6 +7583,27 @@ static void rtw89_scan_get_6g_disabled_chan(struct rtw89_dev *rtwdev,
}
}
+static void rtw89_hw_scan_calc_req_ssid(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
+ struct cfg80211_scan_request *req = rtwvif->scan_req;
+ int i, num = 0;
+ u16 sum = 0;
+
+ for (i = 0; i < req->n_ssids; i++) {
+ if (req->ssids[i].ssid_len == 0)
+ continue;
+
+ num++;
+ sum += req->ssids[i].ssid_len + 1;
+ }
+
+ scan_info->n_ssids = num;
+ scan_info->ssid_total_len = sum;
+}
+
int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *option,
struct rtw89_vif_link *rtwvif_link,
@@ -7594,12 +7624,13 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
struct sk_buff *skb;
u8 macc_role_size = sizeof(*macc_role) * option->num_macc_role;
u8 opch_size = sizeof(*opch) * option->num_opch;
+ u8 *probe_id = scan_info->wildcard_pkt_id;
enum rtw89_scan_be_opmode opmode;
- u8 probe_id[NUM_NL80211_BANDS];
u8 scan_offload_ver = U8_MAX;
u8 cfg_len = sizeof(*h2c);
unsigned int cond;
u8 ver = U8_MAX;
+ u8 n_ssids = 0;
u8 policy_val;
void *ptr;
u8 txnull;
@@ -7621,9 +7652,14 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
} else if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V1, &rtwdev->fw)) {
cfg_len = offsetofend(typeof(*h2c), w9);
scan_offload_ver = 1;
+ } else if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V2, &rtwdev->fw)) {
+ scan_offload_ver = 2;
}
len = cfg_len + macc_role_size + opch_size;
+ if (scan_offload_ver > 2)
+ len += scan_info->ssid_total_len;
+
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c scan offload\n");
@@ -7634,8 +7670,6 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
h2c = (struct rtw89_h2c_scanofld_be *)skb->data;
ptr = skb->data;
- memset(probe_id, RTW89_SCANOFLD_PKT_NONE, sizeof(probe_id));
-
if (RTW89_CHK_FW_FEATURE(CH_INFO_BE_V0, &rtwdev->fw))
ver = 0;
@@ -7667,7 +7701,10 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
le32_encode_bits(option->norm_cy, RTW89_H2C_SCANOFLD_BE_W2_NORM_CY) |
le32_encode_bits(option->opch_end, RTW89_H2C_SCANOFLD_BE_W2_OPCH_END);
- h2c->w3 = le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W3_NUM_SSID) |
+ if (scan_offload_ver > 2)
+ n_ssids = scan_info->n_ssids;
+
+ h2c->w3 = le32_encode_bits(n_ssids, RTW89_H2C_SCANOFLD_BE_W3_NUM_SSID) |
le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W3_NUM_SHORT_SSID) |
le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W3_NUM_BSSID) |
le32_encode_bits(probe_id[NL80211_BAND_2GHZ], RTW89_H2C_SCANOFLD_BE_W3_PROBEID);
@@ -7794,6 +7831,20 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
ptr += sizeof(*opch);
}
+ if (scan_offload_ver <= 2)
+ goto set_hdr;
+
+ for (i = 0; i < req->n_ssids; i++) {
+ if (req->ssids[i].ssid_len == 0)
+ continue;
+
+ memcpy(ptr, &req->ssids[i].ssid_len, 1);
+ ptr++;
+ memcpy(ptr, req->ssids[i].ssid, req->ssids[i].ssid_len);
+ ptr += req->ssids[i].ssid_len;
+ }
+
+set_hdr:
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
H2C_FUNC_SCANOFLD_BE, 1, 1,
@@ -9123,14 +9174,19 @@ void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev)
static void rtw89_hw_scan_release_pkt_list(struct rtw89_dev *rtwdev)
{
+ struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
struct rtw89_pktofld_info *info, *tmp;
- u8 idx;
+ u8 idx, wildcard_pkt_id;
for (idx = NL80211_BAND_2GHZ; idx < NUM_NL80211_BANDS; idx++) {
if (!(rtwdev->chip->support_bands & BIT(idx)))
continue;
+ wildcard_pkt_id = scan_info->wildcard_pkt_id[idx];
+ if (wildcard_pkt_id != RTW89_SCANOFLD_PKT_NONE)
+ rtw89_fw_h2c_del_pkt_offload(rtwdev, wildcard_pkt_id);
+
list_for_each_entry_safe(info, tmp, &pkt_list[idx], list) {
if (test_bit(info->id, rtwdev->pkt_offload))
rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
@@ -9225,16 +9281,57 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
return ret;
}
+static int rtw89_hw_scan_append_wildcard_probe_req(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ const u8 *mac_addr)
+{
+ struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
+ struct cfg80211_scan_request *req = rtwvif->scan_req;
+ struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
+ enum nl80211_band band;
+ struct sk_buff *skb;
+ int ret;
+ u8 id;
+
+ for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
+ if (!(rtwdev->chip->support_bands & BIT(band)))
+ continue;
+
+ skb = ieee80211_probereq_get(rtwdev->hw, mac_addr,
+ NULL, 0, req->ie_len);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put_data(skb, ies->ies[band], ies->len[band]);
+ skb_put_data(skb, ies->common_ies, ies->common_ie_len);
+
+ ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &id, skb);
+ kfree_skb(skb);
+
+ if (ret)
+ return ret;
+
+ scan_info->wildcard_pkt_id[band] = id;
+ }
+
+ return 0;
+}
+
static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
const u8 *mac_addr)
{
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
- struct sk_buff *skb;
u8 num = req->n_ssids, i;
+ struct sk_buff *skb;
int ret;
+ ret = rtw89_hw_scan_append_wildcard_probe_req(rtwdev, rtwvif_link, mac_addr);
+ if (ret)
+ return ret;
+
for (i = 0; i < num; i++) {
skb = ieee80211_probereq_get(rtwdev->hw, mac_addr,
req->ssids[i].ssid,
@@ -9542,6 +9639,9 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type,
if (probe_count >= RTW89_SCANOFLD_MAX_SSID)
break;
}
+
+ if (scan_info->n_ssids)
+ ch_info->fw_probe0_ssids = GENMASK(scan_info->n_ssids - 1, 0);
}
if (ch_info->ch_band == RTW89_BAND_6G) {
@@ -10144,6 +10244,10 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
rtwdev->scan_info.delay = 0;
rtwvif->scan_ies = &scan_req->ies;
rtwvif->scan_req = req;
+ rtw89_hw_scan_calc_req_ssid(rtwdev, rtwvif_link);
+
+ memset(rtwdev->scan_info.wildcard_pkt_id, RTW89_SCANOFLD_PKT_NONE,
+ sizeof(rtwdev->scan_info.wildcard_pkt_id));
if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
get_random_mask_addr(mac_addr, req->mac_addr,
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index e86014ca249a..f70b096a542d 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -3099,6 +3099,7 @@ struct rtw89_h2c_scanofld_be {
__le32 w11; /* Added after SCAN_OFFLOAD_BE_V2 */
/* struct rtw89_h2c_scanofld_be_macc_role (flexible number) */
/* struct rtw89_h2c_scanofld_be_opch (flexible number) */
+ /* probe SSID list (flexible number); Added after SCAN_OFFLOAD_BE_V3 */
} __packed;
#define RTW89_H2C_SCANOFLD_BE_W0_OP GENMASK(1, 0)
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 2/3] wifi: rtw89: fix scan offload version check logic
From: Ping-Ke Shih @ 2026-07-24 14:22 UTC (permalink / raw)
To: linux-wireless; +Cc: dian_syuan0116, phhuang
In-Reply-To: <20260724142246.3195274-1-pkshih@realtek.com>
From: Po-Hao Huang <phhuang@realtek.com>
The version check with less than should check for smallest upper-bound
first, or some branch will be unreachable.
Signed-off-by: Po-Hao Huang <phhuang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/fw.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 3b8c144e0e98..7d68ee870ed5 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -7615,12 +7615,12 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
rtw89_scan_get_6g_disabled_chan(rtwdev, option);
- if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V1, &rtwdev->fw)) {
- cfg_len = offsetofend(typeof(*h2c), w9);
- scan_offload_ver = 1;
- } else if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw)) {
+ if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw)) {
cfg_len = offsetofend(typeof(*h2c), w8);
scan_offload_ver = 0;
+ } else if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V1, &rtwdev->fw)) {
+ cfg_len = offsetofend(typeof(*h2c), w9);
+ scan_offload_ver = 1;
}
len = cfg_len + macc_role_size + opch_size;
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 1/3] wifi: rtw89: refine RX filter configuration for WiFi 7 generation
From: Ping-Ke Shih @ 2026-07-24 14:22 UTC (permalink / raw)
To: linux-wireless; +Cc: dian_syuan0116, phhuang
In-Reply-To: <20260724142246.3195274-1-pkshih@realtek.com>
From: Dian-Syuan Yang <dian_syuan0116@realtek.com>
When an AP interface is registered and starts AP, mac80211 calls the
configure_filter() to clear B_AX_A_UC_CAM_MATCH and B_AX_A_BC_CAM_MATCH
so that frames from un-associated stations can be received. However, for
a dedicated AP interface created via iw command, configure_filter() is
only triggered on the initial AP startup. Since the interface remains up
even after hostapd stops, and it isn't triggered again on later restarts.
Additionally, each AP start causes IPS leave, reverting the RX filter to
its default value.
For WiFi 7 chips, the default value is hardcoded in rx_fltr_init_be(),
so the reverted value does not match hal.rx_fltr. Therefore, refine
the behavior of WiFi 7 chips to align with the WiFi 6 implementation.
Signed-off-by: Dian-Syuan Yang <dian_syuan0116@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.c | 3 ++-
drivers/net/wireless/realtek/rtw89/mac.c | 1 +
drivers/net/wireless/realtek/rtw89/mac.h | 1 +
drivers/net/wireless/realtek/rtw89/mac_be.c | 7 ++-----
drivers/net/wireless/realtek/rtw89/reg.h | 6 +++++-
5 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 77a0e2582dbe..097e9b0312a1 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -6960,6 +6960,7 @@ void rtw89_sta_unset_link(struct rtw89_sta *rtwsta, unsigned int link_id)
int rtw89_core_init(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_btc *btc = &rtwdev->btc;
u8 band;
@@ -7016,7 +7017,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
rtw89_core_ppdu_sts_init(rtwdev);
rtw89_traffic_stats_init(rtwdev, &rtwdev->stats);
- rtwdev->hal.rx_fltr = DEFAULT_AX_RX_FLTR;
+ rtwdev->hal.rx_fltr = mac->default_rx_fltr;
rtwdev->dbcc_en = false;
rtwdev->mlo_dbcc_mode = MLO_DBCC_NOT_SUPPORT;
rtwdev->mac.qta_mode = RTW89_QTA_SCC;
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index db9fca828829..ca08fe520eaa 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -7458,6 +7458,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
.mem_base_addrs = rtw89_mac_mem_base_addrs_ax,
.mem_page_size = MAC_MEM_DUMP_PAGE_SIZE_AX,
.rx_fltr = R_AX_RX_FLTR_OPT,
+ .default_rx_fltr = DEFAULT_AX_RX_FLTR,
.port_base = &rtw89_port_base_ax,
.agg_len_ht = R_AX_AGG_LEN_HT_0,
.ps_status = R_AX_PPWRBIT_SETTING,
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index 493d2b9626a6..8419bcd3956a 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -1063,6 +1063,7 @@ struct rtw89_mac_gen_def {
const u32 *mem_base_addrs;
u32 mem_page_size;
u32 rx_fltr;
+ u32 default_rx_fltr;
const struct rtw89_port_reg *port_base;
u32 agg_len_ht;
u32 ps_status;
diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c
index 8de0fe5a3b1d..413c214d968a 100644
--- a/drivers/net/wireless/realtek/rtw89/mac_be.c
+++ b/drivers/net/wireless/realtek/rtw89/mac_be.c
@@ -1332,11 +1332,7 @@ static int rx_fltr_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
rtw89_mac_typ_fltr_opt_be(rtwdev, RTW89_DATA, RTW89_FWD_TO_HOST, mac_idx);
reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_FLTR_OPT, mac_idx);
- val = B_BE_A_BC_CAM_MATCH | B_BE_A_UC_CAM_MATCH | B_BE_A_MC |
- B_BE_A_BC | B_BE_A_A1_MATCH |
- u32_encode_bits(15, B_BE_UID_FILTER_MASK);
- rtw89_write32(rtwdev, reg, val);
- u32p_replace_bits(&rtwdev->hal.rx_fltr, 15, B_BE_UID_FILTER_MASK);
+ rtw89_write32(rtwdev, reg, rtwdev->hal.rx_fltr);
reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PLCP_HDR_FLTR, mac_idx);
val = B_BE_HE_SIGB_CRC_CHK | B_BE_VHT_MU_SIGB_CRC_CHK |
@@ -3280,6 +3276,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
.mem_base_addrs = rtw89_mac_mem_base_addrs_be,
.mem_page_size = MAC_MEM_DUMP_PAGE_SIZE_BE,
.rx_fltr = R_BE_RX_FLTR_OPT,
+ .default_rx_fltr = DEFAULT_BE_RX_FLTR,
.port_base = &rtw89_port_base_be,
.agg_len_ht = R_BE_AGG_LEN_HT_0,
.ps_status = R_BE_WMTX_POWER_BE_BIT_CTL,
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 756b94dcd475..abeeb61007dc 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -3348,7 +3348,7 @@
#define DEFAULT_AX_RX_FLTR (B_AX_A_A1_MATCH | B_AX_A_BC | B_AX_A_MC | \
B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH | \
B_AX_A_PWR_MGNT | B_AX_A_FTM_REQ | \
- u32_encode_bits(3, B_AX_UID_FILTER_MASK) | \
+ FIELD_PREP_CONST(B_AX_UID_FILTER_MASK, 3) | \
B_AX_A_BCN_CHK_EN)
#define B_AX_RX_FLTR_CFG_MASK ((u32)~B_AX_RX_MPDU_MAX_LEN_MASK)
@@ -8209,6 +8209,10 @@
#define B_BE_A_BC BIT(2)
#define B_BE_A_A1_MATCH BIT(1)
#define B_BE_SNIFFER_MODE BIT(0)
+#define DEFAULT_BE_RX_FLTR (B_BE_A_BC_CAM_MATCH | B_BE_A_UC_CAM_MATCH | \
+ B_BE_A_MC | B_BE_A_BC | B_BE_A_A1_MATCH | \
+ FIELD_PREP_CONST(B_BE_UID_FILTER_MASK, 15) | \
+ B_BE_A_FTM_REQ | B_BE_A_BCN_CHK_EN)
#define R_BE_CTRL_FLTR 0x11424
#define R_BE_CTRL_FLTR_C1 0x15424
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 0/3] wifi: rtw89: support hw_scan v3 format for WiFI 7 chips
From: Ping-Ke Shih @ 2026-07-24 14:22 UTC (permalink / raw)
To: linux-wireless; +Cc: dian_syuan0116, phhuang
Due to firmware change the hw_scan format, update the format accordingly
to support current new firmware. (By patch 2/3 and 3/3)
The patch 1/3 is to store RX filter settings by a variable, so hardware
leaves from idle can restore the setting from the variable. Otherwise,
the RX filter is unexpected, and AP mode can't receive certain types of
frames.
Dian-Syuan Yang (1):
wifi: rtw89: refine RX filter configuration for WiFi 7 generation
Po-Hao Huang (2):
wifi: rtw89: fix scan offload version check logic
wifi: rtw89: change scan offload format to V3 for WiFi 7 IC
drivers/net/wireless/realtek/rtw89/core.c | 3 +-
drivers/net/wireless/realtek/rtw89/core.h | 4 +
drivers/net/wireless/realtek/rtw89/fw.c | 126 ++++++++++++++++++--
drivers/net/wireless/realtek/rtw89/fw.h | 1 +
drivers/net/wireless/realtek/rtw89/mac.c | 1 +
drivers/net/wireless/realtek/rtw89/mac.h | 1 +
drivers/net/wireless/realtek/rtw89/mac_be.c | 7 +-
drivers/net/wireless/realtek/rtw89/reg.h | 6 +-
8 files changed, 131 insertions(+), 18 deletions(-)
base-commit: b0034a2e415603daa1cf00363b407cc145bbcd31
--
2.25.1
^ permalink raw reply
* [PATCH rtw-next 14/14] wifi: rtw89: coex: Handle Bluetooth LE-Audio related coexistence feature
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
Implement event handler of BTF_EVNT_BT_LEAUDIO_INFO C2H command, and
related coexistence mechanism for Bluetooth LE-Audio feature.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 199 ++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/core.h | 35 +++-
2 files changed, 233 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 6b3e199398cf..0e42c720819a 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -951,6 +951,7 @@ enum btc_reason_and_action {
BTC_RSN_ACT1_WORK,
BTC_RSN_BT_DEVINFO_WORK,
BTC_RSN_RFK_CHK_WORK,
+ BTC_RSN_UPDATE_BT_LEAUDINFO,
BTC_RSN_NUM,
BTC_ACT_NONE = 100,
BTC_ACT_WL_ONLY,
@@ -975,6 +976,8 @@ enum btc_reason_and_action {
BTC_ACT_BT_A2DP_PAN,
BTC_ACT_BT_PAN_HID,
BTC_ACT_BT_A2DP_PAN_HID,
+ BTC_ACT_BT_BIS,
+ BTC_ACT_BT_CIS,
BTC_ACT_WL_25G_MCC,
BTC_ACT_WL_2G_MCC,
BTC_ACT_WL_2G_SCC,
@@ -6076,6 +6079,43 @@ static void _action_bt_pan_hid(struct rtw89_dev *rtwdev)
}
}
+static void _action_bt_bis(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u16 policy_type;
+
+ if (dm->bis_tdma)
+ policy_type = BTC_CXP_OFFE_2GBWISOB;
+ else
+ policy_type = BTC_CXP_OFF_EQ0;
+
+ _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_PTA);
+ _set_policy(rtwdev, policy_type, BTC_ACT_BT_BIS);
+}
+
+static void _action_bt_cis(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt0.link_info;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u16 policy_type;
+
+ if (bt_linfo->a2dp_desc.active) {
+ dm->slot_dur[CXST_W1] = 80;
+ dm->slot_dur[CXST_B1] = 20;
+ policy_type = BTC_CXP_PFIX_TDW1B1;
+ } else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
+ policy_type = BTC_CXP_OFF_BWB0;
+ } else {
+ policy_type = BTC_CXP_OFF_BWB1;
+ }
+
+ _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_PTA);
+ _set_policy(rtwdev, policy_type, BTC_ACT_BT_CIS);
+}
+
static void _action_bt_a2dp_pan_hid(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -6692,6 +6732,7 @@ static void _action_by_bt(struct rtw89_dev *rtwdev)
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
+ struct rtw89_btc_bt_leaudio_desc leaudio = bt_linfo->leaudio_desc;
struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
@@ -6715,6 +6756,12 @@ static void _action_by_bt(struct rtw89_dev *rtwdev)
if (bt_linfo->pan_desc.exist)
profile_map |= BTC_BT_PAN;
+ if (leaudio.bis_exist)
+ profile_map |= BTC_BT_BIS;
+
+ if (leaudio.cis_exist)
+ profile_map |= BTC_BT_CIS;
+
switch (profile_map) {
case BTC_BT_NOPROFILE:
if (pan.active)
@@ -6740,6 +6787,13 @@ static void _action_by_bt(struct rtw89_dev *rtwdev)
case BTC_BT_PAN:
_action_bt_pan(rtwdev);
break;
+ case BTC_BT_BIS:
+ _action_bt_bis(rtwdev);
+ break;
+ case BTC_BT_CIS:
+ case BTC_BT_CIS | BTC_BT_HID:
+ _action_bt_cis(rtwdev);
+ break;
case BTC_BT_A2DP | BTC_BT_HFP:
case BTC_BT_A2DP | BTC_BT_HID:
case BTC_BT_A2DP | BTC_BT_HFP | BTC_BT_HID:
@@ -7909,6 +7963,140 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid)
}
}
+static void _update_bt_link_cnt(struct rtw89_dev *rtwdev,
+ struct rtw89_btc_bt_info *bt, bool b56g)
+{
+ struct rtw89_btc_bt_link_info *b = b56g ? &bt->link_info_56g :
+ &bt->link_info;
+ struct rtw89_btc_bt_leaudio_desc *leaudio = &b->leaudio_desc;
+ struct rtw89_btc_bt_a2dp_desc *a2dp = &b->a2dp_desc;
+ struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
+ struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
+ struct rtw89_btc_bt_pan_desc *pan = &b->pan_desc;
+
+ b->link_cnt.last = b->link_cnt.now;
+ b->link_cnt.now = 0;
+ b->link_cnt.chg = 0;
+
+ b->link_cnt.now += hfp->exist;
+ b->link_cnt.now += hid->exist;
+ b->link_cnt.now += a2dp->exist;
+ b->link_cnt.now += pan->exist;
+ b->link_cnt.now += leaudio->bis_exist;
+ b->link_cnt.now += leaudio->cis_exist;
+}
+
+static void _update_bt_leaudio_info(struct rtw89_dev *rtwdev, u8 bid,
+ void *buf, u32 len)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_bt_info *bt = (bid == BTC_BT_1ST) ? &cx->bt0 : &cx->bt1;
+ struct rtw89_btc_bt_link_info *b = &bt->link_info;
+ struct rtw89_btc_bt_leaudio_info *src = buf;
+ struct rtw89_btc_bt_leaudio_desc *leaudio;
+ bool bt_56g = false, cis_exist, bis_exist;
+ u8 bis_cnt, cis_cnt;
+
+ if ((src->len & BIT(7)) && bt->band_56G_support) {
+ b = &bt->link_info_56g;
+ bt_56g = true;
+ }
+
+ leaudio = &b->leaudio_desc;
+
+ if (!memcmp(b->leaudio_raw_info, src, BTC_BTINFO_MAX)) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s return by leaudio-info duplicate!\n",
+ __func__);
+ bt->bcnt[BTC_BCNT_LEAUDIO_INFOSAME]++;
+ return;
+ }
+
+ memcpy(b->leaudio_raw_info, src, BTC_BTINFO_MAX);
+
+ bis_exist = u8_get_bits(src->bis_cis, RTW89_BTC_LEAU_INFO_L2_BIS_EX);
+ cis_exist = u8_get_bits(src->bis_cis, RTW89_BTC_LEAU_INFO_L2_CIS_EX);
+ bis_cnt = u8_get_bits(src->bis_cis, RTW89_BTC_LEAU_INFO_L2_BIS_CNT);
+ cis_cnt = u8_get_bits(src->bis_cis, RTW89_BTC_LEAU_INFO_L2_CIS_CNT);
+
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s: bis_exist:%d bis_cnt:%d cis_exist:%d cis_cnt:%d rssi:%d\n",
+ __func__, bis_exist, bis_cnt, cis_exist, cis_cnt, src->rssi);
+
+ if (!bis_exist && !cis_exist)
+ memset(leaudio, 0, sizeof(*leaudio));
+
+ leaudio->bis_cnt = bis_cnt;
+ leaudio->bis_exist = bis_exist;
+ leaudio->cis_cnt = cis_cnt;
+ leaudio->cis_exist = cis_exist;
+
+ if (leaudio->bis_exist)
+ b->status.map.profile_map |= BTC_BT_BIS;
+ else
+ b->status.map.profile_map &= ~BTC_BT_BIS;
+
+ if (leaudio->cis_exist)
+ b->status.map.profile_map |= BTC_BT_CIS;
+ else
+ b->status.map.profile_map &= ~BTC_BT_CIS;
+
+ _update_bt_link_cnt(rtwdev, bt, bt_56g);
+
+ leaudio->rssi = chip->ops->btc_get_bt_rssi(rtwdev, src->rssi);
+
+ leaudio->bis_cnt_last = leaudio->bis_cnt;
+ leaudio->bis_exist_last = leaudio->bis_exist;
+ leaudio->cis_cnt_last = leaudio->cis_cnt;
+ leaudio->cis_exist_last = leaudio->cis_exist;
+}
+
+static void _update_bt_bistdma_info(struct rtw89_dev *rtwdev, u8 bid,
+ void *buf, u32 len)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_btc_bt_info *bt = (bid == BTC_BT_1ST) ? &cx->bt0 : &cx->bt1;
+ struct rtw89_btc_bt_link_info *b = &bt->link_info;
+ struct rtw89_btc_bt_bistdma_info_le *src = buf;
+ struct rtw89_btc_bt_leaudio_desc *leaudio;
+
+ if ((src->len & BIT(7)) && bt->band_56G_support)
+ b = &bt->link_info_56g;
+
+ leaudio = &b->leaudio_desc;
+
+ if (!memcmp(b->bistdma_raw_info, src, BTC_BTINFO_MAX)) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s return by bistdma-info duplicate!\n",
+ __func__);
+ bt->bcnt[BTC_BCNT_LEAUDIO_INFOSAME]++;
+ return;
+ }
+
+ memcpy(b->bistdma_raw_info, src, BTC_BTINFO_MAX);
+
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s: bis_start_end:%d bis_trx:%d\n",
+ __func__,
+ u8_get_bits(src->bis, RTW89_BTC_BIS_INFO_L2_START_END),
+ u8_get_bits(src->bis, RTW89_BTC_BIS_INFO_L2_TRX));
+
+ leaudio->bis_trx = u8_get_bits(src->bis, RTW89_BTC_BIS_INFO_L2_TRX);
+ leaudio->bis_start_end = u8_get_bits(src->bis,
+ RTW89_BTC_BIS_INFO_L2_START_END);
+
+ leaudio->diff_t = (src->diff_t_hb * 256 + src->diff_t_lb) * 625 / 1000;
+
+ if (btc->ant_type == BTC_ANT_SHARED && leaudio->diff_t > 13)
+ dm->bis_tdma = true;
+ else
+ dm->bis_tdma = false;
+}
+
#define BTC_BTINFO_PWR_LEN 5
static void _update_bt_txpwr_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
{
@@ -9606,6 +9794,14 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
case BTF_EVNT_CX_RUNINFO:
btc->dm.cnt_dm[BTC_DCNT_CX_RUNINFO]++;
break;
+ case BTF_EVNT_BT_LEAUDIO_INFO:
+ bt->bcnt[BTC_BCNT_LEAUDIO_INFOUPDATE]++;
+ if (buf[BTC_BTINFO_L0] == BTC_BTINFO_BISTDMA)
+ _update_bt_bistdma_info(rtwdev, bid, buf, len);
+ else
+ _update_bt_leaudio_info(rtwdev, bid, buf, len);
+ _run_coex(rtwdev, BTC_RSN_UPDATE_BT_LEAUDINFO);
+ break;
case BTF_EVNT_BT_QUERY_TXPWR:
bt->bcnt[BTC_BCNT_TXPWR_UPDATE]++;
_update_bt_txpwr_info(rtwdev, buf, len);
@@ -10107,6 +10303,7 @@ static const char *steps_to_str(u16 step)
CASE_BTC_RSN_STR(ACT1_WORK);
CASE_BTC_RSN_STR(BT_DEVINFO_WORK);
CASE_BTC_RSN_STR(RFK_CHK_WORK);
+ CASE_BTC_RSN_STR(UPDATE_BT_LEAUDINFO);
CASE_BTC_ACT_STR(NONE);
CASE_BTC_ACT_STR(WL_ONLY);
@@ -10131,6 +10328,8 @@ static const char *steps_to_str(u16 step)
CASE_BTC_ACT_STR(BT_A2DP_PAN);
CASE_BTC_ACT_STR(BT_PAN_HID);
CASE_BTC_ACT_STR(BT_A2DP_PAN_HID);
+ CASE_BTC_ACT_STR(BT_BIS);
+ CASE_BTC_ACT_STR(BT_CIS);
CASE_BTC_ACT_STR(WL_25G_MCC);
CASE_BTC_ACT_STR(WL_2G_MCC);
CASE_BTC_ACT_STR(WL_2G_SCC);
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index aaed155ea423..09c19a6b9058 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1383,6 +1383,8 @@ enum rtw89_btc_btinfo {
BTC_BTINFO_MAX
};
+#define BTC_BTINFO_BISTDMA 0x48 /* cmd value that identifies BISTDMA data */
+
enum rtw89_btc_dcnt {
BTC_DCNT_RUN = 0x0,
BTC_DCNT_CX_RUNINFO,
@@ -2167,6 +2169,31 @@ struct rtw89_btc_bt_txpwr_desc {
u8 le_gain_index;
};
+struct rtw89_btc_bt_leaudio_info {
+ u8 cmd;
+ u8 len;
+ u8 bis_cis;
+#define RTW89_BTC_LEAU_INFO_L2_BIS_EX BIT(0)
+#define RTW89_BTC_LEAU_INFO_L2_BIS_CNT GENMASK(3, 1)
+#define RTW89_BTC_LEAU_INFO_L2_CIS_EX BIT(4)
+#define RTW89_BTC_LEAU_INFO_L2_CIS_CNT GENMASK(7, 5)
+ u8 rssi;
+ __le32 hbrsvd;
+} __packed;
+
+struct rtw89_btc_bt_bistdma_info_le {
+ u8 cmd;
+ u8 len;
+ u8 bis; /* BIT(2) ~ BIT(7) is rsvd */
+#define RTW89_BTC_BIS_INFO_L2_START_END BIT(0) /* 0: BIS start, 1: BIS end */
+#define RTW89_BTC_BIS_INFO_L2_TRX BIT(1) /* 0: BIS Tx, 1: BIS Rx */
+ u8 diff_t_lb;
+ u8 diff_t_hb; /* diff_t = (diff_t_hb * 256 + diff_t_lb) * 0.625 ms */
+ u8 hb1rsvd;
+ u8 hb2rsvd;
+ u8 hb3rsvd;
+} __packed;
+
struct rtw89_btc_bt_leaudio_desc {
u32 bis_exist: 1;
u32 bis_exist_last: 1;
@@ -2177,7 +2204,9 @@ struct rtw89_btc_bt_leaudio_desc {
u32 rssi: 8;
u32 bis_cnt_last: 3;
u32 cis_cnt_last: 3;
- u32 rsvd: 8;
+ u32 bis_trx: 1;
+ u32 bis_start_end: 1;
+ u32 rsvd: 6;
u16 diff_t;
};
@@ -2213,6 +2242,9 @@ struct rtw89_btc_bt_link_info {
u8 ble_scan_en: 1;
u8 reinit: 1;
u8 rsvd: 6;
+
+ u8 leaudio_raw_info[BTC_BTINFO_MAX]; /* raw LE audio info from BT mailbox */
+ u8 bistdma_raw_info[BTC_BTINFO_MAX]; /* raw BIS-TDMA info from BT mailbox */
};
struct rtw89_btc_bind_bt_status {
@@ -4085,6 +4117,7 @@ struct rtw89_btc_dm {
u8 lps_ctrl_scbd: 1;
u8 lps_ctrl_scbd_last: 1;
u8 lps_ctrl_change: 1;
+ u8 bis_tdma: 1; /* BIS TDMA mode active */
u8 scbd_write_instant;
bool scbd_b2w_update;
bool scbd_w2b_update;
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 13/14] wifi: rtw89: coex: Fix H2C command redundant send & version fall through
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
I/O offload higher priority sending event didn't return after H2C command
was sent, add a return to prevent send twice in the same time. Update
driver info entry which is handling module control info didn't handle the
version 9 command format, add if condition to handle it. TX power update
H2C command result checker logic was reversed, it will lead to the TX
power value never update again after first update, fix the issue.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 7ab22c60a420..6b3e199398cf 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1073,6 +1073,7 @@ static int _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
}
btc->fwinfo.cnt_h2c++;
+ return 0;
} else { /* Fill H2C MACRO buffer(TLV format) temporarily */
if (btc->hbuf_cnt == 0)
_reset_h2c_macro(btc);
@@ -3500,6 +3501,8 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
if (ver->fcxctrl == 7)
rtw89_fw_h2c_cxdrv_ctrl_v7(rtwdev, index);
+ else if (ver->fcxctrl == 9)
+ rtw89_fw_h2c_cxdrv_ctrl_v9(rtwdev, index);
else
rtw89_fw_h2c_cxdrv_ctrl(rtwdev, index);
break;
@@ -3893,7 +3896,7 @@ static void _set_bt_tx_power(struct rtw89_dev *rtwdev, bool force_exec, u8 bid,
if (rtwdev->chip->chip_gen == RTW89_CHIP_AX)
len = SET_RF_PARA_AX_LEN;
- if (_send_fw_cmd(rtwdev, BTFC_SET, h2c_func, buf, len)) {
+ if (!_send_fw_cmd(rtwdev, BTFC_SET, h2c_func, buf, len)) {
btc->dm.rf_trx_para.bt_tx_power[i] = level;
if (rf_band == RTW89_BAND_2G)
bt->tx_power_now = level;
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 12/14] wifi: rtw89: coex: Fix TDMA v8 handling to unblock BTC report parsing
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
fcxtdma=8 was not handled in _chk_btc_report(), causing the parser to
hit 'goto err' and return 0 when processing the TDMA sub-report. This
broke the _parse_btc_report() loop before reaching BT_VER (type=9),
leaving bt->ver_info.fw always zero on RTL8922A/D.
TDMA v8 uses the same struct layout as v3/v4/v7 (rtw89_btc_fbtc_tdma_v3,
12 bytes), so add it to the existing v3/v4/v7 branch in both switch cases.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 6a718c54de67..7ab22c60a420 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1769,7 +1769,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1);
fwsubver->fcxtdma = 0;
} else if (ver->fcxtdma == 3 || ver->fcxtdma == 4 ||
- ver->fcxtdma == 7) {
+ ver->fcxtdma == 7 || ver->fcxtdma == 8) {
pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3);
fwsubver->fcxtdma = pfwinfo->rpt_fbtc_tdma.finfo.v3.fver;
@@ -2300,7 +2300,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
&pfwinfo->rpt_fbtc_tdma.finfo.v1,
sizeof(dm->tdma_now)));
else if (ver->fcxtdma == 3 || ver->fcxtdma == 4 ||
- ver->fcxtdma == 7)
+ ver->fcxtdma == 7 || ver->fcxtdma == 8)
_chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
memcmp(&dm->tdma_now,
&pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma,
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 11/14] wifi: rtw89: coex: Add dual Bluetooth debug info dump
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
As RTL8922D support dual Bluetooth, add BT debug info dump for it.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 51 ++++++++++++++++-------
1 file changed, 37 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 96bb68f09a01..6a718c54de67 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -9779,10 +9779,13 @@ enum btc_bt_a2dp_type {
BTC_A2DP_TWS_RELAY = 2,
};
-static int _show_bt_profile_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
+static int _show_bt_profile_info(struct rtw89_dev *rtwdev, char *buf,
+ size_t bufsz, u8 bid)
{
struct rtw89_btc *btc = &rtwdev->btc;
- struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt0.link_info;
+ struct rtw89_btc_bt_info *bt = (bid == BTC_BT_1ST) ?
+ &btc->cx.bt0 : &btc->cx.bt1;
+ struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
struct rtw89_btc_bt_hfp_desc hfp = bt_linfo->hfp_desc;
struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
@@ -9835,15 +9838,16 @@ static int _show_bt_profile_info(struct rtw89_dev *rtwdev, char *buf, size_t buf
return p - buf;
}
-static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
+static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz, u8 bid)
{
struct rtw89_btc *btc = &rtwdev->btc;
const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_cx *cx = &btc->cx;
- struct rtw89_btc_bt_info *bt = &cx->bt0;
+ struct rtw89_btc_bt_info *bt = (bid == BTC_BT_1ST) ? &cx->bt0 : &cx->bt1;
struct rtw89_btc_wl_info *wl = &cx->wl;
struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
struct rtw89_btc_module *md = &btc->mdinfo;
+ u8 bt_pos = (bid == BTC_BT_1ST) ? md->bt0_pos : md->bt1_pos;
s8 br_dbm = bt->link_info.bt_txpwr_desc.br_dbm;
s8 le_dbm = bt->link_info.bt_txpwr_desc.le_dbm;
u8 hw_band = wl->role_info.pta_req_band;
@@ -9855,13 +9859,21 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT))
return 0;
- p += scnprintf(p, end - p, "========== [BT Status] ==========\n");
+ if (bid == BTC_BT_2ND) {
+ if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
+ return 0;
+ if (!bt->enable.now)
+ return 0;
+ }
+
+ p += scnprintf(p, end - p, "========== [BT_%s Status] ==========\n",
+ bid == BTC_BT_1ST ? "1ST" : "2ND");
p += scnprintf(p, end - p,
" %-15s : enable:%s, btg:%s%s, connect:%s, ",
"[status]", bt->enable.now ? "Y" : "N",
bt->btg_type ? "Y" : "N",
- (bt->enable.now && (bt->btg_type != md->bt0_pos) ?
+ (bt->enable.now && (bt->btg_type != bt_pos) ?
"(efuse-mismatch!!)" : ""),
(bt_linfo->status.map.connect ? "Y" : "N"));
@@ -9927,7 +9939,7 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
bt->bcnt[BTC_BCNT_INQPAG], bt->bcnt[BTC_BCNT_INQ],
bt->bcnt[BTC_BCNT_PAGE], bt->bcnt[BTC_BCNT_IGNOWL]);
- p += _show_bt_profile_info(rtwdev, p, end - p);
+ p += _show_bt_profile_info(rtwdev, p, end - p, bid);
p += scnprintf(p, end - p,
" %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)\n",
@@ -12034,12 +12046,22 @@ static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
dm->gnt_set[RTW89_PHY_0].gnt_bt0);
if (rtwdev->dbcc_en) {
- p += scnprintf(p, end - p,
- ", phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]",
- dm->gnt_set[RTW89_PHY_1].gnt_wl_sw_en ? "SW" : "HW",
- dm->gnt_set[RTW89_PHY_1].gnt_wl,
- dm->gnt_set[RTW89_PHY_1].gnt_bt0_sw_en ? "SW" : "HW",
- dm->gnt_set[RTW89_PHY_1].gnt_bt0);
+ if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT)
+ p += scnprintf(p, end - p,
+ ", phy-1[gnt_wl:%s-%d/gnt_bt0:%s-%d/gnt_bt1:%s-%d]",
+ dm->gnt_set[RTW89_PHY_1].gnt_wl_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_1].gnt_wl,
+ dm->gnt_set[RTW89_PHY_1].gnt_bt0_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_1].gnt_bt0,
+ dm->gnt_set[RTW89_PHY_1].gnt_bt1_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_1].gnt_bt1);
+ else
+ p += scnprintf(p, end - p,
+ ", phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]",
+ dm->gnt_set[RTW89_PHY_1].gnt_wl_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_1].gnt_wl,
+ dm->gnt_set[RTW89_PHY_1].gnt_bt0_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_1].gnt_bt0);
}
pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
@@ -13020,7 +13042,8 @@ ssize_t rtw89_btc_dump_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += _show_cx_info(rtwdev, p, end - p);
p += _show_wl_info(rtwdev, p, end - p);
- p += _show_bt_info(rtwdev, p, end - p);
+ p += _show_bt_info(rtwdev, p, end - p, BTC_BT_1ST);
+ p += _show_bt_info(rtwdev, p, end - p, BTC_BT_2ND);
p += _show_dm_info(rtwdev, p, end - p);
p += _show_fw_dm_msg(rtwdev, p, end - p);
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 10/14] wifi: rtw89: coex: Add BTC report version 8 support for BT sub-reports
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
RTL8922A (FW >= 0.35.111) and RTL8922D (FW >= 0.35.94) set fcxbtver,
fcxbtscan and fcxbtafh to 8, but the handler in _chk_btc_report only
had branches for version 1 and 7. When version 8 arrived pfinfo was
left NULL and pcinfo->req_len was left at zero, so the length check at
validation stage rejected the report and bt->ver_info.fw was never
written, causing BT_FW:0x0 in the BTC dump.
BT-scan and BT-afh version 8 hit the goto err path for the same reason,
making all BT sub-reports silently broken on these chips.
The structural change in version 8 is that the previously reserved
second byte in each struct is now bt_id (0 = BT0, 1 = BT1), allowing
firmware to send separate reports for each Bluetooth device. All three
structs are otherwise layout-compatible with version 7.
Add rtw89_btc_fbtc_btver_v8, rtw89_btc_fbtc_btscan_v8 and
rtw89_btc_fbtc_btafh_v8 structs with the bt_id field, extend the
corresponding unions, add version 8 branches to _chk_btc_report, and
update _update_bt_report to route each report to BT0 or BT1 according
to BT ID.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 52 ++++++++++++++++++++++-
drivers/net/wireless/realtek/rtw89/core.h | 34 +++++++++++++++
2 files changed, 85 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 5aa06ef430c8..96bb68f09a01 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1529,7 +1529,14 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
switch (rpt_type) {
case BTC_RPT_TYPE_BT_VER:
- if (ver->fcxbtver == 7) {
+ if (ver->fcxbtver == 8) {
+ pver->v8 = *(struct rtw89_btc_fbtc_btver_v8 *)pfinfo;
+ bt = pver->v8.bt_id ? &btc->cx.bt1 : &btc->cx.bt0;
+ bt->ver_info.fw = le32_to_cpu(pver->v8.fw_ver);
+ bt->ver_info.fw_coex = le32_get_bits(pver->v8.coex_ver,
+ GENMASK(7, 0));
+ bt->feature = le32_to_cpu(pver->v8.feature);
+ } else if (ver->fcxbtver == 7) {
pver->v7 = *(struct rtw89_btc_fbtc_btver_v7 *)pfinfo;
bt->ver_info.fw = le32_to_cpu(pver->v7.fw_ver);
bt->ver_info.fw_coex = le32_get_bits(pver->v7.coex_ver,
@@ -1570,6 +1577,19 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
pscan_v7->para[i].intvl == 0)
scan_update = false;
}
+ } else if (ver->fcxbtscan == 8) {
+ struct rtw89_btc_fbtc_btscan_v8 *pscan_v8 =
+ (struct rtw89_btc_fbtc_btscan_v8 *)pfinfo;
+ struct rtw89_btc_bt_info *tbt =
+ pscan_v8->bt_id ? &btc->cx.bt1 : &btc->cx.bt0;
+
+ for (i = 0; i < CXSCAN_MAX; i++) {
+ tbt->scan_info_v2[i] = pscan_v8->para[i];
+ if ((pscan_v8->type & BIT(i)) &&
+ pscan_v8->para[i].win == 0 &&
+ pscan_v8->para[i].intvl == 0)
+ scan_update = false;
+ }
}
if (scan_update)
bt->scan_info_update = 1;
@@ -1597,6 +1617,22 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
memcpy(&bt_linfo->afh_map_le[0], pafh_v7->afh_le_a, 4);
memcpy(&bt_linfo->afh_map_le[4], pafh_v7->afh_le_b, 1);
}
+ } else if (ver->fcxbtafh == 8) {
+ struct rtw89_btc_fbtc_btafh_v8 *pafh_v8 =
+ (struct rtw89_btc_fbtc_btafh_v8 *)pfinfo;
+ struct rtw89_btc_bt_info *tbt =
+ pafh_v8->bt_id ? &btc->cx.bt1 : &btc->cx.bt0;
+ struct rtw89_btc_bt_link_info *tbt_linfo = &tbt->link_info;
+
+ if (pafh_v8->map_type & RPT_BT_AFH_SEQ_LEGACY) {
+ memcpy(&tbt_linfo->afh_map[0], pafh_v8->afh_l, 4);
+ memcpy(&tbt_linfo->afh_map[4], pafh_v8->afh_m, 4);
+ memcpy(&tbt_linfo->afh_map[8], pafh_v8->afh_h, 2);
+ }
+ if (pafh_v8->map_type & RPT_BT_AFH_SEQ_LE) {
+ memcpy(&tbt_linfo->afh_map_le[0], pafh_v8->afh_le_a, 4);
+ memcpy(&tbt_linfo->afh_map_le[4], pafh_v8->afh_le_b, 1);
+ }
} else if (ver->fcxbtafh == 1) {
pafh_v1 = (struct rtw89_btc_fbtc_btafh *)pfinfo;
memcpy(&bt_linfo->afh_map[0], pafh_v1->afh_l, 4);
@@ -1882,6 +1918,12 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v7;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v7);
fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v7.fver;
+ } else if (ver->fcxbtver == 8) {
+ pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v8;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v8);
+ fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v8.fver;
+ } else {
+ goto err;
}
pcinfo->req_fver = ver->fcxbtver;
break;
@@ -1899,6 +1941,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v7;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v7);
fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v7.fver;
+ } else if (ver->fcxbtscan == 8) {
+ pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v8;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v8);
+ fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v8.fver;
} else {
goto err;
}
@@ -1918,6 +1964,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v7;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v7);
fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v7.fver;
+ } else if (ver->fcxbtafh == 8) {
+ pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v8;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v8);
+ fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v8.fver;
} else {
goto err;
}
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index ba3a9b0d4aa2..aaed155ea423 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -2647,10 +2647,19 @@ struct rtw89_btc_fbtc_btscan_v7 {
struct rtw89_btc_bt_scan_info_v2 para[CXSCAN_MAX];
} __packed;
+struct rtw89_btc_fbtc_btscan_v8 {
+ u8 fver; /* btc_ver::fcxbtscan */
+ u8 type;
+ u8 bt_id; /* 0:BT0, 1:BT1 */
+ u8 rsvd1;
+ struct rtw89_btc_bt_scan_info_v2 para[CXSCAN_MAX];
+} __packed;
+
union rtw89_btc_fbtc_btscan {
struct rtw89_btc_fbtc_btscan_v1 v1;
struct rtw89_btc_fbtc_btscan_v2 v2;
struct rtw89_btc_fbtc_btscan_v7 v7;
+ struct rtw89_btc_fbtc_btscan_v8 v8;
};
struct rtw89_btc_bt_info {
@@ -3683,9 +3692,21 @@ struct rtw89_btc_fbtc_btver_v7 {
__le32 feature;
} __packed;
+struct rtw89_btc_fbtc_btver_v8 {
+ u8 fver;
+ u8 bt_id; /* 0:BT0, 1:BT1 */
+ u8 rsvd1;
+ u8 rsvd2;
+
+ __le32 coex_ver; /*bit[15:8]->shared, bit[7:0]->non-shared */
+ __le32 fw_ver;
+ __le32 feature;
+} __packed;
+
union rtw89_btc_fbtc_btver {
struct rtw89_btc_fbtc_btver_v1 v1;
struct rtw89_btc_fbtc_btver_v7 v7;
+ struct rtw89_btc_fbtc_btver_v8 v8;
} __packed;
struct rtw89_btc_fbtc_btafh {
@@ -3721,6 +3742,18 @@ struct rtw89_btc_fbtc_btafh_v7 {
u8 afh_le_b[4];
} __packed;
+struct rtw89_btc_fbtc_btafh_v8 {
+ u8 fver;
+ u8 map_type;
+ u8 bt_id; /* 0:BT0, 1:BT1 */
+ u8 rsvd1;
+ u8 afh_l[4]; /*bit0:2402, bit1:2403.... bit31:2433 */
+ u8 afh_m[4]; /*bit0:2434, bit1:2435.... bit31:2465 */
+ u8 afh_h[4]; /*bit0:2466, bit1:2467.....bit14:2480 */
+ u8 afh_le_a[4];
+ u8 afh_le_b[4];
+} __packed;
+
struct rtw89_btc_fbtc_btdevinfo {
u8 fver; /* btc_ver::fcxbtdevinfo */
u8 rsvd;
@@ -4194,6 +4227,7 @@ union rtw89_btc_fbtc_btafh_info {
struct rtw89_btc_fbtc_btafh v1;
struct rtw89_btc_fbtc_btafh_v2 v2;
struct rtw89_btc_fbtc_btafh_v7 v7;
+ struct rtw89_btc_fbtc_btafh_v8 v8;
};
struct rtw89_btc_report_ctrl_state {
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 09/14] wifi: rtw89: coex: Fix log dump format with proper newline
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
Fix the log output format in _show_mreg_v7() where the phy-0 gnt_status
line was missing the proper field label and newline. Use the standard
" %-15s : " format with "[gnt_status]" label consistent with the rest
of the dump output.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 167 ++++++++++++----------
1 file changed, 88 insertions(+), 79 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 187e7e70e86d..5aa06ef430c8 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -9656,8 +9656,10 @@ static int _show_wl_role_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
plink->client_cnt - 1, plink->mode,
plink->ch, plink->bw);
- if (plink->connected == MLME_NO_LINK)
+ if (plink->connected == MLME_NO_LINK) {
+ p += scnprintf(p, end - p, "\n");
continue;
+ }
p += scnprintf(p, end - p,
", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n",
@@ -9747,7 +9749,7 @@ static int _show_bt_profile_info(struct rtw89_dev *rtwdev, char *buf, size_t buf
if (hid.exist) {
p += scnprintf(p, end - p,
- "\n\r %-15s : type:%s%s%s%s%s pair-cnt:%d, sut_pwr:%d, golden-rx:%d\n",
+ "\n %-15s : type:%s%s%s%s%s pair-cnt:%d, sut_pwr:%d, golden-rx:%d\n",
"[HID]",
hid.type & BTC_HID_218 ? "2/18," : "",
hid.type & BTC_HID_418 ? "4/18," : "",
@@ -10345,7 +10347,7 @@ static int _show_dm_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
"" : "(Mismatch!!)"));
p += scnprintf(p, end - p,
- " %-15s : wl[rssi_lvl:%d/para:%d/tx_pwr:[%d %d]/rx_lvl:[%d %d]/lna2:%d/stb_chg:%d]\n ",
+ " %-15s : wl[rssi_lvl:%d/para:%d/tx_pwr:[%d %d]/rx_lvl:[%d %d]/lna2:%d/stb_chg:%d]\n",
"[dm_rf_ctrl]",
wl->rssi_level, dm->trx_para_level,
dm->rf_trx_para.wl_tx_power[RTW89_PHY_0],
@@ -10355,7 +10357,7 @@ static int _show_dm_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
dm->wl_lna2, dm->wl_stb_chg);
p += scnprintf(p, end - p,
- " %-15s : pre_agc:%d, btg_rx:%d\n ",
+ " %-15s : pre_agc:%d, btg_rx:%d\n",
"[dm_bb_ctrl]", dm->wl_pre_agc, dm->wl_btg_rx);
p += scnprintf(p, end - p,
@@ -10467,11 +10469,9 @@ static int _show_fbtc_tdma(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
t->bind, t->leak_n, t->ext_ctrl);
p += scnprintf(p, end - p,
- "policy_type:%d",
+ "policy_type:%d\n",
(u32)btc->policy_type);
- p += scnprintf(p, end - p, "\n");
-
return p - buf;
}
@@ -10778,11 +10778,9 @@ static int _show_fbtc_cysta_v3(struct rtw89_dev *rtwdev, char *buf, size_t bufsz
le16_to_cpu(pcysta->a2dp_ept.cnt),
le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
- p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
+ p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d\n",
le16_to_cpu(pcysta->a2dp_ept.tavg),
le16_to_cpu(pcysta->a2dp_ept.tmax));
-
- p += scnprintf(p, end - p, "\n");
}
out:
@@ -10917,11 +10915,9 @@ static int _show_fbtc_cysta_v4(struct rtw89_dev *rtwdev, char *buf, size_t bufsz
le16_to_cpu(pcysta->a2dp_ept.cnt),
le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
- p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
+ p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d\n",
le16_to_cpu(pcysta->a2dp_ept.tavg),
le16_to_cpu(pcysta->a2dp_ept.tmax));
-
- p += scnprintf(p, end - p, "\n");
}
out:
@@ -11055,11 +11051,9 @@ static int _show_fbtc_cysta_v5(struct rtw89_dev *rtwdev, char *buf, size_t bufsz
le16_to_cpu(pcysta->a2dp_ept.cnt),
le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
- p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
+ p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d\n",
le16_to_cpu(pcysta->a2dp_ept.tavg),
le16_to_cpu(pcysta->a2dp_ept.tmax));
-
- p += scnprintf(p, end - p, "\n");
}
out:
@@ -11193,11 +11187,9 @@ static int _show_fbtc_cysta_v105(struct rtw89_dev *rtwdev, char *buf, size_t buf
le16_to_cpu(pcysta->a2dp_ept.cnt),
le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
- p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
+ p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d\n",
le16_to_cpu(pcysta->a2dp_ept.tavg),
le16_to_cpu(pcysta->a2dp_ept.tmax));
-
- p += scnprintf(p, end - p, "\n");
}
out:
@@ -11246,7 +11238,7 @@ static int _show_fbtc_cysta_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz
le16_to_cpu(pcysta->skip_cnt));
p += scnprintf(p, end - p,
- "\n\r %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
+ "\n %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
"[cycle_stat]",
le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
@@ -11267,7 +11259,7 @@ static int _show_fbtc_cysta_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz
if (a2dp->exist) {
p += scnprintf(p, end - p,
- "\n\r %-15s : a2dp_ept:%d, a2dp_late:%d(streak 2S:%d/max:%d)",
+ "\n %-15s : a2dp_ept:%d, a2dp_late:%d(streak 2S:%d/max:%d)",
"[a2dp_stat]",
le16_to_cpu(pcysta->a2dp_ept.cnt),
le16_to_cpu(pcysta->a2dp_ept.cnt_timeout),
@@ -11306,10 +11298,10 @@ static int _show_fbtc_cysta_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz
if (cnt % divide_cnt == 1) {
if (a2dp->exist)
- p += scnprintf(p, end - p, "\n\r %-15s : ",
+ p += scnprintf(p, end - p, "\n %-15s : ",
"[slotT_wermtan]");
else
- p += scnprintf(p, end - p, "\n\r %-15s : ",
+ p += scnprintf(p, end - p, "\n %-15s : ",
"[slotT_rxerr]");
}
@@ -11370,7 +11362,7 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
ns = &pfwinfo->rpt_fbtc_nullsta.finfo;
if (ver->fcxnullsta == 1) {
for (i = 0; i < 2; i++) {
- p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]");
+ p += scnprintf(p, end - p, "\n %-15s : ", "[NULL-STA]");
p += scnprintf(p, end - p, "null-%d", i);
p += scnprintf(p, end - p, "[ok:%d/",
le32_to_cpu(ns->v1.result[i][1]));
@@ -11389,7 +11381,7 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
}
} else if (ver->fcxnullsta == 7) {
for (i = 0; i < 2; i++) {
- p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]");
+ p += scnprintf(p, end - p, "\n %-15s : ", "[NULL-STA]");
p += scnprintf(p, end - p, "null-%d", i);
p += scnprintf(p, end - p, "[Tx:%d/",
le32_to_cpu(ns->v7.result[i][4]));
@@ -11410,7 +11402,7 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
}
} else {
for (i = 0; i < 2; i++) {
- p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]");
+ p += scnprintf(p, end - p, "\n %-15s : ", "[NULL-STA]");
p += scnprintf(p, end - p, "null-%d", i);
p += scnprintf(p, end - p, "[Tx:%d/",
le32_to_cpu(ns->v2.result[i][4]));
@@ -11717,7 +11709,7 @@ static int _show_gpio_dbg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
if (!en_map)
goto out;
- p += scnprintf(p, end - p, "\n\r %-15s : enable_map:0x%08x",
+ p += scnprintf(p, end - p, "\n %-15s : enable_map:0x%08x",
"[gpio_dbg]", en_map);
for (i = 0; i < BTC_DBG_NUM; i++) {
@@ -11943,7 +11935,7 @@ static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
if (!(dm->coex_info_map & BTC_COEX_INFO_MREG))
return 0;
- p += scnprintf(p, end - p, "\n\r========== [HW Status] ==========");
+ p += scnprintf(p, end - p, "\n========== [HW Status] ==========\n");
p += scnprintf(p, end - p,
" %-15s : WL->BT0:0x%08x(cnt:%d), BT0->WL:0x%08x(total:%d, bt_update:%d)\n",
@@ -11965,18 +11957,31 @@ static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
dm->pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
p += scnprintf(p, end - p,
- "\n\r %-15s : pta_owner:%s, pta_req_mac:MAC%d, rf_gnt_source: polut_type:%s",
+ " %-15s : pta_owner:%s, pta_req_mac:MAC%d, rf_gnt_source: polut_type:%s\n",
"[gnt_status]",
rtwdev->chip->para_ver & BTC_FEAT_PTA_ONOFF_CTRL ? "HW" :
dm->pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
wl->pta_req_mac,
id_to_polut(wl->bt_polut_type[wl->pta_req_mac]));
- p += scnprintf(p, end - p, ", phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d]",
- dm->gnt_set[RTW89_PHY_0].gnt_wl_sw_en ? "SW" : "HW",
- dm->gnt_set[RTW89_PHY_0].gnt_wl,
- dm->gnt_set[RTW89_PHY_0].gnt_bt0_sw_en ? "SW" : "HW",
- dm->gnt_set[RTW89_PHY_0].gnt_bt0);
+ if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT)
+ p += scnprintf(p, end - p,
+ " %-15s : phy-0[gnt_wl:%s-%d/gnt_bt0:%s-%d/gnt_bt1:%s-%d]",
+ "[gnt_status]",
+ dm->gnt_set[RTW89_PHY_0].gnt_wl_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_0].gnt_wl,
+ dm->gnt_set[RTW89_PHY_0].gnt_bt0_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_0].gnt_bt0,
+ dm->gnt_set[RTW89_PHY_0].gnt_bt1_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_0].gnt_bt1);
+ else
+ p += scnprintf(p, end - p,
+ " %-15s : phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d]",
+ "[gnt_status]",
+ dm->gnt_set[RTW89_PHY_0].gnt_wl_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_0].gnt_wl,
+ dm->gnt_set[RTW89_PHY_0].gnt_bt0_sw_en ? "SW" : "HW",
+ dm->gnt_set[RTW89_PHY_0].gnt_bt0);
if (rtwdev->dbcc_en) {
p += scnprintf(p, end - p,
@@ -12000,7 +12005,7 @@ static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
if (cnt % 6 == 0)
p += scnprintf(p, end - p,
- "\n\r %-15s : %s_0x%x=0x%x", "[reg]",
+ "\n %-15s : %s_0x%x=0x%x", "[reg]",
id_to_regtype(type), offset, val);
else
p += scnprintf(p, end - p, ", %s_0x%x=0x%x",
@@ -12336,12 +12341,11 @@ static int _show_summary_v5(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
p += scnprintf(p, end - p,
- "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
+ "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
cnt[BTC_NCNT_WL_STA]);
- p += scnprintf(p, end - p, "\n");
p += scnprintf(p, end - p,
" %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
"[notify_cnt]",
@@ -12457,12 +12461,11 @@ static int _show_summary_v105(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
p += scnprintf(p, end - p,
- "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
+ "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
cnt[BTC_NCNT_WL_STA]);
- p += scnprintf(p, end - p, "\n");
p += scnprintf(p, end - p,
" %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
"[notify_cnt]",
@@ -12495,7 +12498,7 @@ static int _show_summary_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
return 0;
p += scnprintf(p, end - p, "%s",
- "\n\r========== [Statistics] ==========");
+ "\n========== [Statistics] ==========\n");
pcinfo = &pfwinfo->rpt_ctrl.cinfo;
if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
@@ -12503,7 +12506,7 @@ static int _show_summary_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
prptctrl = &pfwinfo->rpt_ctrl.finfo.v7;
p += scnprintf(p, end - p,
- "\n\r %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d),"
+ " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d),"
"c2h_cnt=%d(fw_send:%d, len:%d, max:%d), ",
"[summary]", pfwinfo->cnt_h2c,
pfwinfo->cnt_h2c_fail,
@@ -12521,16 +12524,17 @@ static int _show_summary_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
if (dm->error.map.wl_fw_hang)
p += scnprintf(p, end - p, " (WL FW Hang!!)");
+ p += scnprintf(p, end - p, "\n");
p += scnprintf(p, end - p,
- "\n\r %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
+ " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
"[mailbox]",
le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
p += scnprintf(p, end - p,
- "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)",
+ "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)\n",
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
@@ -12538,7 +12542,7 @@ static int _show_summary_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
p += scnprintf(p, end - p,
- "\n\r %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
+ " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
"[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
wl->wcnt[BTC_WCNT_RFK_GO],
wl->wcnt[BTC_WCNT_RFK_REJECT],
@@ -12548,12 +12552,12 @@ static int _show_summary_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p, ", bt_rfk[req:%d]",
le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
- p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]",
+ p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]\n",
le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
} else {
p += scnprintf(p, end - p,
- "\n\r %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)",
+ " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)\n",
"[summary]",
pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
pfwinfo->cnt_c2h,
@@ -12564,19 +12568,19 @@ static int _show_summary_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
cnt_sum += dm->cnt_notify[i];
p += scnprintf(p, end - p,
- "\n\r %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
+ " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
"[notify_cnt]",
cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
p += scnprintf(p, end - p,
- "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
+ "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
cnt[BTC_NCNT_WL_STA]);
p += scnprintf(p, end - p,
- "\n\r %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
+ " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
"[notify_cnt]",
cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
@@ -12608,7 +12612,7 @@ static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
return 0;
p += scnprintf(p, end - p, "%s",
- "\n\r========== [Statistics] ==========");
+ "\n========== [Statistics] ==========\n");
pcinfo = &pfwinfo->rpt_ctrl.cinfo;
if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
@@ -12616,7 +12620,7 @@ static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
prptctrl = &pfwinfo->rpt_ctrl.finfo.v8;
p += scnprintf(p, end - p,
- "\n\r %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, max:fw-%d/drv-%d), ",
+ " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, max:fw-%d/drv-%d), ",
"[summary]", pfwinfo->cnt_h2c,
pfwinfo->cnt_h2c_fail,
le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
@@ -12634,16 +12638,17 @@ static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
if (dm->error.map.wl_fw_hang)
p += scnprintf(p, end - p, " (WL FW Hang!!)");
+ p += scnprintf(p, end - p, "\n");
p += scnprintf(p, end - p,
- "\n\r %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
+ " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
"[mailbox]",
le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
p += scnprintf(p, end - p,
- "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)",
+ "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)\n",
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
@@ -12651,7 +12656,7 @@ static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
p += scnprintf(p, end - p,
- "\n\r %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
+ " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
"[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
wl->wcnt[BTC_WCNT_RFK_GO],
wl->wcnt[BTC_WCNT_RFK_REJECT],
@@ -12661,12 +12666,12 @@ static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p, ", bt_rfk[req:%d]",
le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
- p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]",
+ p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]\n",
le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
} else {
p += scnprintf(p, end - p,
- "\n\r %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)",
+ " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)\n",
"[summary]",
pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
pfwinfo->cnt_c2h,
@@ -12677,19 +12682,19 @@ static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
cnt_sum += dm->cnt_notify[i];
p += scnprintf(p, end - p,
- "\n\r %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
+ " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
"[notify_cnt]",
cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
p += scnprintf(p, end - p,
- "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
+ "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
cnt[BTC_NCNT_WL_STA]);
p += scnprintf(p, end - p,
- "\n\r %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
+ " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
"[notify_cnt]",
cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
@@ -12721,7 +12726,7 @@ static int _show_summary_v9(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
return 0;
p += scnprintf(p, end - p, "%s",
- "\n\r========== [Statistics] ==========");
+ "\n========== [Statistics] ==========\n");
pcinfo = &pfwinfo->rpt_ctrl.cinfo;
if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
@@ -12729,7 +12734,7 @@ static int _show_summary_v9(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
prptctrl = &pfwinfo->rpt_ctrl.finfo.v9;
p += scnprintf(p, end - p,
- "\n\r %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, ",
+ " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, ",
"[summary]", pfwinfo->cnt_h2c,
pfwinfo->cnt_h2c_fail,
le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
@@ -12745,16 +12750,17 @@ static int _show_summary_v9(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
if (dm->error.map.wl_fw_hang)
p += scnprintf(p, end - p, " (WL FW Hang!!)");
+ p += scnprintf(p, end - p, "\n");
p += scnprintf(p, end - p,
- "\n\r %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
+ " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
"[mailbox]",
le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
p += scnprintf(p, end - p,
- "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)",
+ "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)\n",
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
@@ -12762,7 +12768,7 @@ static int _show_summary_v9(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
p += scnprintf(p, end - p,
- "\n\r %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
+ " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
"[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
wl->wcnt[BTC_WCNT_RFK_GO],
wl->wcnt[BTC_WCNT_RFK_REJECT],
@@ -12772,12 +12778,12 @@ static int _show_summary_v9(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p, ", bt_rfk[req:%d]",
le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
- p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]",
+ p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]\n",
le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
} else {
p += scnprintf(p, end - p,
- "\n\r %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)",
+ " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)\n",
"[summary]",
pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
pfwinfo->cnt_c2h,
@@ -12788,19 +12794,19 @@ static int _show_summary_v9(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
cnt_sum += dm->cnt_notify[i];
p += scnprintf(p, end - p,
- "\n\r %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
+ " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
"[notify_cnt]",
cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
p += scnprintf(p, end - p,
- "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
+ "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
cnt[BTC_NCNT_WL_STA]);
p += scnprintf(p, end - p,
- "\n\r %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
+ " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
"[notify_cnt]",
cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
@@ -12832,7 +12838,7 @@ static int _show_summary_v11(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
return 0;
p += scnprintf(p, end - p, "%s",
- "\n\r========== [Statistics] ==========");
+ "\n========== [Statistics] ==========\n");
pcinfo = &pfwinfo->rpt_ctrl.cinfo;
if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
@@ -12840,7 +12846,7 @@ static int _show_summary_v11(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
prptctrl = &pfwinfo->rpt_ctrl.finfo.v11;
p += scnprintf(p, end - p,
- "\n\r %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, max:fw-%d/drv-%d), ",
+ " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, max:fw-%d/drv-%d), ",
"[summary]", pfwinfo->cnt_h2c,
pfwinfo->cnt_h2c_fail,
le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
@@ -12858,16 +12864,17 @@ static int _show_summary_v11(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
if (dm->error.map.wl_fw_hang)
p += scnprintf(p, end - p, " (WL FW Hang!!)");
+ p += scnprintf(p, end - p, "\n");
p += scnprintf(p, end - p,
- "\n\r %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
+ " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
"[mailbox]",
le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
p += scnprintf(p, end - p,
- "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)",
+ "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)\n",
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
@@ -12875,19 +12882,19 @@ static int _show_summary_v11(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
p += scnprintf(p, end - p,
- "\n\r %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
+ " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
"[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
wl->wcnt[BTC_WCNT_RFK_GO],
wl->wcnt[BTC_WCNT_RFK_REJECT],
wl->wcnt[BTC_WCNT_RFK_TIMEOUT],
wl->rfk_info.proc_time);
- p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]",
+ p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]\n",
le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
} else {
p += scnprintf(p, end - p,
- "\n\r %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)",
+ " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)\n",
"[summary]",
pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
pfwinfo->cnt_c2h,
@@ -12898,19 +12905,19 @@ static int _show_summary_v11(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
cnt_sum += dm->cnt_notify[i];
p += scnprintf(p, end - p,
- "\n\r %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
+ " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
"[notify_cnt]",
cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
p += scnprintf(p, end - p,
- "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
+ "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
cnt[BTC_NCNT_WL_STA]);
p += scnprintf(p, end - p,
- "\n\r %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
+ " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
"[notify_cnt]",
cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
@@ -12993,6 +13000,8 @@ ssize_t rtw89_btc_dump_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
else if (ver->fcxbtcrpt == 11)
p += _show_summary_v11(rtwdev, p, end - p);
+ p += scnprintf(p, end - p, "\n");
+
return p - buf;
}
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 08/14] wifi: rtw89: coex: Refine RF calibration notify flow
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
BT-coexistence only needs to record RF calibration is doing or not, don't
need to record the status of the calibration steps.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 96ec5fa20422..187e7e70e86d 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -9144,14 +9144,13 @@ static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
wl->rfk_info.state = BTC_WRFK_START;
btc->cx.wl.wcnt[BTC_WCNT_RFK_REQ]++;
- btc->cx.wl.wcnt[BTC_WCNT_RFK_GO]++;
btc->dm.cnt_notify[BTC_NCNT_WL_RFK]++;
_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_WLRFK, true);
break;
case BTC_WRFK_ONESHOT_START:
case BTC_WRFK_ONESHOT_STOP:
- wl->rfk_info.state = state;
+ btc->cx.wl.wcnt[BTC_WCNT_RFK_GO]++;
if (type != BTC_WRFKT_RXDCK)
return BTC_WRFK_ALLOW;
break;
@@ -9165,7 +9164,7 @@ static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
default:
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s() warning state=%d\n", __func__, state);
- break;
+ return result;
}
if (result == BTC_WRFK_ALLOW) {
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 07/14] wifi: rtw89: coex: complete GPIO debug configuration handler
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
Complete the implementation of _fw_set_gpio() function to support all
GPIO control configuration types for coexistence. Included debug signal,
antenna switch, external I2C mailbox, external PTA related GPIO
configuration. This function is called during initialization and when
BT re-enables.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 234 +++++++++++++++++++++-
drivers/net/wireless/realtek/rtw89/coex.h | 35 ----
drivers/net/wireless/realtek/rtw89/core.h | 162 ++++++++++++++-
drivers/net/wireless/realtek/rtw89/fw.h | 10 +
4 files changed, 392 insertions(+), 49 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index ae458917ecf7..96ec5fa20422 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -3206,6 +3206,212 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
rtw89_set_coex_ctrl_lps(rtwdev, btc->btc_ctrl_lps);
}
+static u8 _get_gpiosig_for_ver(struct rtw89_dev *rtwdev, u8 sig_v8)
+{
+ const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
+
+ /* v8: gpio_ver >= 8, directly use v8 signal ID */
+ if (ver->fcxgpiodbg >= 8)
+ return sig_v8;
+
+ /* v7: gpio_ver < 8, convert v8 signal ID to v7 signal ID */
+ if (sig_v8 <= BTC_DBG_GNT_WL) {
+ return sig_v8;
+ } else if (sig_v8 <= BTC_DBG_GNT_WL1) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): sig %d not supported in v7\n",
+ __func__, sig_v8);
+ return BTC_DBG_NUM;
+ } else if (sig_v8 >= BTC_DBG_NUM) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): sig %d not available\n",
+ __func__, sig_v8);
+ return BTC_DBG_NUM;
+ } else {
+ return sig_v8 - 2;
+ }
+}
+
+static u32 _convert_gpio_enmap_to_ver(struct rtw89_dev *rtwdev, u32 en_map_v8)
+{
+ const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
+ u32 en_map_v7 = 0;
+ u32 bit;
+
+ /* v8: gpio_ver >= 8, directly use v8 en_map */
+ if (ver->fcxgpiodbg >= 8)
+ return en_map_v8;
+
+ /* v7: gpio_ver < 8, convert v8 en_map bitmap to v7 en_map bitmap */
+ /* bit 0-1: GNT_BT, GNT_WL - same position in both versions */
+ en_map_v7 |= en_map_v8 & GENMASK(1, 0);
+
+ /* bit 2-3: GNT_BT1, GNT_WL1 - not supported in v7, skip these bits */
+
+ /* bit 4-31: shift right by 2 positions (become bit 2-29 in v7) */
+ for (bit = BTC_DBG_BCN_EARLY; bit < BTC_DBG_NUM; bit++) {
+ if (en_map_v8 & BIT(bit))
+ en_map_v7 |= BIT(bit - 2);
+ }
+
+ return en_map_v7;
+}
+
+static u32 _convert_gpio_enmap_from_ver(struct rtw89_dev *rtwdev, u32 en_map)
+{
+ const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
+ u32 en_map_v8 = 0;
+ u32 bit;
+
+ if (ver->fcxgpiodbg >= 8)
+ return en_map;
+
+ /* bit 0-1: GNT_BT, GNT_WL - same position in both versions */
+ en_map_v8 |= en_map & GENMASK(1, 0);
+
+ /* bit 2-29: shift left by 2 positions (become bit 4-31 in v8) */
+ for (bit = BTC_DBG_GNT_BT1; bit < BTC_DBG_NUM - 2; bit++) {
+ if (en_map & BIT(bit))
+ en_map_v8 |= BIT(bit + 2);
+ }
+
+ return en_map_v8;
+}
+
+static void _fw_set_gpio(struct rtw89_dev *rtwdev, u8 type, u32 val)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_fbtc_h2c_set_gpio *gpio = &btc->gpio;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ struct rtw89_fbtc_h2c_set_gpio_2b l2_h2c;
+ struct rtw89_fbtc_h2c_set_gpio_4b l4_h2c;
+ u8 gpio_ver = ver->fcxgpiodbg;
+ u8 buf[sizeof(l4_h2c)];
+ u8 len;
+
+ if (gpio_ver < 8 && type > CXDGPIO_MUX_MAP)
+ return;
+
+ if (type >= CXDGPIO_MAX)
+ return;
+
+ switch (type) {
+ case CXDGPIO_EN_MAP: /* GPIO debug signal en-map 0~31 */
+ val = _convert_gpio_enmap_to_ver(rtwdev, val);
+ gpio->en_map.data.type = CXDGPIO_EN_MAP;
+ gpio->en_map.data.fver = gpio_ver;
+ gpio->en_map.data.dlen = CXDGPIO_SET_L4;
+ gpio->en_map.data.en_map = val;
+ l4_h2c = gpio->en_map.fmt;
+ put_unaligned_le32(val, (u32 *)l4_h2c.data);
+ memcpy(buf, &l4_h2c, sizeof(l4_h2c));
+ len = sizeof(l4_h2c);
+ break;
+ case CXDGPIO_MUX_MAP: /* GPIO dbg: Signal to GPIO Mux */
+ gpio->mux.data.type = CXDGPIO_MUX_MAP;
+ gpio->mux.data.fver = gpio_ver;
+ gpio->mux.data.dlen = CXDGPIO_SET_L2;
+ gpio->mux.data.sig = _get_gpiosig_for_ver(rtwdev,
+ FIELD_GET(GENMASK(7, 0), val));
+ if (gpio->mux.data.sig == 0xff)
+ return;
+ gpio->mux.data.gpio = FIELD_GET(GENMASK(15, 8), val);
+ l2_h2c = gpio->mux.fmt;
+ memcpy(buf, &l2_h2c, sizeof(l2_h2c));
+ len = sizeof(l2_h2c);
+ break;
+ case CXDGPIO_EXT_HPTA: /* GPIO config for Ext HW-PTA */
+ gpio->ext_pta.data.type = CXDGPIO_EXT_HPTA;
+ gpio->ext_pta.data.fver = gpio_ver;
+ gpio->ext_pta.data.dlen = CXDGPIO_SET_L2;
+ gpio->ext_pta.data.map_low = FIELD_GET(GENMASK(7, 0), val);
+ gpio->ext_pta.data.map_high = FIELD_GET(GENMASK(15, 8), val);
+ l2_h2c = gpio->ext_pta.fmt;
+ memcpy(buf, &l2_h2c, sizeof(l2_h2c));
+ len = sizeof(l2_h2c);
+ break;
+ case CXDGPIO_EXT_HMBX: /* GPIO config for Ext HW-mailbox */
+ gpio->ext_mb.data.type = CXDGPIO_EXT_HMBX;
+ gpio->ext_mb.data.fver = gpio_ver;
+ gpio->ext_mb.data.dlen = CXDGPIO_SET_L2;
+ gpio->ext_mb.data.map_low = FIELD_GET(GENMASK(7, 0), val);
+ gpio->ext_mb.data.map_high = FIELD_GET(GENMASK(15, 8), val);
+ l2_h2c = gpio->ext_mb.fmt;
+ memcpy(buf, &l2_h2c, sizeof(l2_h2c));
+ len = sizeof(l2_h2c);
+ break;
+ case CXDGPIO_EXT_SWOUT: /* GPIO config for Ext SW output (wlan_act) */
+ gpio->ext_swout.data.type = CXDGPIO_EXT_SWOUT;
+ gpio->ext_swout.data.fver = gpio_ver;
+ gpio->ext_swout.data.dlen = CXDGPIO_SET_L2;
+ gpio->ext_swout.data.map_low = FIELD_GET(GENMASK(7, 0), val);
+ gpio->ext_swout.data.map_high = FIELD_GET(GENMASK(15, 8), val);
+ l2_h2c = gpio->ext_swout.fmt;
+ memcpy(buf, &l2_h2c, sizeof(l2_h2c));
+ len = sizeof(l2_h2c);
+ break;
+ case CXDGPIO_EXT_SWIN: /* GPIO config for Ext SW input control */
+ gpio->ext_swin.data.type = CXDGPIO_EXT_SWIN;
+ gpio->ext_swin.data.fver = gpio_ver;
+ gpio->ext_swin.data.dlen = CXDGPIO_SET_L4;
+ gpio->ext_swin.data.in_map_low = FIELD_GET(GENMASK(7, 0), val);
+ gpio->ext_swin.data.in_map_high = FIELD_GET(GENMASK(15, 8), val);
+ gpio->ext_swin.data.int_map_low = FIELD_GET(GENMASK(23, 16), val);
+ gpio->ext_swin.data.int_map_high = FIELD_GET(GENMASK(31, 24), val);
+ l4_h2c = gpio->ext_swin.fmt;
+ put_unaligned_le32(val, (u32 *)l4_h2c.data);
+ memcpy(buf, &l4_h2c, sizeof(l4_h2c));
+ len = sizeof(l4_h2c);
+ break;
+ default:
+ return;
+ }
+
+ _send_fw_cmd(rtwdev, BTFC_SET, SET_GPIO_DBG, buf, len);
+}
+
+static void _set_ext_interface(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_cx *cx = &btc->cx;
+ u8 bt1_sw_type = BTC_SWITCH_INTERNAL;
+ u32 val;
+
+ if (btc->ver->fcxgpiodbg < 7)
+ return;
+
+ /* if BT1+WL-S0, route DBG_GNT_BT1 to control SPDT */
+ if ((rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) &&
+ btc->ver->fcxinit >= 10) {
+ if (btc->ver->fcxinit >= 10)
+ bt1_sw_type = btc->mdinfo.bt1_sw_type;
+ else
+ return;
+
+ if (bt1_sw_type > BTC_SWITCH_INTERNAL) {
+ _fw_set_gpio(rtwdev, CXDGPIO_EN_MAP,
+ BIT(BTC_DBG_GNT_BT1));
+
+ val = (bt1_sw_type << 8) + BTC_DBG_GNT_BT1;
+ _fw_set_gpio(rtwdev, CXDGPIO_MUX_MAP, val);
+ }
+ }
+
+ /* set GPIO as Ext-PTA interface wire */
+ if (cx->bt_ext.hw_coex & BTC_EXTSOC_INTF_PTA)
+ _fw_set_gpio(rtwdev, CXDGPIO_EXT_HPTA, cx->bt_ext.hpta_cfg);
+
+ /* set GPIO as Ext-mailbox interface wire */
+ if (cx->bt_ext.hw_coex & BTC_EXTSOC_INTF_MBX)
+ _fw_set_gpio(rtwdev, CXDGPIO_EXT_HMBX, cx->bt_ext.hmbx_cfg);
+
+ /* set GPIO as Ext-SWIO interface wire */
+ if (cx->bt_ext.hw_coex & BTC_EXTSOC_INTF_SWIO) {
+ _fw_set_gpio(rtwdev, CXDGPIO_EXT_SWOUT, cx->bt_ext.swout_cfg);
+ _fw_set_gpio(rtwdev, CXDGPIO_EXT_SWIN, cx->bt_ext.swin_cfg);
+ }
+}
+
static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -8251,6 +8457,7 @@ static void _set_init_info(struct rtw89_dev *rtwdev)
_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
rtw89_btc_fw_set_slots(rtwdev);
btc_fw_set_monreg(rtwdev);
+ _set_ext_interface(rtwdev);
_set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR, RTW89_PHY_0);
}
@@ -9779,6 +9986,8 @@ static const char *id_to_gdbg(u32 id)
switch (id) {
CASE_BTC_GDBG_STR(GNT_BT);
CASE_BTC_GDBG_STR(GNT_WL);
+ CASE_BTC_GDBG_STR(GNT_BT1);
+ CASE_BTC_GDBG_STR(GNT_WL1);
CASE_BTC_GDBG_STR(BCN_EARLY);
CASE_BTC_GDBG_STR(WL_NULL0);
CASE_BTC_GDBG_STR(WL_NULL1);
@@ -9807,8 +10016,6 @@ static const char *id_to_gdbg(u32 id)
CASE_BTC_GDBG_STR(SLOT_B1FDD);
CASE_BTC_GDBG_STR(BT_CHANGE);
CASE_BTC_GDBG_STR(WL_CCA);
- CASE_BTC_GDBG_STR(BT_LEAUDIO);
- CASE_BTC_GDBG_STR(USER_DEF);
default:
return "unknown";
}
@@ -11487,8 +11694,8 @@ static int _show_gpio_dbg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
union rtw89_btc_fbtc_gpio_dbg *gdbg = NULL;
char *p = buf, *end = buf + bufsz;
- u8 *gpio_map, i;
- u32 en_map;
+ u32 en_map_raw, en_map;
+ u8 *gpio_map, i, sig;
pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
gdbg = &rtwdev->btc.fwinfo.rpt_fbtc_gpio_dbg.finfo;
@@ -11499,27 +11706,32 @@ static int _show_gpio_dbg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
goto out;
}
- if (ver->fcxgpiodbg == 7) {
- en_map = le32_to_cpu(gdbg->v7.en_map);
+ if (ver->fcxgpiodbg == 7 || ver->fcxgpiodbg == 8) {
+ en_map_raw = le32_to_cpu(gdbg->v7.en_map);
gpio_map = gdbg->v7.gpio_map;
} else {
- en_map = le32_to_cpu(gdbg->v1.en_map);
+ en_map_raw = le32_to_cpu(gdbg->v1.en_map);
gpio_map = gdbg->v1.gpio_map;
}
+ en_map = _convert_gpio_enmap_from_ver(rtwdev, en_map_raw);
if (!en_map)
goto out;
- p += scnprintf(p, end - p, " %-15s : enable_map:0x%08x",
+ p += scnprintf(p, end - p, "\n\r %-15s : enable_map:0x%08x",
"[gpio_dbg]", en_map);
- for (i = 0; i < BTC_DBG_MAX1; i++) {
+ for (i = 0; i < BTC_DBG_NUM; i++) {
if (!(en_map & BIT(i)))
continue;
+
+ sig = ver->fcxgpiodbg >= 8 ? i : _get_gpiosig_for_ver(rtwdev, i);
+ if (sig >= BTC_DBG_NUM)
+ continue;
+
p += scnprintf(p, end - p, ", %s->GPIO%d", id_to_gdbg(i),
- gpio_map[i]);
+ gpio_map[sig]);
}
- p += scnprintf(p, end - p, "\n");
out:
return p - buf;
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index 355784941edd..3e9e1510c44f 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -315,41 +315,6 @@ enum btc_mlo_rf_combin {
BTC_MLO_RF_2_PLUS_2 = 3,
};
-enum btc_wl_gpio_debug {
- BTC_DBG_GNT_BT = 0,
- BTC_DBG_GNT_WL = 1,
- BTC_DBG_BCN_EARLY = 2,
- BTC_DBG_WL_NULL0 = 3,
- BTC_DBG_WL_NULL1 = 4,
- BTC_DBG_WL_RXISR = 5,
- BTC_DBG_TDMA_ENTRY = 6,
- BTC_DBG_A2DP_EMPTY = 7,
- BTC_DBG_BT_RETRY = 8,
- BTC_DBG_BT_RELINK = 9,
- BTC_DBG_SLOT_WL = 10,
- BTC_DBG_SLOT_BT = 11,
- BTC_DBG_WL_ERR = 12,
- BTC_DBG_WL_OK = 13,
- BTC_DBG_SLOT_B2W = 14,
- BTC_DBG_SLOT_W1 = 15,
- BTC_DBG_SLOT_W2 = 16,
- BTC_DBG_SLOT_W2B = 17,
- BTC_DBG_SLOT_B1 = 18,
- BTC_DBG_SLOT_B2 = 19,
- BTC_DBG_SLOT_B3 = 20,
- BTC_DBG_SLOT_B4 = 21,
- BTC_DBG_SLOT_LK = 22,
- BTC_DBG_SLOT_E2G = 23,
- BTC_DBG_SLOT_E5G = 24,
- BTC_DBG_SLOT_EBT = 25,
- BTC_DBG_SLOT_WLK = 26,
- BTC_DBG_SLOT_B1FDD = 27,
- BTC_DBG_BT_CHANGE = 28,
- BTC_DBG_WL_CCA = 29,
- BTC_DBG_BT_LEAUDIO = 30,
- BTC_DBG_USER_DEF = 31,
-};
-
void rtw89_btc_init(struct rtw89_dev *rtwdev);
void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev);
void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 0ec63f9510bd..ba3a9b0d4aa2 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3074,14 +3074,55 @@ enum rtw89_btc_afh_map_type { /*AFH MAP TYPE */
RPT_BT_AFH_SEQ_LE = 0x20
};
-#define BTC_DBG_MAX1 32
+enum btc_wl_gpio_debug {
+ BTC_DBG_GNT_BT = 0,
+ BTC_DBG_GNT_WL = 1,
+ BTC_DBG_GNT_BT1 = 2,
+ BTC_DBG_GNT_WL1 = 3,
+ /* The following signals should 0-1 tiggle by each function-call */
+ BTC_DBG_BCN_EARLY = 4,
+ BTC_DBG_WL_NULL0 = 5,
+ BTC_DBG_WL_NULL1 = 6,
+ BTC_DBG_WL_RXISR = 7,
+ BTC_DBG_TDMA_ENTRY = 8,
+ BTC_DBG_A2DP_EMPTY = 9,
+ BTC_DBG_BT_RETRY = 10,
+ /* The following signals should 0-1 tiggle by state L/H */
+ BTC_DBG_BT_RELINK = 11,
+ BTC_DBG_SLOT_WL = 12,
+ BTC_DBG_SLOT_BT = 13,
+ /* The following signals should 0-1 tiggle by external*/
+ BTC_DBG_WL_ERR = 14,
+ BTC_DBG_WL_OK = 15,
+ /* The following signals appear only 1-active at same time*/
+ BTC_DBG_SLOT_B2W = 16,
+ BTC_DBG_SLOT_W1 = 17,
+ BTC_DBG_SLOT_W2 = 18,
+ BTC_DBG_SLOT_W2B = 19,
+ BTC_DBG_SLOT_B1 = 20,
+ BTC_DBG_SLOT_B2 = 21,
+ BTC_DBG_SLOT_B3 = 22,
+ BTC_DBG_SLOT_B4 = 23,
+ BTC_DBG_SLOT_LK = 24,
+ BTC_DBG_SLOT_E2G = 25,
+ BTC_DBG_SLOT_E5G = 26,
+ BTC_DBG_SLOT_EBT = 27,
+ BTC_DBG_SLOT_WLK = 28,
+ BTC_DBG_SLOT_B1FDD = 29,
+ BTC_DBG_BT_CHANGE = 30,
+ /* The following signals should 0-1 tiggle by external*/
+ BTC_DBG_WL_CCA = 31,
+
+ BTC_DBG_NUM,
+};
+
struct rtw89_btc_fbtc_gpio_dbg_v1 {
u8 fver; /* btc_ver::fcxgpiodbg */
u8 rsvd;
__le16 rsvd2;
__le32 en_map; /* which debug signal (see btc_wl_gpio_debug) is enable */
__le32 pre_state; /* the debug signal is 1 or 0 */
- u8 gpio_map[BTC_DBG_MAX1]; /*the debug signals to GPIO-Position */
+ u8 gpio_map[BTC_DBG_NUM]; /*the debug signals to GPIO-Position */
} __packed;
struct rtw89_btc_fbtc_gpio_dbg_v7 {
@@ -3090,7 +3131,7 @@ struct rtw89_btc_fbtc_gpio_dbg_v7 {
u8 rsvd1;
u8 rsvd2;
- u8 gpio_map[BTC_DBG_MAX1];
+ u8 gpio_map[BTC_DBG_NUM];
__le32 en_map;
__le32 pre_state;
@@ -3101,6 +3142,120 @@ union rtw89_btc_fbtc_gpio_dbg {
struct rtw89_btc_fbtc_gpio_dbg_v7 v7;
};
+/*
+ * SET_GPIO_CTRL payload (max len = 7 bytes)
+ *
+ * type = CXDGPIO_EN_MAP
+ * data.val[31:0] = debug signal enable map
+ *
+ * type = CXDGPIO_MUX_MAP
+ * data.mux.sig = debug signal id
+ * data.mux.gpio = GPIO id
+ *
+ * type = CXDGPIO_EXT_HPTA / CXDGPIO_EXT_HMBX / CXDGPIO_EXT_SWOUT
+ * data.map.map_low = GPIO 7~0 map
+ * data.map.map_high = GPIO 15~8 map
+ *
+ * type = CXDGPIO_EXT_SWIN
+ * data.swin.in_map_low = GPIO 7~0 input-en-map
+ * data.swin.in_map_high = GPIO 15~8 input-en-map
+ * data.swin.int_map_low = GPIO 7~0 interrupt source map
+ * data.swin.int_map_high = GPIO 15~8 interrupt source map
+ */
+#define CXDGPIO_SET_L4 4
+#define CXDGPIO_SET_L2 2
+struct rtw89_fbtc_h2c_set_gpio_en_map {
+ u8 type; /* gpio_type */
+ u8 fver; /* FCX_VER_GPIODBG */
+ u8 dlen;
+ u32 en_map;
+};
+
+struct rtw89_fbtc_h2c_set_gpio_mux {
+ u8 type; /* gpio_type */
+ u8 fver; /* FCX_VER_GPIODBG */
+ u8 dlen;
+ u8 sig;
+ u8 gpio;
+};
+
+struct rtw89_fbtc_h2c_set_gpio_ext_pta {
+ u8 type; /* gpio_type */
+ u8 fver; /* FCX_VER_GPIODBG */
+ u8 dlen;
+ u8 map_low;
+ u8 map_high;
+};
+
+struct rtw89_fbtc_h2c_set_gpio_ext_mb {
+ u8 type; /* gpio_type */
+ u8 fver; /* FCX_VER_GPIODBG */
+ u8 dlen;
+ u8 map_low;
+ u8 map_high;
+};
+
+struct rtw89_fbtc_h2c_set_gpio_ext_swout {
+ u8 type; /* gpio_type */
+ u8 fver; /* FCX_VER_GPIODBG */
+ u8 dlen;
+ u8 map_low;
+ u8 map_high;
+};
+
+struct rtw89_fbtc_h2c_set_gpio_ext_swin {
+ u8 type; /* gpio_type */
+ u8 fver; /* FCX_VER_GPIODBG */
+ u8 dlen;
+ u8 in_map_low;
+ u8 in_map_high;
+ u8 int_map_low;
+ u8 int_map_high;
+};
+
+struct rtw89_fbtc_h2c_set_gpio_2b {
+ u8 type; /* gpio_type */
+ u8 fver; /* FCX_VER_GPIODBG */
+ u8 dlen;
+ u8 data[CXDGPIO_SET_L2];
+} __packed;
+
+struct rtw89_fbtc_h2c_set_gpio_4b {
+ u8 type; /* gpio_type */
+ u8 fver; /* FCX_VER_GPIODBG */
+ u8 dlen;
+ u8 data[CXDGPIO_SET_L4];
+} __packed;
+
+union rtw89_fbtc_h2c_set_gpio_en_map_u {
+ struct rtw89_fbtc_h2c_set_gpio_4b fmt;
+ struct rtw89_fbtc_h2c_set_gpio_en_map data;
+};
+
+union rtw89_fbtc_h2c_set_gpio_mux_u {
+ struct rtw89_fbtc_h2c_set_gpio_2b fmt;
+ struct rtw89_fbtc_h2c_set_gpio_mux data;
+};
+
+union rtw89_fbtc_h2c_set_gpio_ext_pta_u {
+ struct rtw89_fbtc_h2c_set_gpio_2b fmt;
+ struct rtw89_fbtc_h2c_set_gpio_ext_pta data;
+};
+
+union rtw89_fbtc_h2c_set_gpio_ext_swin_u {
+ struct rtw89_fbtc_h2c_set_gpio_4b fmt;
+ struct rtw89_fbtc_h2c_set_gpio_ext_swin data;
+};
+
+struct rtw89_fbtc_h2c_set_gpio {
+ union rtw89_fbtc_h2c_set_gpio_en_map_u en_map;
+ union rtw89_fbtc_h2c_set_gpio_mux_u mux;
+ union rtw89_fbtc_h2c_set_gpio_ext_pta_u ext_pta;
+ union rtw89_fbtc_h2c_set_gpio_ext_pta_u ext_mb;
+ union rtw89_fbtc_h2c_set_gpio_ext_pta_u ext_swout;
+ union rtw89_fbtc_h2c_set_gpio_ext_swin_u ext_swin;
+};
+
struct rtw89_btc_fbtc_mreg_val_v1 {
u8 fver; /* btc_ver::fcxmreg */
u8 reg_num;
@@ -4178,6 +4333,7 @@ struct rtw89_btc {
struct rtw89_btc_module mdinfo;
struct rtw89_btc_btf_fwinfo fwinfo;
struct rtw89_btc_dbg dbg;
+ struct rtw89_fbtc_h2c_set_gpio gpio;
struct wiphy_work eapol_notify_work;
struct wiphy_work arp_notify_work;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 538df0fb42cc..6147960521ee 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2391,6 +2391,16 @@ enum rtw89_btc_cxdrvinfo {
CXDRVINFO_MAX,
};
+enum rtw89_fbtc_gpio_type {
+ CXDGPIO_EN_MAP = 0x0,
+ CXDGPIO_MUX_MAP = 0x1,
+ CXDGPIO_EXT_HPTA = 0x2,
+ CXDGPIO_EXT_HMBX = 0x3,
+ CXDGPIO_EXT_SWOUT = 0x4,
+ CXDGPIO_EXT_SWIN = 0x5,
+ CXDGPIO_MAX,
+};
+
enum rtw89_scan_mode {
RTW89_SCAN_IMMEDIATE,
RTW89_SCAN_DELAY,
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 06/14] wifi: rtw89: coex: Decrease Wi-Fi special packet protect time
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
While Wi-Fi is doing special packet handshake, or going into some
transient state, BT-Coexistence will held timer to fix control logic
to protect the segment. Set the protection duration to 1 second,
it is enough to cover the situation.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index 41a68ab21d80..355784941edd 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -69,7 +69,7 @@ enum btc_wl_rfk_type {
#define NM_EXEC false
#define FC_EXEC true
-#define RTW89_COEX_ACT1_WORK_PERIOD round_jiffies_relative(HZ * 4)
+#define RTW89_COEX_ACT1_WORK_PERIOD round_jiffies_relative(HZ)
#define RTW89_COEX_BT_DEVINFO_WORK_PERIOD round_jiffies_relative(HZ * 16)
#define RTW89_COEX_RFK_CHK_WORK_PERIOD msecs_to_jiffies(300)
#define BTC_RFK_PATH_MAP GENMASK(3, 0)
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 05/14] wifi: rtw89: coex: Separate _ntfy_role_info into two function
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
To make logic more clearly, separate _ntfy_role_info into two function by
data collecting and using.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 109 ++++++++++++++++------
1 file changed, 80 insertions(+), 29 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 9da3b23b2d14..ae458917ecf7 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -7233,6 +7233,7 @@ static void _update_wl_non_mlo_info(struct rtw89_dev *rtwdev)
mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, cnt, notv10);
mode_v0 = wl_rinfo->link_mode_v0;
} else if (!b2g && b5g && notv10) {
+ mode = _get_role_link_mode(wl_rinfo, cid_role[0], notv10);
mode_v0 = BTC_WLINK_V0_5G;
} else if (b2g && b5g) {
mode = BTC_WLINK_DB_MCC;
@@ -7247,6 +7248,7 @@ static void _update_wl_non_mlo_info(struct rtw89_dev *rtwdev)
}
} else {
mode = _get_role_link_mode(wl_rinfo, cid_role[0], notv10);
+ mode_v0 = wl_rinfo->link_mode_v0;
}
wl_rinfo->link_mode = mode;
@@ -8667,6 +8669,78 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
_run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO);
}
+static void _ntfy_role_info(struct rtw89_dev *rtwdev, u8 rid,
+ struct rtw89_btc_wl_link_info *info,
+ enum btc_role_state reason)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_wl_link_info *wlinfo = NULL;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ u8 rlink_id = info->phy; /* 1 role_id has 2 rlink_id(by HW_Band0/1) */
+ bool refresh_role = false;
+
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(), role_id=%d, reason=%d\n",
+ __func__, rid, reason);
+
+ if (rid >= ver->max_role_num || rlink_id >= RTW89_PHY_NUM)
+ return;
+
+ btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++;
+
+ wlinfo = &wl->rlink_info[rid][rlink_id];
+ memcpy(wlinfo, info, sizeof(struct rtw89_btc_wl_link_info));
+
+ switch (reason) {
+ case BTC_ROLE_START:
+ wlinfo->active = true;
+ return;
+ case BTC_ROLE_STOP:
+ wlinfo->active = false;
+ return;
+ case BTC_ROLE_MSTS_STA_CONN_START:
+ wl->status.map.transacting = 1;
+ wiphy_delayed_work_cancel(rtwdev->hw->wiphy,
+ &rtwdev->coex_act1_work);
+ wiphy_delayed_work_queue(rtwdev->hw->wiphy,
+ &rtwdev->coex_act1_work,
+ RTW89_COEX_ACT1_WORK_PERIOD);
+ break;
+ case BTC_ROLE_MSTS_STA_CONN_END:
+ wl->status.map.transacting = 0;
+ refresh_role = true;
+ break;
+ case BTC_ROLE_MSTS_STA_DIS_CONN:
+ wl->status.map.transacting = 1;
+ refresh_role = false;
+ wiphy_delayed_work_cancel(rtwdev->hw->wiphy,
+ &rtwdev->coex_act1_work);
+ wiphy_delayed_work_queue(rtwdev->hw->wiphy,
+ &rtwdev->coex_act1_work,
+ RTW89_COEX_ACT1_WORK_PERIOD);
+ break;
+ case BTC_ROLE_MSTS_AP_START:
+ case BTC_ROLE_MSTS_AP_STOP:
+ refresh_role = true;
+ break;
+ case BTC_ROLE_STATE_UNKNOWN:
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(), role_id=%d, Unknown reason return!\n",
+ __func__, rid);
+ return;
+ default:
+ return;
+ }
+
+ if (refresh_role) {
+ _update_wl_info(rtwdev, wlinfo);
+ _fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
+ }
+
+ _run_coex(rtwdev, BTC_RSN_NTFY_ROLE_INFO);
+}
+
void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct rtw89_sta_link *rtwsta_link,
@@ -8679,20 +8753,20 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
struct ieee80211_p2p_noa_desc *noa_desc;
struct ieee80211_bss_conf *bss_conf;
struct ieee80211_link_sta *link_sta;
- struct rtw89_btc *btc = &rtwdev->btc;
- struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_wl_link_info r = {0};
- u8 i, mode = 0;
+ u8 i, role_id, mode = 0;
rcu_read_lock();
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
+ role_id = rtwvif_link->port;
+
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state);
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], role is STA=%d\n",
vif->type == NL80211_IFTYPE_STATION);
- rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif_link->port);
+ rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", role_id);
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], band=%d ch=%d bw=%d\n",
chan->band_type, chan->channel, chan->band_width);
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], associated=%d\n",
@@ -8747,7 +8821,7 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
r.mode = mode;
r.role = rtwvif_link->wifi_role;
r.phy = rtwvif_link->phy_idx;
- r.pid = rtwvif_link->port;
+ r.pid = role_id;
r.active = true;
if (vif->active_links) {
if (rtwvif_link->link_id < 16)
@@ -8780,30 +8854,7 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
rcu_read_unlock();
- btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++;
-
- if (r.role == RTW89_WIFI_ROLE_STATION &&
- r.connected == MLME_NO_LINK)
- btc->dm.leak_ap = 0;
-
- if (state == BTC_ROLE_MSTS_STA_CONN_START) {
- wl->status.map.transacting = 1;
- wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->coex_act1_work);
- wiphy_delayed_work_queue(rtwdev->hw->wiphy,
- &rtwdev->coex_act1_work,
- RTW89_COEX_ACT1_WORK_PERIOD);
- } else {
- wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->coex_act1_work);
- wl->status.map.transacting = 0;
- }
-
- if (state == BTC_ROLE_MSTS_STA_DIS_CONN ||
- state == BTC_ROLE_MSTS_STA_CONN_END)
- wl->status.map._4way = false;
-
- _update_wl_info(rtwdev, &r);
-
- _run_coex(rtwdev, BTC_RSN_NTFY_ROLE_INFO);
+ _ntfy_role_info(rtwdev, role_id, &r, state);
}
void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_state)
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 04/14] wifi: rtw89: coex: Rearrange _ntfy_role_info info
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
rtw89_btc_wl_link_info is duplicated declaring in the function, remove one
of them. We need MAC Address only when Wi-Fi role is station, included the
copy operation into if statement.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 79 +++++++++++++++--------
1 file changed, 53 insertions(+), 26 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index d873b9482e49..9da3b23b2d14 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -8675,13 +8675,14 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
rtwvif_link->chanctx_idx);
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct ieee80211_p2p_noa_attr *noa_attr;
+ struct ieee80211_p2p_noa_desc *noa_desc;
struct ieee80211_bss_conf *bss_conf;
struct ieee80211_link_sta *link_sta;
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_wl_link_info r = {0};
- struct rtw89_btc_wl_link_info *wlinfo = NULL;
- u8 mode = 0;
+ u8 i, mode = 0;
rcu_read_lock();
@@ -8729,34 +8730,60 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], wifi_role=%d\n", rtwvif_link->wifi_role);
- wlinfo = &wl->rlink_info[rtwvif_link->port][rtwvif_link->phy_idx];
-
- wlinfo->mode = mode;
- wlinfo->role = rtwvif_link->wifi_role;
- wlinfo->phy = rtwvif_link->phy_idx;
- wlinfo->pid = rtwvif_link->port;
- wlinfo->active = true;
- wlinfo->connected = MLME_LINKED;
- wlinfo->bcn_period = bss_conf->beacon_int;
- wlinfo->dtim_period = bss_conf->dtim_period;
- wlinfo->band = chan->band_type;
- wlinfo->ch = chan->channel;
- wlinfo->bw = chan->band_width;
- wlinfo->chdef.band = chan->band_type;
- wlinfo->chdef.center_ch = chan->channel;
- wlinfo->chdef.bw = chan->band_width;
- wlinfo->chdef.chan = chan->primary_channel;
- ether_addr_copy(r.mac_addr, rtwvif_link->mac_addr);
+ if (vif->type == NL80211_IFTYPE_P2P_GO ||
+ vif->type == NL80211_IFTYPE_P2P_CLIENT) {
+ noa_attr = &bss_conf->p2p_noa_attr;
- rcu_read_unlock();
+ for (i = 0; i < RTW89_P2P_MAX_NOA_NUM; i++) {
+ noa_desc = &noa_attr->desc[i];
+ if (noa_desc->count != 0) {
+ r.noa = 1;
+ r.noa_duration = le32_to_cpu(noa_desc->duration);
+ break;
+ }
+ }
+ }
+
+ r.mode = mode;
+ r.role = rtwvif_link->wifi_role;
+ r.phy = rtwvif_link->phy_idx;
+ r.pid = rtwvif_link->port;
+ r.active = true;
+ if (vif->active_links) {
+ if (rtwvif_link->link_id < 16)
+ r.active = !!(vif->active_links & BIT(rtwvif_link->link_id));
+ }
+ r.bcn_period = bss_conf->beacon_int;
+ r.dtim_period = bss_conf->dtim_period;
+ r.band = chan->band_type;
+ r.ch = chan->channel;
+ r.bw = chan->band_width;
+ r.chdef.band = chan->band_type;
+ r.chdef.center_ch = chan->channel;
+ r.chdef.bw = chan->band_width;
+ r.chdef.chan = chan->primary_channel;
+
+ if (rtwsta_link && vif->type == NL80211_IFTYPE_STATION) {
+ r.mac_id = rtwsta_link->mac_id;
+ ether_addr_copy(r.mac_addr, rtwvif_link->mac_addr);
+ }
+
+ switch (state) {
+ case BTC_ROLE_MSTS_STA_CONN_END:
+ case BTC_ROLE_MSTS_AP_START:
+ r.connected = MLME_LINKED;
+ break;
+ default:
+ r.connected = MLME_NO_LINK;
+ break;
+ }
- if (rtwsta_link && vif->type == NL80211_IFTYPE_STATION)
- wlinfo->mac_id = rtwsta_link->mac_id;
+ rcu_read_unlock();
btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++;
- if (wlinfo->role == RTW89_WIFI_ROLE_STATION &&
- wlinfo->connected == MLME_NO_LINK)
+ if (r.role == RTW89_WIFI_ROLE_STATION &&
+ r.connected == MLME_NO_LINK)
btc->dm.leak_ap = 0;
if (state == BTC_ROLE_MSTS_STA_CONN_START) {
@@ -8774,7 +8801,7 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
state == BTC_ROLE_MSTS_STA_CONN_END)
wl->status.map._4way = false;
- _update_wl_info(rtwdev, wlinfo);
+ _update_wl_info(rtwdev, &r);
_run_coex(rtwdev, BTC_RSN_NTFY_ROLE_INFO);
}
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 03/14] wifi: rtw89: coex: Add firmware 0.35.111.X support for RTL8922A/D
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
Add BTC version table entries for RTL8922A and RTL8922D. The new firmware
need driver provide more chip initial related parameters.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 0c5599a23b4a..d873b9482e49 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -133,6 +133,15 @@ static const u32 cxtbl[] = {
static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
/* firmware version must be in decreasing order for each chip */
+ {RTL8922D, RTW89_FW_VER_CODE(0, 35, 111, 0),
+ .fcxbtcrpt = 11, .fcxtdma = 8, .fcxslots = 7, .fcxcysta = 8,
+ .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 8,
+ .fcxbtver = 8, .fcxbtscan = 8, .fcxbtafh = 8, .fcxbtdevinfo = 8,
+ .fwlrole = 10, .frptmap = 5, .fcxctrl = 9, .fcxinit = 11,
+ .fwevntrptl = 1, .fwc2hfunc = 4, .drvinfo_ver = 3, .info_buf = 1800,
+ .max_role_num = 6, .fcxosi = 6, .fcxmlo = 2, .bt_desired = 8,
+ .fcxtrx = 9,
+ },
{RTL8922D, RTW89_FW_VER_CODE(0, 35, 94, 0),
.fcxbtcrpt = 11, .fcxtdma = 8, .fcxslots = 7, .fcxcysta = 8,
.fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 8,
@@ -169,6 +178,15 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
.max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 8,
.fcxtrx = 0,
},
+ {RTL8922A, RTW89_FW_VER_CODE(0, 35, 111, 0),
+ .fcxbtcrpt = 11, .fcxtdma = 8, .fcxslots = 7, .fcxcysta = 8,
+ .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 8,
+ .fcxbtver = 8, .fcxbtscan = 8, .fcxbtafh = 8, .fcxbtdevinfo = 8,
+ .fwlrole = 10, .frptmap = 5, .fcxctrl = 9, .fcxinit = 11,
+ .fwevntrptl = 1, .fwc2hfunc = 4, .drvinfo_ver = 3, .info_buf = 1800,
+ .max_role_num = 6, .fcxosi = 6, .fcxmlo = 2, .bt_desired = 8,
+ .fcxtrx = 9,
+ },
{RTL8922A, RTW89_FW_VER_CODE(0, 35, 71, 0),
.fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7,
.fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7,
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 02/14] wifi: rtw89: coex: Add Wi-Fi MLO info version 2 H2C command
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
The info included MLO status, hardware status, firmware will set
corresponding register control to do coexistence (PTA slot priority,
RF switch etc.)
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 3 ++
drivers/net/wireless/realtek/rtw89/core.h | 19 ++++++++
drivers/net/wireless/realtek/rtw89/fw.c | 58 +++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/fw.h | 6 +++
4 files changed, 86 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index f94866e1f43a..0c5599a23b4a 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -3274,6 +3274,9 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
else
return;
+ if (ver->fcxmlo == 2)
+ rtw89_fw_h2c_cxdrv_mlo_v2(rtwdev, index);
+
break;
case CXDRVINFO_OSI:
if (!ver->fcxosi || ver->drvinfo_ver == 103)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 7147e186b4a5..0ec63f9510bd 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1783,6 +1783,25 @@ struct rtw89_btc_wl_dbcc_info {
u8 role[RTW89_PHY_NUM]; /* role in each phy */
};
+struct rtw89_btc_wl_mlo_info_v2 {
+ u8 wmode[RTW89_PHY_NUM];
+ u8 ch_type[RTW89_PHY_NUM];
+ u8 hwb_rf_band[RTW89_PHY_NUM];
+ u8 path_rf_band[RTW89_PHY_NUM];
+
+ u8 wtype;
+ u8 mrcx_mode;
+ u8 mrcx_act_hwb_map;
+ u8 mrcx_bt_slot_rsp;
+
+ u8 rf_combination;
+ u8 mlo_en;
+ u8 mlo_adie;
+ u8 dual_hw_band_en;
+
+ __le32 link_status;
+} __packed;
+
struct rtw89_btc_wl_mlo_info {
u8 wmode[RTW89_PHY_NUM]; /* enum phl_mr_wmode */
u8 ch_type[RTW89_PHY_NUM]; /* enum phl_mr_ch_type */
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index a3a04697e2e6..5ab80bda3ae5 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -6616,6 +6616,64 @@ int rtw89_fw_h2c_cxdrv_role_v10(struct rtw89_dev *rtwdev, u8 type)
return ret;
}
+int rtw89_fw_h2c_cxdrv_mlo_v2(struct rtw89_dev *rtwdev, u8 type)
+{
+ struct rtw89_btc_wl_mlo_info *mlo = &rtwdev->btc.cx.wl.mlo_info;
+ struct rtw89_h2c_cxmlo_v2 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_mlo_v2\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_cxmlo_v2 *)skb->data;
+
+ h2c->hdr.type = type;
+ h2c->hdr.ver = 2;
+ h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
+
+ memcpy(h2c->mlo.wmode, mlo->wmode,
+ sizeof(h2c->mlo.wmode));
+ memcpy(h2c->mlo.ch_type, mlo->ch_type,
+ sizeof(h2c->mlo.ch_type));
+ memcpy(h2c->mlo.hwb_rf_band, mlo->hwb_rf_band,
+ sizeof(h2c->mlo.hwb_rf_band));
+ memcpy(h2c->mlo.path_rf_band, mlo->path_rf_band,
+ sizeof(h2c->mlo.path_rf_band));
+
+ h2c->mlo.wtype = mlo->wtype;
+ h2c->mlo.mrcx_mode = mlo->mrcx_mode;
+ h2c->mlo.mrcx_act_hwb_map = mlo->mrcx_act_hwb_map;
+ h2c->mlo.mrcx_bt_slot_rsp = mlo->mrcx_bt_slot_rsp;
+
+ h2c->mlo.rf_combination = mlo->rf_combination;
+ h2c->mlo.mlo_en = mlo->mlo_en;
+ h2c->mlo.mlo_adie = mlo->mlo_adie;
+ h2c->mlo.dual_hw_band_en = mlo->dual_hw_band_en;
+ h2c->mlo.link_status = cpu_to_le32(mlo->link_status);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, BTFC_SET,
+ SET_DRV_INFO, 0, 0,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
int rtw89_fw_h2c_cxdrv_osi_info(struct rtw89_dev *rtwdev, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index c0a00b721060..538df0fb42cc 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2453,6 +2453,11 @@ struct rtw89_h2c_cxrole_v10 {
struct rtw89_btc_wl_role_info_v10 r;
} __packed;
+struct rtw89_h2c_cxmlo_v2 {
+ struct rtw89_h2c_cxhdr_v7 hdr;
+ struct rtw89_btc_wl_mlo_info_v2 mlo;
+} __packed;
+
struct rtw89_h2c_cxosi {
struct rtw89_h2c_cxhdr_v7 hdr;
struct rtw89_btc_fbtc_outsrc_set_info_v1 osi;
@@ -5462,6 +5467,7 @@ int rtw89_fw_h2c_cxdrv_role_v7(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_role_v8(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_role_v10(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_init_v11(struct rtw89_dev *rtwdev, u8 type);
+int rtw89_fw_h2c_cxdrv_mlo_v2(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_osi_info(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_osi_info_v6(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev, u8 type);
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 01/14] wifi: rtw89: coex: Add chip initial info version 11 for RTL8922A/D
From: Ping-Ke Shih @ 2026-07-24 13:56 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260724135640.3195044-1-pkshih@realtek.com>
From: Ching-Te Ku <ku920601@realtek.com>
The version 11 init info add current RF path control information.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 2 +
drivers/net/wireless/realtek/rtw89/coex.h | 19 ++++
drivers/net/wireless/realtek/rtw89/core.h | 47 ++++++++++
drivers/net/wireless/realtek/rtw89/fw.c | 75 ++++++++++++++++
drivers/net/wireless/realtek/rtw89/fw.h | 6 ++
drivers/net/wireless/realtek/rtw89/rtw8922a.c | 88 ++++++++++++++++---
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 40 ++++++---
7 files changed, 251 insertions(+), 26 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 6a1888d8c476..f94866e1f43a 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -3199,6 +3199,8 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
rtw89_fw_h2c_cxdrv_init_v7(rtwdev, index);
else if (ver->fcxinit == 10)
rtw89_fw_h2c_cxdrv_init_v10(rtwdev, index);
+ else if (ver->fcxinit == 11)
+ rtw89_fw_h2c_cxdrv_init_v11(rtwdev, index);
else
rtw89_fw_h2c_cxdrv_init(rtwdev, index);
break;
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index 3238c44429a9..41a68ab21d80 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -127,6 +127,11 @@ enum btc_fddt_en {
((__rssi == BTC_RSSI_ST_LOW || \
__rssi == BTC_RSSI_ST_HIGH) ? 1 : 0); })
+/* Antenna TX/RX path position masks and helpers */
+#define BTC_ANT_TX_MASK 0xf0
+#define BTC_ANT_RX_MASK 0x0f
+#define BTC_ANT_SHIFT 4
+
enum btc_ant {
BTC_ANT_SHARED = 0,
BTC_ANT_DEDICATED,
@@ -473,4 +478,18 @@ void btc_dw2b(u8 *buf, size_t idx, u32 val)
buf[idx + 3] = u32_get_bits(val, MASKBYTE3);
}
+static inline
+u8 _btc_get_rf_path_from_ant_num(struct rtw89_btc *btc, u8 antnum)
+{
+ switch (antnum) {
+ default:
+ case 1:
+ return btc->mdinfo.ant.single_pos;
+ case 2:
+ return RF_PATH_AB;
+ case 3:
+ return RF_PATH_ABC;
+ }
+}
+
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 7573f1965c98..7147e186b4a5 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1537,6 +1537,21 @@ struct rtw89_btc_ant_info_v10 {
u8 ant_xmap[2][4];
} __packed;
+struct rtw89_btc_ant_info_v11 {
+ u8 type;
+ u8 num;
+ u8 isolation;
+ u8 single_pos;
+
+ u8 stream_cnt;
+ u8 path_pos; /* WL path position: Tx[7:4], Rx[3:0] */
+ u8 btg_pos;
+ u8 btg1_pos;
+ u8 func[5];
+ u8 ant_xmap[2][4];
+ u8 rsvd0[3];
+} __packed;
+
struct rtw89_btc_ant_info {
u8 type; /* shared, dedicated(non-shared) */
u8 num; /* antenna count */
@@ -1546,6 +1561,7 @@ struct rtw89_btc_ant_info {
u8 stream_cnt; /* spatial_stream count: Tx[7:4], Rx[3:0] */
u8 btg_pos; /* BT0 btg-circuit at 0:WL-S0/1:WL-S1 */
u8 btg1_pos; /* BT1 btg-circuit at 0:WL-S0/1:WL-S1 */
+ u8 path_pos; /* WL path position: Tx[7:4], Rx[3:0] */
u8 func[5]; /* function at 1~5 Ant refer to enum btc_bt_func_type */
u8 ant_xmap[2][4];
@@ -2387,10 +2403,25 @@ struct rtw89_btc_module_v10 {
struct rtw89_btc_ant_info_v10 ant;
} __packed;
+struct rtw89_btc_module_v11 {
+ u8 rfe_type;
+ u8 wa_type;
+ u8 kt_ver;
+ u8 kt_ver_adie;
+
+ u8 bt0_pos;
+ u8 bt0_sw_type;
+ u8 bt1_pos;
+ u8 bt1_sw_type;
+
+ struct rtw89_btc_ant_info_v11 ant;
+} __packed;
+
union rtw89_btc_module_info {
struct rtw89_btc_module_v0 md_v0;
struct rtw89_btc_module_v7 md_v7;
struct rtw89_btc_module_v10 md_v10;
+ struct rtw89_btc_module_v11 md_v11;
};
struct rtw89_btc_module {
@@ -2473,11 +2504,26 @@ struct rtw89_btc_init_info_v10 {
struct rtw89_btc_module_v10 module;
} __packed;
+struct rtw89_btc_init_info_v11 {
+ u8 endian_type; /* 0: little-endian, 1:big-endian */
+ u8 init_mode; /* refer to enum BTC_MODE_xxx */
+ u8 wl_init_ok;
+ u8 bt0_function;
+
+ u8 bt1_function;
+ u8 bt2_function;
+ u8 pta_mode;
+ u8 pta_direction;
+
+ struct rtw89_btc_module_v11 module;
+};
+
union rtw89_btc_init_info_u {
struct rtw89_btc_init_info_v0 init_v0;
struct rtw89_btc_init_info_v7 init_v7;
struct rtw89_btc_init_info_v10 init_v10;
struct rtw89_btc_init_info_v107 init_v107;
+ struct rtw89_btc_init_info_v11 init_v11;
};
struct rtw89_btc_init_info {
@@ -2547,6 +2593,7 @@ enum rtw89_btc_bt_func_type {
#define RTW89_BTC_BT_DEF_BR_TX_PWR 4
#define RTW89_BTC_BT_DEF_LE_TX_PWR 4
#define RTW89_BTC_DEFAULT_ANISO 10
+#define RTW89_BTC_BT_DEF_LE_TX_PWR_1 10
struct rtw89_btc_bt_scan_info_v1 {
__le16 win;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 3b8c144e0e98..a3a04697e2e6 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -5973,6 +5973,81 @@ int rtw89_fw_h2c_cxdrv_init_v10(struct rtw89_dev *rtwdev, u8 type)
return ret;
}
+int rtw89_fw_h2c_cxdrv_init_v11(struct rtw89_dev *rtwdev, u8 type)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_btc_init_info *init = &dm->init_info;
+ struct rtw89_h2c_cxinit_v11 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_init_v11\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_cxinit_v11 *)skb->data;
+
+ h2c->hdr.type = type;
+ h2c->hdr.ver = 11;
+ h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
+
+ h2c->init.endian_type = init->endian_type;
+ h2c->init.init_mode = init->init_mode;
+ h2c->init.wl_init_ok = init->wl_init_ok;
+ h2c->init.bt0_function = init->bt0_function;
+
+ h2c->init.bt1_function = init->bt1_function;
+ h2c->init.bt2_function = init->bt2_function;
+ h2c->init.pta_mode = init->pta_mode;
+ h2c->init.pta_direction = init->pta_direction;
+
+ h2c->init.module.rfe_type = init->module.rfe_type;
+ h2c->init.module.wa_type = init->module.wa_type;
+ h2c->init.module.kt_ver = init->module.kt_ver;
+ h2c->init.module.kt_ver_adie = init->module.kt_ver_adie;
+
+ h2c->init.module.bt0_pos = init->module.bt0_pos;
+ h2c->init.module.bt0_sw_type = init->module.bt0_sw_type;
+ h2c->init.module.bt1_pos = init->module.bt1_pos;
+ h2c->init.module.bt1_sw_type = init->module.bt1_sw_type;
+
+ h2c->init.module.ant.type = init->module.ant.type;
+ h2c->init.module.ant.num = init->module.ant.num;
+ h2c->init.module.ant.isolation = init->module.ant.isolation;
+ h2c->init.module.ant.single_pos = init->module.ant.single_pos;
+
+ h2c->init.module.ant.stream_cnt = init->module.ant.stream_cnt;
+ h2c->init.module.ant.path_pos = init->module.ant.path_pos;
+ h2c->init.module.ant.btg_pos = init->module.ant.btg_pos;
+ h2c->init.module.ant.btg1_pos = init->module.ant.btg1_pos;
+ memcpy(h2c->init.module.ant.func, init->module.ant.func,
+ sizeof(init->module.ant.func));
+
+ memcpy(h2c->init.module.ant.ant_xmap, init->module.ant.ant_xmap,
+ sizeof(init->module.ant.ant_xmap));
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, BTFC_SET,
+ SET_DRV_INFO, 0, 0,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
#define PORT_DATA_OFFSET 4
#define H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN 12
#define H2C_LEN_CXDRVINFO_ROLE_SIZE(max_role_num) \
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index e86014ca249a..c0a00b721060 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2603,6 +2603,11 @@ struct rtw89_h2c_cxinit_v10 {
struct rtw89_btc_init_info_v10 init;
} __packed;
+struct rtw89_h2c_cxinit_v11 {
+ struct rtw89_h2c_cxhdr_v7 hdr;
+ struct rtw89_btc_init_info_v11 init;
+} __packed;
+
#define RTW89_H2C_CXROLE_V101_ROLE_STAT_CONNTECTED BIT(0)
#define RTW89_H2C_CXROLE_V101_ROLE_STAT_PID GENMASK(3, 1)
#define RTW89_H2C_CXROLE_V101_ROLE_STAT_PHY BIT(4)
@@ -5456,6 +5461,7 @@ int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_role_v7(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_role_v8(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_role_v10(struct rtw89_dev *rtwdev, u8 type);
+int rtw89_fw_h2c_cxdrv_init_v11(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_osi_info(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_osi_info_v6(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev, u8 type);
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
index 2586fd2df8ab..2d225e009b28 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -2721,25 +2721,33 @@ static u32 rtw8922a_chan_to_rf18_val(struct rtw89_dev *rtwdev,
static void rtw8922a_btc_set_rfe(struct rtw89_dev *rtwdev)
{
- struct rtw89_btc_module *md = &rtwdev->btc.mdinfo;
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_module *md = &btc->mdinfo;
+ u8 i, j;
+ u8 tx_path_pos, rx_path_pos;
md->rfe_type = rtwdev->efuse.rfe_type;
md->kt_ver = rtwdev->hal.cv;
- md->bt_solo = 0;
- md->bt0_sw_type = BTC_SWITCH_INTERNAL;
+ md->kt_ver_adie = rtwdev->hal.acv;
md->wa_type = 0;
- md->ant.type = BTC_ANT_SHARED;
md->ant.num = 2;
- md->ant.isolation = 10;
- md->ant.diversity = 0;
- md->ant.single_pos = RF_PATH_A;
- md->ant.btg_pos = RF_PATH_B;
+ md->ant.single_pos = BTC_RF_S0;
if (md->kt_ver <= 1)
md->wa_type |= BTC_WA_HFP_ZB;
- rtwdev->btc.cx.bt_ext.func_type = BTC_3CX_NONE;
+ btc->cx.bt0.ant_iso_to_wl = md->ant.isolation;
+ btc->cx.bt1.ant_iso_to_wl = md->ant.isolation;
+
+ md->ant.stream_cnt = 2;
+ md->ant.btg_pos = RF_PATH_B;
+ md->ant.single_pos = RF_PATH_A;
+
+ btc->cx.bt0.band_56G_support = 0;
+ btc->cx.bt1.band_56G_support = 0;
+ btc->cx.bt0.func_type = BTC_BTF_BT;
+ btc->cx.bt1.func_type = BTC_BTF_NONE;
if (md->rfe_type == 0) {
rtwdev->btc.dm.error.map.rfe_type0 = true;
@@ -2747,17 +2755,69 @@ static void rtw8922a_btc_set_rfe(struct rtw89_dev *rtwdev)
}
md->ant.num = (md->rfe_type % 2) ? 2 : 3;
-
if (md->kt_ver == 0)
md->ant.num = 2;
- if (md->ant.num == 3) {
- md->ant.type = BTC_ANT_DEDICATED;
- md->bt0_pos = BTC_BT_ALONE;
- } else {
+ memset(btc->dm.ant_xmap, 0, sizeof(btc->dm.ant_xmap));
+
+ switch (md->ant.num) {
+ case 1:
md->ant.type = BTC_ANT_SHARED;
md->bt0_pos = BTC_BT_BTG;
+ md->bt0_sw_type = BTC_SWITCH_V1_INTERNAL;
+ md->ant.btg_pos = BTC_RF_S0;
+ btc->dm.ant_xmap[BTC_RF_S0][BTC_BT_1ST] = 1;
+ md->ant.func[0] = BTC_EFMAP_BT0;
+ break;
+ case 2: /* 2-Ant */
+ default:
+ md->ant.type = BTC_ANT_SHARED;
+ md->bt0_pos = BTC_BT_BTG;
+ md->bt0_sw_type = BTC_SWITCH_V1_INTERNAL;
+ btc->dm.wl_trx_nss_en = 1;
+ btc->dm.ant_xmap[BTC_RF_S1][BTC_BT_1ST] = 1;
+ md->ant.func[1] = BTC_EFMAP_BT0;
+ break;
+ case 3: /* 3-Ant, 3 different BT-configuration */
+ /* WL-S0 + WL-S1 + BT0-S0 */
+ md->ant.type = BTC_ANT_DEDICATED;
+ md->bt0_pos = BTC_BT_ALONE;
+ md->bt0_sw_type = BTC_SWITCH_V1_NONE;
+ md->ant.func[2] = BTC_EFMAP_BT0;
+ }
+
+ tx_path_pos = _btc_get_rf_path_from_ant_num(btc, rtwdev->hal.tx_nss);
+ rx_path_pos = _btc_get_rf_path_from_ant_num(btc, rtwdev->hal.rx_nss);
+ /* Combine TX[7:4] and RX[3:0] into path_pos byte */
+ md->ant.path_pos = ((tx_path_pos << BTC_ANT_SHIFT) & BTC_ANT_TX_MASK) |
+ (rx_path_pos & BTC_ANT_RX_MASK);
+
+ switch (btc->cx.bt_ext.chip_id) {
+ default:
+ case BTC_ESOC_NONE:
+ memset(&btc->cx.bt_ext, 0, sizeof(struct rtw89_btc_extsoc_info));
+ btc->cx.bt_ext.max_tx_pwr = RTW89_BTC_BT_DEF_LE_TX_PWR_1;
+ btc->cx.bt_ext.ant_iso_to_wl = RTW89_BTC_DEFAULT_ANISO;
+ break;
+ case BTC_ESOC_8771:
+ btc->cx.bt_ext.func_type = BTC_BTF_THREAD;
+ btc->cx.bt_ext.hw_coex = BTC_EXTSOC_INTF_PTA;
+ btc->cx.bt_ext.rf_band_map = 0x1; /* 2.4G only */
+ btc->cx.bt_ext.link_weight[BTC_BT_B2G] = 10;
+ btc->cx.bt_ext.profile_map[BTC_BT_B2G] |= BTC_BT_THREAD;
+ /* use GPIO 12~15 for Ext-4-wire-PTA */
+ btc->cx.bt_ext.hpta_cfg = BIT(12) | BIT(13) | BIT(14) | BIT(15);
+ md->ant.func[2] = BTC_EFMAP_ZB;
+ break;
}
+
+ btc->dm.ant_xmap[BTC_RF_S0][BTC_BT_EXT] = 0;
+ btc->dm.ant_xmap[BTC_RF_S1][BTC_BT_EXT] = 0;
+
+ for (i = BTC_RF_S0; i <= BTC_RF_S1; i++)
+ for (j = BTC_BT_1ST; j <= BTC_BT_EXT; j++)
+ md->ant.ant_xmap[i][j] = btc->dm.ant_xmap[i][j];
+
rtwdev->btc.btg_pos = md->ant.btg_pos;
rtwdev->btc.ant_type = md->ant.type;
}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 12c96425a6ff..142e693c87bf 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -3174,7 +3174,9 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_cx *cx = &btc->cx;
u8 efuse_bt_func, efuse_ant_info, bt_sw_gpio_pos;
- u8 is_combo, is_bt_share;
+ u8 is_combo, is_bt_share, is_spdt;
+ u8 tx_path_pos, rx_path_pos;
+ u8 i, j;
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s !!\n", __func__);
@@ -3192,7 +3194,8 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
cx->bt0.ant_iso_to_wl = md->ant.isolation;
cx->bt1.ant_iso_to_wl = md->ant.isolation;
- md->ant.stream_cnt = 2;
+ md->ant.stream_cnt = (rtwdev->hal.tx_nss << BTC_ANT_SHIFT) +
+ rtwdev->hal.rx_nss;
md->ant.btg_pos = BTC_RF_S1; /* BTG0 at WL-S1 */
md->ant.btg1_pos = BTC_RF_S0; /* BTG1 at WL-S0 if Dual-BTGA */
@@ -3203,19 +3206,20 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
efuse_bt_func = rtwdev->efuse.bt_setting_2;
- switch ((efuse_bt_func & 0xe0) >> 5) { /* 0xcd[7:5] */
+ is_spdt = !!(efuse_bt_func & BIT(5));
+
+ switch ((efuse_bt_func & 0xc0) >> 6) { /* 0xcd[7:6] */
default:
case 0:
- case 1:
bt_sw_gpio_pos = 5;
break;
- case 2:
+ case 1:
bt_sw_gpio_pos = 11;
break;
- case 3:
+ case 2:
bt_sw_gpio_pos = 15;
break;
- case 4:
+ case 3:
bt_sw_gpio_pos = 20;
break;
}
@@ -3233,9 +3237,8 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
case 1: /* 1-Ant WL-S0 only & BT0 only */
md->ant.type = BTC_ANT_SHARED;
md->bt0_pos = BTC_BT_BTG;
- md->bt0_sw_type = BTC_SWITCH_INTERNAL;
+ md->bt0_sw_type = BTC_SWITCH_V1_INTERNAL;
md->ant.btg_pos = BTC_RF_S0; /* BTG0 at WL-S0 */
- md->ant.stream_cnt = 1;
md->ant.func[0] = BTC_EFMAP_BT0;
dm->ant_xmap[BTC_RF_S0][BTC_BT_1ST] = 1; /* BT0 shared with S0*/
dm->ant_xmap[BTC_RF_S1][BTC_BT_1ST] = 0; /* WL 1T1R no RF-S1 */
@@ -3265,13 +3268,13 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
if (md->ant.func[0] == BTC_EFMAP_BT1) { /* if 2nd BT exist */
dm->ant_xmap[BTC_RF_S0][BTC_BT_2ND] = 1;
- if (md->rfe_type == 12) { /* WL-S0 & BT1 by SPDT */
+ if (is_spdt) { /* WL-S0 & BT1 by SPDT */
md->bt1_pos = BTC_BT_ALONE;
/* Todo: set SPDT GPIO-ctrl */
md->bt1_sw_type = bt_sw_gpio_pos;
} else { /* WL-S0 & BT1-S1 by BTGA */
md->bt1_pos = BTC_BT_BTG;
- md->bt1_sw_type = BTC_SWITCH_INTERNAL;
+ md->bt1_sw_type = BTC_SWITCH_V1_INTERNAL;
}
}
@@ -3284,7 +3287,7 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
md->ant.func[2] = efuse_bt_func & (~BTC_EFMAP_BT0);
md->ant.type = BTC_ANT_SHARED;
md->bt0_pos = BTC_BT_BTG;
- md->bt0_sw_type = BTC_SWITCH_INTERNAL;
+ md->bt0_sw_type = BTC_SWITCH_V1_INTERNAL;
dm->ant_xmap[BTC_RF_S1][BTC_BT_1ST] = 1;
dm->wl_trx_nss_en = 1; /* 1ss MIMO-PS capability */
} else {
@@ -3324,6 +3327,12 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
break;
}
+ tx_path_pos = _btc_get_rf_path_from_ant_num(btc, rtwdev->hal.tx_nss);
+ rx_path_pos = _btc_get_rf_path_from_ant_num(btc, rtwdev->hal.rx_nss);
+ /* Combine TX[7:4] and RX[3:0] into path_pos byte */
+ md->ant.path_pos = ((tx_path_pos << BTC_ANT_SHIFT) & BTC_ANT_TX_MASK) |
+ (rx_path_pos & BTC_ANT_RX_MASK);
+
/*
* if only BT0 at BTGA: 2-Ant, 3-Ant(BT1 used dedicated-ant)
* can setup dm->wl_trx_nss_en = 1, WL MIMO-PS to 1T1R
@@ -3373,6 +3382,13 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
dm->ant_xmap[BTC_RF_S0][BTC_BT_EXT] = 0;
dm->ant_xmap[BTC_RF_S1][BTC_BT_EXT] = 0;
+
+ for (i = BTC_RF_S0; i <= BTC_RF_S1; i++)
+ for (j = BTC_BT_1ST; j <= BTC_BT_EXT; j++)
+ md->ant.ant_xmap[i][j] = dm->ant_xmap[i][j];
+
+ rtwdev->btc.btg_pos = md->ant.btg_pos;
+ rtwdev->btc.ant_type = md->ant.type;
}
static void rtw8922d_btc_init_cfg(struct rtw89_dev *rtwdev)
--
2.25.1
^ permalink raw reply related
page: next (older)
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox