* RE: [Intel-wired-lan] [PATCH net-next v2 03/13] net: introduce ndo_set_rx_mode_async and dev_rx_mode_work
From: Loktionov, Aleksandr @ 2026-03-23 12:09 UTC (permalink / raw)
To: Stanislav Fomichev, netdev@vger.kernel.org
Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, horms@kernel.org, corbet@lwn.net,
skhan@linuxfoundation.org, andrew+netdev@lunn.ch,
michael.chan@broadcom.com, pavan.chebbi@broadcom.com,
Nguyen, Anthony L, Kitszel, Przemyslaw, saeedm@nvidia.com,
tariqt@nvidia.com, mbloch@nvidia.com, alexanderduyck@fb.com,
kernel-team@meta.com, johannes@sipsolutions.net,
sd@queasysnail.net, jianbol@nvidia.com, dtatulea@nvidia.com,
mohsin.bashr@gmail.com, Keller, Jacob E, willemb@google.com,
skhawaja@google.com, bestswngs@gmail.com,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
intel-wired-lan@lists.osuosl.org, linux-rdma@vger.kernel.org,
linux-wireless@vger.kernel.org, linux-kselftest@vger.kernel.org,
leon@kernel.org
In-Reply-To: <20260318150305.123900-4-sdf@fomichev.me>
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of Stanislav Fomichev
> Sent: Wednesday, March 18, 2026 4:03 PM
> To: netdev@vger.kernel.org
> Cc: davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
> pabeni@redhat.com; horms@kernel.org; corbet@lwn.net;
> skhan@linuxfoundation.org; andrew+netdev@lunn.ch;
> michael.chan@broadcom.com; pavan.chebbi@broadcom.com; Nguyen, Anthony
> L <anthony.l.nguyen@intel.com>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; saeedm@nvidia.com; tariqt@nvidia.com;
> mbloch@nvidia.com; alexanderduyck@fb.com; kernel-team@meta.com;
> johannes@sipsolutions.net; sd@queasysnail.net; jianbol@nvidia.com;
> dtatulea@nvidia.com; sdf@fomichev.me; mohsin.bashr@gmail.com; Keller,
> Jacob E <jacob.e.keller@intel.com>; willemb@google.com;
> skhawaja@google.com; bestswngs@gmail.com; linux-doc@vger.kernel.org;
> linux-kernel@vger.kernel.org; intel-wired-lan@lists.osuosl.org; linux-
> rdma@vger.kernel.org; linux-wireless@vger.kernel.org; linux-
> kselftest@vger.kernel.org; leon@kernel.org
> Subject: [Intel-wired-lan] [PATCH net-next v2 03/13] net: introduce
> ndo_set_rx_mode_async and dev_rx_mode_work
>
> Add ndo_set_rx_mode_async callback that drivers can implement instead
> of the legacy ndo_set_rx_mode. The legacy callback runs under the
> netif_addr_lock spinlock with BHs disabled, preventing drivers from
> sleeping. The async variant runs from a work queue with rtnl_lock and
> netdev_lock_ops held, in fully sleepable context.
>
> When __dev_set_rx_mode() sees ndo_set_rx_mode_async, it schedules
> dev_rx_mode_work instead of calling the driver inline. The work
> function takes two snapshots of each address list (uc/mc) under the
> addr_lock, then drops the lock and calls the driver with the work
> copies. After the driver returns, it reconciles the snapshots back to
> the real lists under the lock.
>
> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
> ---
> Documentation/networking/netdevices.rst | 8 +++
> include/linux/netdevice.h | 20 ++++++
> net/core/dev.c | 94 +++++++++++++++++++++++-
> -
> 3 files changed, 115 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/networking/netdevices.rst
> b/Documentation/networking/netdevices.rst
> index 35704d115312..dc83d78d3b27 100644
> --- a/Documentation/networking/netdevices.rst
> +++ b/Documentation/networking/netdevices.rst
> @@ -289,6 +289,14 @@ struct net_device synchronization rules
> ndo_set_rx_mode:
> Synchronization: netif_addr_lock spinlock.
> Context: BHs disabled
...
>
> -/*
> - * Upload unicast and multicast address lists to device and
> - * configure RX filtering. When the device doesn't support unicast
> - * filtering it is put in promiscuous mode while unicast addresses
> - * are present.
> +static void dev_rx_mode_work(struct work_struct *work) {
> + struct net_device *dev = container_of(work, struct net_device,
> + rx_mode_work);
> + struct netdev_hw_addr_list uc_snap, mc_snap, uc_ref, mc_ref;
> + const struct net_device_ops *ops = dev->netdev_ops;
> + int err;
> +
> + __hw_addr_init(&uc_snap);
> + __hw_addr_init(&mc_snap);
> + __hw_addr_init(&uc_ref);
> + __hw_addr_init(&mc_ref);
> +
> + rtnl_lock();
> + netdev_lock_ops(dev);
> +
> + if (!netif_up_and_present(dev))
> + goto out;
> +
> + if (ops->ndo_set_rx_mode_async) {
> + netif_addr_lock_bh(dev);
> +
> + err = __hw_addr_list_snapshot(&uc_snap, &dev->uc,
> + dev->addr_len);
> + if (!err)
> + err = __hw_addr_list_snapshot(&uc_ref, &dev->uc,
> + dev->addr_len);
> + if (!err)
> + err = __hw_addr_list_snapshot(&mc_snap, &dev->mc,
> + dev->addr_len);
> + if (!err)
> + err = __hw_addr_list_snapshot(&mc_ref, &dev->mc,
> + dev->addr_len);
> + netif_addr_unlock_bh(dev);
> +
> + if (err) {
> + __hw_addr_flush(&uc_snap);
> + __hw_addr_flush(&uc_ref);
> + __hw_addr_flush(&mc_snap);
Shouldn't here go cleanup for symmetry?
__hw_addr_flush(&mc_ref);
> + goto out;
> + }
> +
> + ops->ndo_set_rx_mode_async(dev, &uc_snap, &mc_snap);
> +
> + netif_addr_lock_bh(dev);
> + __hw_addr_list_reconcile(&dev->uc, &uc_snap,
> + &uc_ref, dev->addr_len);
> + __hw_addr_list_reconcile(&dev->mc, &mc_snap,
> + &mc_ref, dev->addr_len);
> + netif_addr_unlock_bh(dev);
> + }
> +
> +out:
> + netdev_unlock_ops(dev);
> + rtnl_unlock();
> +}
...
> --
> 2.53.0
^ permalink raw reply
* Re: ath12k: desc_va endianness problem
From: Alexander Wilhelm @ 2026-03-23 11:20 UTC (permalink / raw)
To: Baochen Qiang; +Cc: Jeff Johnson, ath12k, linux-wireless, linux-kernel
In-Reply-To: <d0db7062-f428-410d-a704-395d67bd4554@oss.qualcomm.com>
On Mon, Mar 23, 2026 at 05:31:03PM +0800, Baochen Qiang wrote:
>
>
> On 3/20/2026 5:52 PM, Alexander Wilhelm wrote:
> > Hello ath12k developers,
> >
> > I have another fix for the big endian platform, but unfortunately the data types
> > do not match here, so I need your support. The problem is the following: the
> > structs `hal_reo_dest_ring`, `hal_wbm_completion_ring`, and
> > `hal_wbm_release_ring_cc_rx` all define the members `buf_va_lo` and `buf_va_hi`
> > as `__le32`. At first glance this seems correct, because the entire structure
> > contains only little endian fields. The local variable `desc_va` in each
> > function (see patch below) is of type `u64`, so it makes sense that I would need
> > to convert from little endian to CPU endian. Unfortunately, this leads to the
> > following crashes, in `tx_completion` and `rx_process_wbm`, respectivally:
> >
> >
> > Kernel attempted to read user page (40dcdf) - exploit attempt? (uid: 0)
> > BUG: Unable to handle kernel data access on read at 0x0040dcdf
> > Faulting instruction address: 0xe209290c
> > Oops: Kernel access of bad area, sig: 11 [#1]
> > BE PAGE_SIZE=4K SMP NR_CPUS=4 CoreNet Generic
> > Modules linked in: ath12k(O) mac80211(O) cfg80211(O) compat(O) ...
> > CPU: 1 PID: 10200 Comm: jshn Tainted: G O 6.6.73 #0
> > Hardware name: CyBoxAP-A e5500 0x80241021 CoreNet Generic
> > NIP: e209290c LR: e2092854 CTR: c08d3190
> > REGS: dffe3d40 TRAP: 0300 Tainted: G O (6.6.73)
> > MSR: 00029002 <CE,EE,ME> CR: 44004804 XER: 00000000
> > DEAR: 0040dcdf ESR: 00000000
> > GPR00: e2092854 dffe3e30 c328a500 e2092854 0040dcce 00000008 00070000 cf900000
> > GPR08: 00000000 cf900004 40000000 c8e52c4c c08d3190 1002801c 0fcf5000 c0ab85f8
> > GPR16: d0d1f7a0 c12a9080 00000001 df7b7f80 00000003 cf900000 e1bc0000 e1ccb988
> > GPR24: ffffffff c8ed0000 e1cc0220 00000000 c8ec0000 c8ec0000 c8ec0f50 c8ec0000
> > NIP [e209290c] ath12k_dp_tx_completion_handler+0x22c/0x720 [ath12k]
> > LR [e2092854] ath12k_dp_tx_completion_handler+0x174/0x720 [ath12k]
> > Call Trace:
> > [dffe3e30] [e2092854] ath12k_dp_tx_completion_handler+0x174/0x720 [ath12k] (unreliable)
> > [dffe3e80] [e208fe18] ath12k_dp_service_srng+0x58/0x380 [ath12k]
> > [dffe3ed0] [e20a1490] ath12k_pci_hif_resume+0x520/0x8a0 [ath12k]
> > [dffe3f00] [c067404c] __napi_poll+0x4c/0x260
> > [dffe3f30] [c06746f8] net_rx_action+0x188/0x340
> > [dffe3fa0] [c003a3d8] handle_softirqs+0x128/0x280
> > [dffe3ff0] [c00045b0] do_softirq_own_stack+0x30/0x50
> > [d0f2fb70] [00000000] 0x0
> > [d0f2fb90] [c003a7d0] irq_exit+0x70/0xa0
> > [d0f2fba0] [c0000c84] ExternalInput+0x144/0x160
> > --- interrupt: 500 at percpu_counter_add_batch+0x9c/0x150
> > NIP: c0425e8c LR: c01a5964 CTR: c01764e0
> > REGS: d0f2fbb0 TRAP: 0500 Tainted: G O (6.6.73)
> > MSR: 00029002 <CE,EE,ME> CR: 48008802 XER: 20000000
> >
> > GPR00: c01a5a00 d0f2fca0 c328a500 c1db7300 dffc0f20 00000000 fffffffc 00021002
> > GPR08: 1e763000 e1091054 00000007 c12b0530 88002808 1002801c 0fcf5000 c0ab85f8
> > GPR16: d0d1f7a0 dffc0f20 00000000 000003fe 00000000 f92412bd 00000003 c9525480
> > GPR24: d0f2fd74 c8a501f8 c12b0530 00029002 00000007 00000000 0000000b c1db7300
> > NIP [c0425e8c] percpu_counter_add_batch+0x9c/0x150
> > LR [c01a5964] unmap_page_range+0x484/0x820
> > --- interrupt: 500
> > [d0f2fca0] [00000001] 0x1 (unreliable)
> > [d0f2fcd0] [c01a5a00] unmap_page_range+0x520/0x820
> > [d0f2fd60] [c01a5d9c] unmap_vmas+0x9c/0xe0
> > [d0f2fda0] [c01afef4] exit_mmap+0xb4/0x2a0
> > [d0f2fe40] [c0031610] mmput+0x40/0x140
> > [d0f2fe60] [c0038df4] do_exit+0x2b4/0x990
> > [d0f2feb0] [c00396c4] do_group_exit+0x34/0xa0
> > [d0f2fed0] [c0039748] sys_exit_group+0x18/0x20
> > [d0f2fee0] [c000dbac] system_call_exception+0xac/0x1f0
> > [d0f2ff00] [c00110e8] ret_from_syscall+0x0/0x28
> > --- interrupt: c00 at 0xfded438
> > NIP: 0fded438 LR: 0ff23958 CTR: 0fd94930
> > REGS: d0f2ff10 TRAP: 0c00 Tainted: G O (6.6.73)
> > MSR: 0002f902 <CE,EE,PR,FP,ME> CR: 28002402 XER: 20000000
> >
> > GPR00: 000000ea bff93390 b0316520 00000000 113e8af0 113e8af0 00000000 00000000
> > GPR08: 00000000 00000000 00000000 ffffffff b02ccb04 1002801c 100a0000 bfbc4260
> > GPR16: 114974b0 00000000 114a4de0 00000000 b02cc900 00000001 00000000 00000001
> > GPR24: 0ff239a0 00000000 00000001 00000000 b030f52c fffff000 0ff23958 00000000
> > NIP [0fded438] 0xfded438
> > LR [0ff23958] 0xff23958
> > --- interrupt: c00
> > Code: 512a421e 2e140000 512a463e 40f20008 555b9f3e 39350004 754a4000 7c804c2c 41c20224 7c87442c 2c040000 41c20230 <88a40011> 7fc3f378 83a40008 8a640010
> > ---[ end trace 0000000000000000 ]---
> >
> > Kernel panic - not syncing: Fatal exception
> > ---[ end Kernel panic - not syncing: Fatal exception ]---
> >
> >
> > user@root:~# Kernel attempted to read user page (c011de) - exploit attempt? (uid: 0)
> > BUG: Unable to handle kernel data access on read at 0x00c011de
> > Faulting instruction address: 0xe1e3dc44
> > Oops: Kernel access of bad area, sig: 11 [#1]
> > BE PAGE_SIZE=4K SMP NR_CPUS=4 CoreNet Generic
> > Modules linked in: ...
> > CPU: 1 PID: 0 Comm: swapper/1 Tainted: G O 6.6.73 #0
> > Hardware name: CyBoxAP-A e5500 0x80241021 CoreNet Generic
> > NIP: e1e3dc44 LR: e1e3dc30 CTR: c08d40e0
> > REGS: dffe3ce0 TRAP: 0300 Tainted: G O (6.6.73)
> > MSR: 00029002 <CE,EE,ME> CR: 44004402 XER: 00000000
> > DEAR: 00c011de ESR: 00000000
> > GPR00: e1e33154 dffe3dd0 c1870000 00000000 cebe0000 00000000 00000000 00c011ce
> > GPR08: 00000001 00000000 00020000 c30a294c c08d40e0 00000000 00000001 00000000
> > GPR16: e1ce2668 c9270000 c9269a18 c92664d0 e1ce26dc 00000000 babababa dffe3df4
> > GPR24: 00000040 00000000 c9266480 dffe3dec dffe3e04 c9260000 00c011ce c9269a18
> > NIP [e1e3dc44] ath12k_dp_rx_process_wbm_err+0x124/0x600 [ath12k]
> > LR [e1e3dc30] ath12k_dp_rx_process_wbm_err+0x110/0x600 [ath12k]
> > Call Trace:
> > [dffe3dd0] [c0ab8e30] 0xc0ab8e30 (unreliable)
> > [dffe3e80] [e1e33154] ath12k_dp_service_srng+0x314/0x380 [ath12k]
> > [dffe3ed0] [e1e44540] ath12k_pci_hif_resume+0x520/0x8a0 [ath12k]
> > [dffe3f00] [c0674c7c] __napi_poll+0x4c/0x260
> > [dffe3f30] [c0675328] net_rx_action+0x188/0x340
> > [dffe3fa0] [c003a3d8] handle_softirqs+0x128/0x280
> > [dffe3ff0] [c00045b0] do_softirq_own_stack+0x30/0x50
> > [c18c7e10] [c12b040c] 0xc12b040c
> > [c18c7e30] [c003a7d0] irq_exit+0x70/0xa0
> > [c18c7e40] [c0000c84] ExternalInput+0x144/0x160
> > --- interrupt: 500 at arch_cpu_idle+0x24/0x50
> > NIP: c00071f4 LR: c00071f4 CTR: c000fe14
> > REGS: c18c7e50 TRAP: 0500 Tainted: G O (6.6.73)
> > MSR: 0002b002 <CE,EE,FP,ME> CR: 84000402 XER: 00000000
> >
> > GPR00: c08cc978 c18c7f40 c1870000 00000005 00000001 40000000 c328becc c12b0530
> > GPR08: c12b0530 c000fe14 0098ca91 00154674 24000402 00000000 00000001 00000000
> > GPR16: 00000000 00000000 c00119a0 dffee5f0 00000001 00000000 ffffffff c1050254
> > GPR24: c12c0000 c0011970 c0011940 c12d0000 00000004 c12b040c c12b0000 00000001
> > NIP [c00071f4] arch_cpu_idle+0x24/0x50
> > LR [c00071f4] arch_cpu_idle+0x24/0x50
> > --- interrupt: 500
> > [c18c7f40] [c0a367e0] 0xc0a367e0 (unreliable)
> > [c18c7f50] [c08cc978] default_idle_call+0x38/0x58
> > [c18c7f60] [c007b3b0] do_idle+0xf0/0x130
> > [c18c7f80] [c007b580] cpu_startup_entry+0x30/0x40
> > [c18c7fa0] [c001325c] start_secondary+0x48c/0x930
> > [c18c7ff0] [c0002870] __secondary_start+0x90/0xdc
> > Code: 7fa3eb78 4bfcba59 7c641b79 41c20144 38a10044 7fa3eb78 4bfcdb85 7c651b79 40c2026c 83c10058 2c1e0000 41c202d0 <813e0010> 7c09b000 41c20010 7e84a378
> > ---[ end trace 0000000000000000 ]---
> >
> > Kernel panic - not syncing: Fatal exception
> > ---[ end Kernel panic - not syncing: Fatal exception ]---
> >
> >
> > My fix, as shown in the patch below, is to remove the conversion. But then the
> > member variables `buf_va_lo` and `buf_va_hi` must be `u32`, which is obviously
> > wrong. Alternatively, `desc_va` must be `__le64`, but that is likely also
> > incorrect, because the address is simply dereferenced, and this clearly requires
> > CPU endianness. What I also do not fully understand is who actually fills these
> > addresses and at which stage this happens. I hope you can help clarify this so
> > that I can provide a correct patch for this issue afterward.
> >
> >
>
> hmm, i am not sure here, but can you please try
>
> diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
> index 1c82d927d27b..f142759a217b 100644
> --- a/drivers/net/wireless/ath/ath12k/dp.c
> +++ b/drivers/net/wireless/ath/ath12k/dp.c
> @@ -1246,7 +1246,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
>
> /* Update descriptor VA in SPT */
> rx_desc_addr = ath12k_dp_cc_get_desc_addr_ptr(dp, ppt_idx, j);
> - *rx_desc_addr = &rx_descs[j];
> + *rx_desc_addr = (struct ath12k_rx_desc_info
> *)cpu_to_le64(&rx_descs[j]);
> }
> }
>
> @@ -1286,7 +1286,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
> /* Update descriptor VA in SPT */
> tx_desc_addr =
> ath12k_dp_cc_get_desc_addr_ptr(dp, ppt_idx, j);
> - *tx_desc_addr = &tx_descs[j];
> + *tx_desc_addr = (struct ath12k_tx_desc_info
> *)cpu_to_le64(&tx_descs[j]);
> }
> }
> spin_unlock_bh(&dp->tx_desc_lock[pool_id]);
>
Hi Baochen,
It actually worked, although the solution isn't entirely clean. Sparse
consequently complains with:
dp.c:1249:42: warning: cast from restricted __le64
dp.c:1289:50: warning: cast from restricted __le64
To be honest, I also don't quite understand why the struct pointer has to be in
little endian at this point. The function `ath12k_dp_cc_get_desc_addr_ptr`
returns an offset from the `vaddr` inside the `spt_info` struct, stored as a
`u64`. But dereferencing it suddenly treats it as little endian. Shouldn't
`vaddr` itself perhaps be a `__le64`?
Best regards
Alexander Wilhelm
^ permalink raw reply
* wifi: rtw89: rtw8922ae: HWSI bus lockup during RF recalibration on AP bandwidth change
From: Jeffrey Wälti @ 2026-03-23 10:58 UTC (permalink / raw)
To: linux-wireless@vger.kernel.org; +Cc: pkshih@realtek.com
Hi,
I am experiencing a reproducible HWSI bus lockup on the RTL8922AE
(rtw89_8922ae) triggered by the connected AP changing its advertised
bandwidth in a beacon. During the lockup, the radio is unresponsive and the only fix I could find is reconnecting to the network.
The issue occurs on every boot within seconds of association, and also during normal operation whenever the AP re-advertises its
channel width.
I have tested with both the in-tree driver on kernel 6.19 and the
latest out-of-tree driver from morrownr/rtw89 (git HEAD). Both
reproduce the issue identically.
User-visible impact
-------------------
During the HWSI busy window, all network traffic basically stops. Existing TCP connections stall and time-sensitive applications (VoIP, video calls) break. The Wi-Fi/BT coexistence is also disrupted, causing paired Bluetooth devices to disconnect.
The issue reproduces on every association and also during
runtime when the AP periodically re-advertises its bandwidth (sometimes every few minutes), making connectivity unreliable.
Boot-to-bug dmesg (trimmed to relevant entries)
------------------------------------------------
[ 17.659262] rtw89_8922ae 0000:03:00.0: loaded firmware rtw89/rtw8922a_fw-4.bin
[ 17.659440] rtw89_8922ae 0000:03:00.0: enabling device (0000 -> 0003)
[ 17.666964] rtw89_8922ae 0000:03:00.0: Firmware version 0.35.80.3 (8ef4f0cf), cmd version 1, type 1
[ 17.666968] rtw89_8922ae 0000:03:00.0: Firmware version 0.35.80.3 (8ef4f0cf), cmd version 1, type 3
[ 17.685115] rtw89_8922ae 0000:03:00.0: chip rfe_type is 1
[ 17.685886] input: HD-Audio Generic Mic as /devices/pci0000:00/0000:00:08.1/0000:04:00.6/sound/card1/input24
[ 17.685913] input: HD-Audio Generic Headphone as /devices/pci0000:00/0000:00:08.1/0000:04:00.6/sound/card1/input25
[ 17.687499] rtw89_8922ae 0000:03:00.0: Firmware version 0.1.0.0 (7b393818), cmd version 0, type 64
[ 17.687504] rtw89_8922ae 0000:03:00.0: Firmware element BB version: 00 49 00 00
[ 17.687511] rtw89_8922ae 0000:03:00.0: Firmware element radio A version: 00 33 00 00
[ 17.687516] rtw89_8922ae 0000:03:00.0: Firmware element NCTL version: 00 0f 00 00
[ 17.687536] rtw89_8922ae 0000:03:00.0: Firmware element TXPWR version: 00 46 00 00
[ 17.687537] rtw89_8922ae 0000:03:00.0: Firmware element TXPWR version: 00 46 00 00
[ 17.687538] rtw89_8922ae 0000:03:00.0: Firmware element TXPWR version: 00 46 00 00
[ 17.687546] rtw89_8922ae 0000:03:00.0: Firmware element PWR_TRK version: 00 33 00 00
[ 17.687550] rtw89_8922ae 0000:03:00.0: Firmware element REGD version: 00 49 00 08
[ 17.691873] rtw89_8922ae 0000:03:00.0: rfkill hardware state changed to enable
[ 18.108033] systemd-journald[808]: Received client request to flush runtime journal.
[ 18.367229] input: keyd virtual keyboard as /devices/virtual/input/input26
[ 18.383013] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[ 18.383017] Bluetooth: BNEP filters: protocol multicast
[ 18.383021] Bluetooth: BNEP socket layer initialized
[ 18.410929] input: keyd virtual pointer as /devices/virtual/input/input27
[ 18.464298] Bluetooth: hci0: RTL: fw version 0x41c0c905
[ 18.647322] Bluetooth: hci0: AOSP extensions version v1.00
[ 18.647546] Bluetooth: MGMT ver 1.23
[ 18.655814] NET: Registered PF_ALG protocol family
[ 21.985205] wlan0: authenticate with 7c:10:c9:b5:b4:4c (local address=7c:fa:80:c3:5b:f9)
[ 21.985210] wlan0: send auth to 7c:10:c9:b5:b4:4c (try 1/3)
[ 22.001200] wlan0: authenticate with 7c:10:c9:b5:b4:4c (local address=7c:fa:80:c3:5b:f9)
[ 22.001210] wlan0: send auth to 7c:10:c9:b5:b4:4c (try 1/3)
[ 22.002893] wlan0: authenticated
[ 22.003792] wlan0: associate with 7c:10:c9:b5:b4:4c (try 1/3)
[ 22.005327] wlan0: RX AssocResp from 7c:10:c9:b5:b4:4c (capab=0x1011 status=0 aid=17)
[ 22.111182] wlan0: associated
[ 22.111255] wlan0: Ignore NSS change to invalid 4 in VHT opmode notif from 7c:10:c9:b5:b4:4c
[ 22.111263] wlan0: Limiting TX power to 23 (23 - 0) dBm as advertised by 7c:10:c9:b5:b4:4c
[ 32.623170] hid-sensor-hub 0020:1022:0001.0004: hidraw3: SENSOR HUB HID v0.00 Device [hid-amdsfh 1022:0001] on pcie_mp2_amd
[ 33.076564] wlan0: AP 7c:10:c9:b5:b4:4c changed bandwidth in beacon, new used config is 5220.000 MHz, width 5 (5250.000/0 MHz)
[ 33.090085] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.102460] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.114775] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.127371] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.141826] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.153783] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.165901] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.178402] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.191675] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.205185] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.217544] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.229788] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.242802] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.257200] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.269858] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.282153] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.295625] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.307822] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.320258] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.332693] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.345004] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.360051] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.373084] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.385703] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.397827] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.411372] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.426744] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.438969] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.451407] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.464456] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.477296] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.489589] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.502064] rtw89_8922ae 0000:03:00.0: poll HWSI is busy
[ 33.514235] rtw89_8922ae 0000:03:00.0: [rtw89_phy_write_full_rf_v2_a] HWSI is busy
[ 33.514249] wlan0: Ignore NSS change to invalid 4 in VHT opmode notif from 7c:10:c9:b5:b4:4c
[ 34.491697] rfkill: input handler disabled
[ 34.778186] Bluetooth: RFCOMM TTY layer initialized
[ 34.778198] Bluetooth: RFCOMM socket layer initialized
[ 34.778201] Bluetooth: RFCOMM ver 1.11
[ 39.723603] rfkill: input handler enabled
[ 40.871391] rfkill: input handler disabled
[ 41.010414] nvme nvme0: using unchecked data buffer
[ 43.272141] warning: `ThreadPoolForeg' uses wireless extensions which will stop working for Wi-Fi 7 hardware; use nl80211
Environment
-----------
Linux version 6.19.9-1-cachyos (linux-cachyos@cachyos) (clang version 22.1.1, LLD 22.1.1) #1 SMP PREEMPT_DYNAMIC Thu, 19 Mar 2026 20:13:27 +0000
03:00.0 Network controller [0280]: Realtek Semiconductor Co., Ltd. RTL8922AE 802.11be PCIe Wireless Network Adapter [10ec:8922] (rev 01)
Subsystem: Lenovo Device [17aa:4922]
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 112
IOMMU group: 15
Region 0: I/O ports at 2000 [size=256]
Region 2: Memory at 80b00000 (64-bit, non-prefetchable) [size=1M]
Capabilities: <access denied>
Kernel driver in use: rtw89_8922ae
Kernel modules: rtw89_8922ae
rtw89_8922ae 12288 0
rtw89_8922a 77824 1 rtw89_8922ae
rtw89_pci 131072 1 rtw89_8922ae
rtw89_core 1236992 2 rtw89_8922a,rtw89_pci
mac80211 1806336 2 rtw89_core,rtw89_pci
cfg80211 1523712 3 rtw89_core,rtw89_8922a,mac80211
rfkill 45056 9 rtw89_core,bluetooth,ideapad_laptop,cfg80211
Hardware: Lenovo Yoga 7 2-in-1 14AKP10 (machine type 83JR)
Chip: RTL8922AE (PCI ID 10ec:8922)
Firmware: rtw89/rtw8922a_fw-4.bin, version 0.35.80.3 (8ef4f0cf)
RFE type: 1
I am happy to provide additional debugging information, test patches, or collect further traces if needed.
Thanks,
Jeffrey Wälti
^ permalink raw reply
* Re: [PATCH 4/4] wifi: mac80211: add ieee80211_txq_aql_pending()
From: Johannes Berg @ 2026-03-23 10:55 UTC (permalink / raw)
To: Felix Fietkau, linux-wireless
In-Reply-To: <20260323101954.874299-4-nbd@nbd.name>
On Mon, 2026-03-23 at 10:19 +0000, Felix Fietkau wrote:
>
> +u32 ieee80211_txq_aql_pending(struct ieee80211_hw *hw,
> + struct ieee80211_txq *txq)
> +{
> + struct ieee80211_local *local = hw_to_local(hw);
> + struct sta_info *sta;
> +
> + if (!txq->sta)
> + return atomic_read(&local->aql_bc_pending_airtime);
> +
> + sta = container_of(txq->sta, struct sta_info, sta);
> +
> + if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
> + return 0;
I think better to put that check before the !txq->sta check. I don't
think it's there yet, but I think NAN is adding a per-interface mgmt
queue or so. Better to just cover all the cases here now.
johannes
^ permalink raw reply
* Re: [PATCH rtw-next 6/7] wifi: rtw89: 8922d: add set channel of BB part
From: Bitterblue Smith @ 2026-03-23 10:53 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless
In-Reply-To: <20260323032556.19825-7-pkshih@realtek.com>
On 23/03/2026 05:25, Ping-Ke Shih wrote:
> The set channel of BB part is the main part, which according to channel
> and bandwidth to configure CCK SCO, RX gain of LNA and TIA programmed
> in efuse for CCK and OFDM rate, and spur elimination of CSI and NBI tones.
>
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
> ---
> drivers/net/wireless/realtek/rtw89/core.h | 2 +
> drivers/net/wireless/realtek/rtw89/reg.h | 64 +-
> drivers/net/wireless/realtek/rtw89/rtw8922d.c | 820 ++++++++++++++++++
> 3 files changed, 885 insertions(+), 1 deletion(-)
>
[..]
> +
> +static const struct rtw89_nbi_reg_def rtw8922d_nbi_reg_def[] = {
> + [RF_PATH_A] = {
> + .notch1_idx = {0x241A0, 0xFF},
> + .notch1_frac_idx = {0x241A0, 0xC00},
> + .notch1_en = {0x241A0, 0x1000},
> + .notch2_idx = {0x241AC, 0xFF},
> + .notch2_frac_idx = {0x241AC, 0xC00},
> + .notch2_en = {0x241AC, 0x1000},
> + },
> + [RF_PATH_B] = {
> + .notch1_idx = {0x245A0, 0xFF},
> + .notch1_frac_idx = {0x241A0, 0xC00},
Is that supposed to be 0x245A0 ?
> + .notch1_en = {0x245A0, 0x1000},
> + .notch2_idx = {0x245AC, 0xFF},
> + .notch2_frac_idx = {0x245AC, 0xC00},
> + .notch2_en = {0x245AC, 0x1000},
> + },
> +};
> +
[...]
^ permalink raw reply
* Re: [PATCH 4/4] wifi: mac80211: add ieee80211_txq_aql_pending()
From: Felix Fietkau @ 2026-03-23 10:43 UTC (permalink / raw)
To: Johannes Berg, linux-wireless
In-Reply-To: <ba47b360ece399763cc55f7ddfeeb02a6cbb02db.camel@sipsolutions.net>
On 23.03.26 11:39, Johannes Berg wrote:
> On Mon, 2026-03-23 at 10:19 +0000, Felix Fietkau wrote:
>> Add a function to allow drivers to query the pending AQL airtime
>> for a given txq, for both unicast and broadcast.
>> This will be used for mt76 to limit buffering in AP mode for power-save
>> stations.
>
> Can you elaborate? Seems strange to make buffering decisions in the HW
> queues (presumably) based on what's already in SW queues?
AQL is tracking what's pushed to HW queues already, not SW queues.
On MT7615 and newer, firmware handles wakeup of PS stations internally
based on queued packets.
I want to make sure that the driver doesn't queue more packets for
sleeping stations than what's needed to wake them up.
- Felix
^ permalink raw reply
* Re: [PATCH 4/4] wifi: mac80211: add ieee80211_txq_aql_pending()
From: Johannes Berg @ 2026-03-23 10:39 UTC (permalink / raw)
To: Felix Fietkau, linux-wireless
In-Reply-To: <20260323101954.874299-4-nbd@nbd.name>
On Mon, 2026-03-23 at 10:19 +0000, Felix Fietkau wrote:
> Add a function to allow drivers to query the pending AQL airtime
> for a given txq, for both unicast and broadcast.
> This will be used for mt76 to limit buffering in AP mode for power-save
> stations.
Can you elaborate? Seems strange to make buffering decisions in the HW
queues (presumably) based on what's already in SW queues?
johannes
^ permalink raw reply
* Re: [PATCH 3/4] wifi: mac80211: add AQL support for broadcast packets
From: Johannes Berg @ 2026-03-23 10:38 UTC (permalink / raw)
To: Felix Fietkau, linux-wireless
In-Reply-To: <20260323101954.874299-3-nbd@nbd.name>
On Mon, 2026-03-23 at 10:19 +0000, Felix Fietkau wrote:
>
> +++ b/include/net/mac80211.h
> @@ -1252,8 +1252,8 @@ struct ieee80211_tx_info {
> status_data_idr:1,
> status_data:13,
> hw_queue:4,
> + tx_time_mc:1,
> tx_time_est:10;
> + "BC/MC %u us\n"
> + atomic_read(&local->aql_bc_pending_airtime),
> + local->aql_txq_limit_bc);
> return simple_read_from_buffer(user_buf, count, ppos,
> buf, len);
> }
> @@ -273,6 +277,11 @@ static ssize_t aql_txq_limit_write(struct file *file,
> else
> buf[count] = '\0';
>
> + if (sscanf(buf, "mcast %u", &q_limit_low) == 1) {
> + u32 aql_txq_limit_bc;
...
I think you should be consistent with multicast/broadcast. It really
isn't handling purely broadcast anyway.
johannes
^ permalink raw reply
* Re: [PATCH 2/4] wifi: mac80211: estimate expected throughput if not provided by driver/rc
From: Johannes Berg @ 2026-03-23 10:35 UTC (permalink / raw)
To: Felix Fietkau, linux-wireless
In-Reply-To: <20260323101954.874299-2-nbd@nbd.name>
On Mon, 2026-03-23 at 10:19 +0000, Felix Fietkau wrote:
> Estimate the tx throughput based on the expected per-packet tx time.
> This is useful for mesh implementations that rely on expected throughput,
> e.g. 802.11s or batman-adv.
>
> Signed-off-by: Felix Fietkau <nbd@nbd.name>
> ---
> net/mac80211/sta_info.c | 23 +++++++++++++++++++++++
> 1 file changed, 23 insertions(+)
>
> diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
> index 4259e9c13ed7..912f00d905b8 100644
> --- a/net/mac80211/sta_info.c
> +++ b/net/mac80211/sta_info.c
> @@ -2978,6 +2978,27 @@ static void sta_set_link_sinfo(struct sta_info *sta,
> }
> }
>
> +static u32 sta_estimate_expected_throughput(struct sta_info *sta,
> + struct station_info *sinfo)
> +{
> + struct ieee80211_sub_if_data *sdata = sta->sdata;
> + struct ieee80211_local *local = sdata->local;
> + struct rate_info *ri = &sinfo->txrate;
> + struct ieee80211_hw *hw = &local->hw;
> + struct ieee80211_chanctx_conf *conf;
> + u32 duration;
> + u8 band = 0;
> +
> + conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
> + if (conf)
> + band = conf->def.chan->band;
Double indentation, but 'u8 band = 0' is also really strange. Enum? And
should have a justification for assuming =0?
> + duration = ieee80211_rate_expected_tx_airtime(hw, NULL, ri, band, true, 1024);
> + duration += duration >> 4; /* add assumed packet error rate of ~6% */
> +
> + return ((1024 * USEC_PER_SEC) / duration) * 8;
this divides by zero.
> @@ -3202,6 +3223,8 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
> sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
>
> thr = sta_get_expected_throughput(sta);
> + if (!thr && (sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)))
> + thr = sta_estimate_expected_throughput(sta, sinfo);
Wrong indentation too ...
johannes
^ permalink raw reply
* [PATCH 3/4] wifi: mac80211: add AQL support for broadcast packets
From: Felix Fietkau @ 2026-03-23 10:19 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes
In-Reply-To: <20260323101954.874299-1-nbd@nbd.name>
Excessive broadcast traffic with little competing unicast traffic can easily
flood hardware queues, leading to throughput issues. Additionally, filling
the hardware queues with too many packets breaks FQ for broadcast data.
Fix this by enabling AQL for broadcast packets.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/net/cfg80211.h | 1 +
include/net/mac80211.h | 2 +-
net/mac80211/debugfs.c | 13 ++++++++--
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/main.c | 1 +
net/mac80211/sta_info.c | 17 ++++++++++++-
net/mac80211/sta_info.h | 3 ++-
net/mac80211/status.c | 5 ++--
net/mac80211/tx.c | 52 ++++++++++++++++++++------------------
9 files changed, 65 insertions(+), 31 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8cd870ece351..2607b800ada5 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3656,6 +3656,7 @@ enum wiphy_params_flags {
/* The per TXQ device queue limit in airtime */
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000
+#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_BC 50000
/* The per interface airtime threshold to switch to lower queue limit */
#define IEEE80211_AQL_THRESHOLD 24000
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9cc482191ab9..310546d4fca6 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1252,8 +1252,8 @@ struct ieee80211_tx_info {
status_data_idr:1,
status_data:13,
hw_queue:4,
+ tx_time_mc:1,
tx_time_est:10;
- /* 1 free bit */
union {
struct {
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index e8d0a8b71d59..a97d146f1445 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -210,11 +210,13 @@ static ssize_t aql_pending_read(struct file *file,
"VI %u us\n"
"BE %u us\n"
"BK %u us\n"
+ "BC/MC %u us\n"
"total %u us\n",
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]),
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]),
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]),
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]),
+ atomic_read(&local->aql_bc_pending_airtime),
atomic_read(&local->aql_total_pending_airtime));
return simple_read_from_buffer(user_buf, count, ppos,
buf, len);
@@ -239,7 +241,8 @@ static ssize_t aql_txq_limit_read(struct file *file,
"VO %u %u\n"
"VI %u %u\n"
"BE %u %u\n"
- "BK %u %u\n",
+ "BK %u %u\n"
+ "BC/MC %u\n",
local->aql_txq_limit_low[IEEE80211_AC_VO],
local->aql_txq_limit_high[IEEE80211_AC_VO],
local->aql_txq_limit_low[IEEE80211_AC_VI],
@@ -247,7 +250,8 @@ static ssize_t aql_txq_limit_read(struct file *file,
local->aql_txq_limit_low[IEEE80211_AC_BE],
local->aql_txq_limit_high[IEEE80211_AC_BE],
local->aql_txq_limit_low[IEEE80211_AC_BK],
- local->aql_txq_limit_high[IEEE80211_AC_BK]);
+ local->aql_txq_limit_high[IEEE80211_AC_BK],
+ local->aql_txq_limit_bc);
return simple_read_from_buffer(user_buf, count, ppos,
buf, len);
}
@@ -273,6 +277,11 @@ static ssize_t aql_txq_limit_write(struct file *file,
else
buf[count] = '\0';
+ if (sscanf(buf, "mcast %u", &q_limit_low) == 1) {
+ local->aql_txq_limit_bc = q_limit_low;
+ return count;
+ }
+
if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3)
return -EINVAL;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index b0dc93399e95..7ce39d19274f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1427,10 +1427,12 @@ struct ieee80211_local {
spinlock_t handle_wake_tx_queue_lock;
u16 airtime_flags;
+ u32 aql_txq_limit_bc;
u32 aql_txq_limit_low[IEEE80211_NUM_ACS];
u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
u32 aql_threshold;
atomic_t aql_total_pending_airtime;
+ atomic_t aql_bc_pending_airtime;
atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS];
const struct ieee80211_ops *ops;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index d1bb6353908d..a05e3f6cb43c 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -984,6 +984,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
spin_lock_init(&local->rx_path_lock);
spin_lock_init(&local->queue_stop_reason_lock);
+ local->aql_txq_limit_bc = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_BC;
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
INIT_LIST_HEAD(&local->active_txqs[i]);
spin_lock_init(&local->active_txq_lock[i]);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 912f00d905b8..12696c242537 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2443,13 +2443,28 @@ EXPORT_SYMBOL(ieee80211_sta_recalc_aggregates);
void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
struct sta_info *sta, u8 ac,
- u16 tx_airtime, bool tx_completed)
+ u16 tx_airtime, bool tx_completed,
+ bool mcast)
{
int tx_pending;
if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
return;
+ if (mcast) {
+ if (!tx_completed) {
+ atomic_add(tx_airtime, &local->aql_bc_pending_airtime);
+ return;
+ }
+
+ tx_pending = atomic_sub_return(tx_airtime,
+ &local->aql_bc_pending_airtime);
+ if (tx_pending < 0)
+ atomic_cmpxchg(&local->aql_bc_pending_airtime,
+ tx_pending, 0);
+ return;
+ }
+
if (!tx_completed) {
if (sta)
atomic_add(tx_airtime,
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 58ccbea7f6f6..eea7eff35463 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -147,7 +147,8 @@ struct airtime_info {
void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
struct sta_info *sta, u8 ac,
- u16 tx_airtime, bool tx_completed);
+ u16 tx_airtime, bool tx_completed,
+ bool mcast);
struct sta_info;
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 4b38aa0e902a..ccc37c4d843d 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -751,7 +751,7 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
ieee80211_sta_update_pending_airtime(local, sta,
skb_get_queue_mapping(skb),
tx_time_est,
- true);
+ true, info->tx_time_mc);
rcu_read_unlock();
}
@@ -1160,10 +1160,11 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
/* Do this here to avoid the expensive lookup of the sta
* in ieee80211_report_used_skb().
*/
+ bool mcast = IEEE80211_SKB_CB(skb)->tx_time_mc;
ieee80211_sta_update_pending_airtime(local, sta,
skb_get_queue_mapping(skb),
tx_time_est,
- true);
+ true, mcast);
ieee80211_info_set_tx_time_est(IEEE80211_SKB_CB(skb), 0);
}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3844c7fbb8a8..04a3ea9beae5 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3987,20 +3987,20 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
encap_out:
info->control.vif = vif;
- if (tx.sta &&
- wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
- bool ampdu = txq->ac != IEEE80211_AC_VO;
+ if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
+ bool ampdu = txq->sta && txq->ac != IEEE80211_AC_VO;
u32 airtime;
airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
skb->len, ampdu);
- if (airtime) {
- airtime = ieee80211_info_set_tx_time_est(info, airtime);
- ieee80211_sta_update_pending_airtime(local, tx.sta,
- txq->ac,
- airtime,
- false);
- }
+ if (!airtime)
+ return skb;
+
+ airtime = ieee80211_info_set_tx_time_est(info, airtime);
+ info->tx_time_mc = !tx.sta;
+ ieee80211_sta_update_pending_airtime(local, tx.sta, txq->ac,
+ airtime, false,
+ info->tx_time_mc);
}
return skb;
@@ -4052,6 +4052,7 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
struct ieee80211_txq *ret = NULL;
struct txq_info *txqi = NULL, *head = NULL;
bool found_eligible_txq = false;
+ bool aql_check;
spin_lock_bh(&local->active_txq_lock[ac]);
@@ -4075,26 +4076,28 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
if (!head)
head = txqi;
+ aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
+ if (aql_check)
+ found_eligible_txq = true;
+
if (txqi->txq.sta) {
struct sta_info *sta = container_of(txqi->txq.sta,
struct sta_info, sta);
- bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
- s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac);
- if (aql_check)
- found_eligible_txq = true;
-
- if (deficit < 0)
+ if (ieee80211_sta_deficit(sta, txqi->txq.ac) < 0) {
sta->airtime[txqi->txq.ac].deficit +=
sta->airtime_weight;
- if (deficit < 0 || !aql_check) {
- list_move_tail(&txqi->schedule_order,
- &local->active_txqs[txqi->txq.ac]);
- goto begin;
+ aql_check = false;
}
}
+ if (!aql_check) {
+ list_move_tail(&txqi->schedule_order,
+ &local->active_txqs[txqi->txq.ac]);
+ goto begin;
+ }
+
if (txqi->schedule_round == local->schedule_round[ac])
goto out;
@@ -4161,7 +4164,8 @@ bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
return true;
if (!txq->sta)
- return true;
+ return atomic_read(&local->aql_bc_pending_airtime) <
+ local->aql_txq_limit_bc;
if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
return true;
@@ -4210,15 +4214,15 @@ bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
spin_lock_bh(&local->active_txq_lock[ac]);
- if (!txqi->txq.sta)
- goto out;
-
if (list_empty(&txqi->schedule_order))
goto out;
if (!ieee80211_txq_schedule_airtime_check(local, ac))
goto out;
+ if (!txqi->txq.sta)
+ goto out;
+
list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
schedule_order) {
if (iter == txqi)
--
2.51.0
^ permalink raw reply related
* [PATCH 1/4] wifi: mac80211: factor out part of ieee80211_calc_expected_tx_airtime
From: Felix Fietkau @ 2026-03-23 10:19 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes
Create ieee80211_rate_expected_tx_airtime helper function, which returns
the expected tx airtime for a given rate and packet length in units of
1024 usec, for more accuracy.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
net/mac80211/airtime.c | 87 ++++++++++++++++++++++----------------
net/mac80211/ieee80211_i.h | 5 +++
2 files changed, 56 insertions(+), 36 deletions(-)
diff --git a/net/mac80211/airtime.c b/net/mac80211/airtime.c
index c61df637232a..0c54cdbd753c 100644
--- a/net/mac80211/airtime.c
+++ b/net/mac80211/airtime.c
@@ -685,7 +685,7 @@ static int ieee80211_fill_rx_status(struct ieee80211_rx_status *stat,
if (ieee80211_fill_rate_info(hw, stat, band, ri))
return 0;
- if (!ieee80211_rate_valid(rate))
+ if (!rate || !ieee80211_rate_valid(rate))
return -1;
if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
@@ -753,6 +753,53 @@ u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(ieee80211_calc_tx_airtime);
+u32 ieee80211_rate_expected_tx_airtime(struct ieee80211_hw *hw,
+ struct ieee80211_tx_rate *tx_rate,
+ struct rate_info *ri,
+ enum nl80211_band band,
+ bool ampdu, int len)
+{
+ struct ieee80211_rx_status stat;
+ u32 duration, overhead;
+ u8 agg_shift;
+
+ if (ieee80211_fill_rx_status(&stat, hw, tx_rate, ri, band, len))
+ return 0;
+
+ if (stat.encoding == RX_ENC_LEGACY || !ampdu)
+ return ieee80211_calc_rx_airtime(hw, &stat, len) * 1024;
+
+ duration = ieee80211_get_rate_duration(hw, &stat, &overhead);
+
+ /*
+ * Assume that HT/VHT transmission on any AC except VO will
+ * use aggregation. Since we don't have reliable reporting
+ * of aggregation length, assume an average size based on the
+ * tx rate.
+ * This will not be very accurate, but much better than simply
+ * assuming un-aggregated tx in all cases.
+ */
+ if (duration > 400 * 1024) /* <= VHT20 MCS2 1S */
+ agg_shift = 1;
+ else if (duration > 250 * 1024) /* <= VHT20 MCS3 1S or MCS1 2S */
+ agg_shift = 2;
+ else if (duration > 150 * 1024) /* <= VHT20 MCS5 1S or MCS2 2S */
+ agg_shift = 3;
+ else if (duration > 70 * 1024) /* <= VHT20 MCS5 2S */
+ agg_shift = 4;
+ else if (stat.encoding != RX_ENC_HE ||
+ duration > 20 * 1024) /* <= HE40 MCS6 2S */
+ agg_shift = 5;
+ else
+ agg_shift = 6;
+
+ duration *= len;
+ duration /= AVG_PKT_SIZE;
+ duration += (overhead * 1024 >> agg_shift);
+
+ return duration;
+}
+
u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *pubsta,
@@ -775,45 +822,13 @@ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
if (pubsta) {
struct sta_info *sta = container_of(pubsta, struct sta_info,
sta);
- struct ieee80211_rx_status stat;
struct ieee80211_tx_rate *tx_rate = &sta->deflink.tx_stats.last_rate;
struct rate_info *ri = &sta->deflink.tx_stats.last_rate_info;
- u32 duration, overhead;
- u8 agg_shift;
+ u32 duration;
- if (ieee80211_fill_rx_status(&stat, hw, tx_rate, ri, band, len))
- return 0;
-
- if (stat.encoding == RX_ENC_LEGACY || !ampdu)
- return ieee80211_calc_rx_airtime(hw, &stat, len);
-
- duration = ieee80211_get_rate_duration(hw, &stat, &overhead);
- /*
- * Assume that HT/VHT transmission on any AC except VO will
- * use aggregation. Since we don't have reliable reporting
- * of aggregation length, assume an average size based on the
- * tx rate.
- * This will not be very accurate, but much better than simply
- * assuming un-aggregated tx in all cases.
- */
- if (duration > 400 * 1024) /* <= VHT20 MCS2 1S */
- agg_shift = 1;
- else if (duration > 250 * 1024) /* <= VHT20 MCS3 1S or MCS1 2S */
- agg_shift = 2;
- else if (duration > 150 * 1024) /* <= VHT20 MCS5 1S or MCS2 2S */
- agg_shift = 3;
- else if (duration > 70 * 1024) /* <= VHT20 MCS5 2S */
- agg_shift = 4;
- else if (stat.encoding != RX_ENC_HE ||
- duration > 20 * 1024) /* <= HE40 MCS6 2S */
- agg_shift = 5;
- else
- agg_shift = 6;
-
- duration *= len;
- duration /= AVG_PKT_SIZE;
+ duration = ieee80211_rate_expected_tx_airtime(hw, tx_rate, ri,
+ band, true, len);
duration /= 1024;
- duration += (overhead >> agg_shift);
return max_t(u32, duration, 4);
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d71e0c6d2165..b0dc93399e95 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2834,6 +2834,11 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
extern const struct ethtool_ops ieee80211_ethtool_ops;
+u32 ieee80211_rate_expected_tx_airtime(struct ieee80211_hw *hw,
+ struct ieee80211_tx_rate *tx_rate,
+ struct rate_info *ri,
+ enum nl80211_band band,
+ bool ampdu, int len);
u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *pubsta,
--
2.51.0
^ permalink raw reply related
* [PATCH 4/4] wifi: mac80211: add ieee80211_txq_aql_pending()
From: Felix Fietkau @ 2026-03-23 10:19 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes
In-Reply-To: <20260323101954.874299-1-nbd@nbd.name>
Add a function to allow drivers to query the pending AQL airtime
for a given txq, for both unicast and broadcast.
This will be used for mt76 to limit buffering in AP mode for power-save
stations.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/net/mac80211.h | 11 +++++++++++
net/mac80211/tx.c | 18 ++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 310546d4fca6..f260017cc858 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6710,6 +6710,17 @@ void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
bool
ieee80211_txq_airtime_check(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
+/**
+ * ieee80211_txq_aql_pending - get pending AQL airtime for a txq
+ *
+ * @hw: pointer obtained from ieee80211_alloc_hw()
+ * @txq: pointer obtained from station or virtual interface
+ *
+ * Return: pending airtime (in usec) for the given txq.
+ */
+u32 ieee80211_txq_aql_pending(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq);
+
/**
* ieee80211_iter_keys - iterate keys programmed into the device
* @hw: pointer obtained from ieee80211_alloc_hw()
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 04a3ea9beae5..07a65e14d637 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4185,6 +4185,24 @@ bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_txq_airtime_check);
+u32 ieee80211_txq_aql_pending(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+
+ if (!txq->sta)
+ return atomic_read(&local->aql_bc_pending_airtime);
+
+ sta = container_of(txq->sta, struct sta_info, sta);
+
+ if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
+ return 0;
+
+ return atomic_read(&sta->airtime[txq->ac].aql_tx_pending);
+}
+EXPORT_SYMBOL(ieee80211_txq_aql_pending);
+
static bool
ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac)
{
--
2.51.0
^ permalink raw reply related
* [PATCH 2/4] wifi: mac80211: estimate expected throughput if not provided by driver/rc
From: Felix Fietkau @ 2026-03-23 10:19 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes
In-Reply-To: <20260323101954.874299-1-nbd@nbd.name>
Estimate the tx throughput based on the expected per-packet tx time.
This is useful for mesh implementations that rely on expected throughput,
e.g. 802.11s or batman-adv.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
net/mac80211/sta_info.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 4259e9c13ed7..912f00d905b8 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2978,6 +2978,27 @@ static void sta_set_link_sinfo(struct sta_info *sta,
}
}
+static u32 sta_estimate_expected_throughput(struct sta_info *sta,
+ struct station_info *sinfo)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_local *local = sdata->local;
+ struct rate_info *ri = &sinfo->txrate;
+ struct ieee80211_hw *hw = &local->hw;
+ struct ieee80211_chanctx_conf *conf;
+ u32 duration;
+ u8 band = 0;
+
+ conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
+ if (conf)
+ band = conf->def.chan->band;
+
+ duration = ieee80211_rate_expected_tx_airtime(hw, NULL, ri, band, true, 1024);
+ duration += duration >> 4; /* add assumed packet error rate of ~6% */
+
+ return ((1024 * USEC_PER_SEC) / duration) * 8;
+}
+
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
bool tidstats)
{
@@ -3202,6 +3223,8 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
thr = sta_get_expected_throughput(sta);
+ if (!thr && (sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)))
+ thr = sta_estimate_expected_throughput(sta, sinfo);
if (thr != 0) {
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
--
2.51.0
^ permalink raw reply related
* [PATCH v3 2/9] dt-bindings: mmc: amlogic: Add compatible for T7 mmc
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau
In-Reply-To: <20260323-add-emmc-t7-vim4-v3-0-5159d90a984c@aliel.fr>
Add amlogic,t7-mmc compatible string, falling back to amlogic,meson-axg-mmc
as the T7 MMC controller is compatible with the AXG implementation.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
Documentation/devicetree/bindings/mmc/amlogic,meson-gx-mmc.yaml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-gx-mmc.yaml b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx-mmc.yaml
index 57646575a13f8..40dccf9715781 100644
--- a/Documentation/devicetree/bindings/mmc/amlogic,meson-gx-mmc.yaml
+++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx-mmc.yaml
@@ -19,7 +19,10 @@ allOf:
properties:
compatible:
oneOf:
- - const: amlogic,meson-axg-mmc
+ - items:
+ - enum:
+ - amlogic,t7-mmc
+ - const: amlogic,meson-axg-mmc
- items:
- const: amlogic,meson-gx-mmc
- const: amlogic,meson-gxbb-mmc
--
2.49.0
^ permalink raw reply related
* [PATCH v3 3/9] arm64: dts: amlogic: t7: Add MMC controller nodes
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau
In-Reply-To: <20260323-add-emmc-t7-vim4-v3-0-5159d90a984c@aliel.fr>
Add device tree nodes for the three MMC controllers available
on the Amlogic T7 SoC, using amlogic,meson-axg-mmc as fallback compatible.
All nodes are disabled by default and should be
enabled in the board-specific DTS file.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 39 +++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index ac8de8e9b8010..b3898669c9571 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -374,6 +374,45 @@ sec_ao: ao-secure@10220 {
reg = <0x0 0x10220 0x0 0x140>;
amlogic,has-chip-id;
};
+
+ sd_emmc_a: mmc@88000 {
+ compatible = "amlogic,t7-mmc", "amlogic,meson-axg-mmc";
+ reg = <0x0 0x88000 0x0 0x800>;
+ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clkc_periphs CLKID_SYS_SD_EMMC_A>,
+ <&clkc_periphs CLKID_SD_EMMC_A>,
+ <&scmi_clk CLKID_FCLK_DIV2>;
+ clock-names = "core", "clkin0", "clkin1";
+ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_A_SEL>;
+ assigned-clock-parents = <&xtal>;
+ };
+
+ sd_emmc_b: mmc@8a000 {
+ compatible = "amlogic,t7-mmc", "amlogic,meson-axg-mmc";
+ reg = <0x0 0x8a000 0x0 0x800>;
+ interrupts = <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>;
+ status = "disabled";
+ clocks = <&clkc_periphs CLKID_SYS_SD_EMMC_B>,
+ <&clkc_periphs CLKID_SD_EMMC_B>,
+ <&scmi_clk CLKID_FCLK_DIV2>;
+ clock-names = "core", "clkin0", "clkin1";
+ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_B_SEL>;
+ assigned-clock-parents = <&xtal>;
+ };
+
+ sd_emmc_c: mmc@8c000 {
+ compatible = "amlogic,t7-mmc", "amlogic,meson-axg-mmc";
+ reg = <0x0 0x8c000 0x0 0x800>;
+ interrupts = <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>;
+ status = "disabled";
+ clocks = <&clkc_periphs CLKID_SYS_SD_EMMC_C>,
+ <&clkc_periphs CLKID_SD_EMMC_C>,
+ <&scmi_clk CLKID_FCLK_DIV2>;
+ clock-names = "core", "clkin0", "clkin1";
+ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_C_SEL>;
+ assigned-clock-parents = <&xtal>;
+ };
};
};
--
2.49.0
^ permalink raw reply related
* [PATCH v3 0/9] arm64: dts: amlogic: Add MMC/SD/SDIO support for Khadas VIM4 (Amlogic T7)
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau, Nick Xie
This patch series depends on Jian's SCMI clock patches yet to merge
https://lore.kernel.org/all/20260313070022.700437-1-jian.hu@amlogic.com/
This series adds device tree support for the MMC, SD card and SDIO
interfaces on the Amlogic T7 SoC and the Khadas VIM4 board.
The first patches add the necessary building blocks in the T7 SoC
DTSI: pinctrl nodes for pin muxing, PWM controller nodes, and MMC
controller nodes. The amlogic,t7-mmc and amlogic,t7-pwm compatible
strings are introduced with fallbacks to existing drivers, avoiding
the need for new driver code.
The remaining patches enable these interfaces on the Khadas VIM4
board, including the power regulators, the SDIO power sequence and
32.768kHz PWM clock required by the BCM43752 Wi-Fi module, and the
board-specific MMC controller configurations.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
Changes in v3:
- Remove all changes about fixed pll clock from analog controller.
- Use clocks retrieved through SCMI.
- Add other MMC controllers
- Manage Wi-Fi module enablement.
- Link to v2: https://lore.kernel.org/r/20260218101709.35450-1-linux-kernel-dev@aliel.fr
Changes in v2:
- Resend v1 patches as attached to the first patch.
- Link to v1: https://lore.kernel.org/r/20260218101709.35450-1-linux-kernel-dev@aliel.fr
---
Ronald Claveau (9):
arm64: dts: amlogic: t7: Add eMMC, SD card and SDIO pinctrl nodes
dt-bindings: mmc: amlogic: Add compatible for T7 mmc
arm64: dts: amlogic: t7: Add MMC controller nodes
arm64: dts: amlogic: t7: Add PWM pinctrl nodes
arm64: dts: amlogic: t7: Add PWM controller nodes
arm64: dts: amlogic: t7: khadas-vim4: Add power regulators
arm64: dts: amlogic: t7: khadas-vim4: Add SDIO power sequence and WiFi clock
dt-bindings: net: wireless: brcm: Add compatible for bcm43752
arm64: dts: amlogic: t7: khadas-vim4: Add MMC nodes
.../bindings/mmc/amlogic,meson-gx-mmc.yaml | 5 +-
.../bindings/net/wireless/brcm,bcm4329-fmac.yaml | 1 +
.../dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 202 ++++++++++++-
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 336 +++++++++++++++++++++
4 files changed, 542 insertions(+), 2 deletions(-)
---
base-commit: f6eb9ae8b9fc13c3971e4a6d1e8442f253001f36
change-id: 20260320-add-emmc-t7-vim4-6ad16e94614f
prerequisite-message-id: <20260313070022.700437-1-jian.hu@amlogic.com>
prerequisite-patch-id: f03a086b4137158412b2d47b3de793b858de8dde
prerequisite-patch-id: 123970c9b29c2090440f2fd71c85d3c6fd8e36de
prerequisite-patch-id: 3e2e56b0926ba327b520f935df4ced5089bbe503
Best regards,
--
Ronald Claveau <linux-kernel-dev@aliel.fr>
^ permalink raw reply
* [PATCH v3 1/9] arm64: dts: amlogic: t7: Add eMMC, SD card and SDIO pinctrl nodes
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau
In-Reply-To: <20260323-add-emmc-t7-vim4-v3-0-5159d90a984c@aliel.fr>
These pinctrl nodes are required by the eMMC, SD card and SDIO drivers
to configure pin muxing at runtime.
- eMMC: control, 4-bit/8-bit data, data strobe and clock gate pins
- SD card: data, clock, command and clock gate pins
- SDIO: data, clock, command and clock gate pins
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 98 +++++++++++++++++++++++++++++
1 file changed, 98 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index 6510068bcff92..ac8de8e9b8010 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -250,6 +250,104 @@ gpio: bank@4000 {
#gpio-cells = <2>;
gpio-ranges = <&periphs_pinctrl 0 0 157>;
};
+
+ emmc_ctrl_pins: emmc-ctrl {
+ mux-0 {
+ groups = "emmc_cmd";
+ function = "emmc";
+ bias-pull-up;
+ };
+
+ mux-1 {
+ groups = "emmc_clk";
+ function = "emmc";
+ bias-disable;
+ };
+ };
+
+ emmc_data_4b_pins: emmc-data-4b {
+ mux-0 {
+ groups = "emmc_nand_d0",
+ "emmc_nand_d1",
+ "emmc_nand_d2",
+ "emmc_nand_d3";
+ function = "emmc";
+ bias-pull-up;
+ };
+ };
+
+ emmc_data_8b_pins: emmc-data-8b {
+ mux-0 {
+ groups = "emmc_nand_d0",
+ "emmc_nand_d1",
+ "emmc_nand_d2",
+ "emmc_nand_d3",
+ "emmc_nand_d4",
+ "emmc_nand_d5",
+ "emmc_nand_d6",
+ "emmc_nand_d7";
+ function = "emmc";
+ bias-pull-up;
+ };
+ };
+
+ emmc_ds_pins: emmc-ds {
+ mux {
+ groups = "emmc_nand_ds";
+ function = "emmc";
+ bias-pull-down;
+ };
+ };
+
+ emmc_clk_gate_pins: emmc_clk_gate {
+ mux {
+ groups = "GPIOB_8";
+ function = "gpio_periphs";
+ bias-pull-down;
+ };
+ };
+
+ sdcard_pins: sdcard {
+ mux {
+ groups = "sdcard_d0",
+ "sdcard_d1",
+ "sdcard_d2",
+ "sdcard_d3",
+ "sdcard_clk",
+ "sdcard_cmd";
+ function = "sdcard";
+ bias-pull-up;
+ };
+ };
+
+ sdcard_clk_gate_pins: sdcard_clk_gate {
+ mux {
+ groups = "GPIOC_4";
+ function = "gpio_periphs";
+ bias-pull-down;
+ };
+ };
+
+ sdio_pins: sdio {
+ mux-0 {
+ groups = "sdio_d0",
+ "sdio_d1",
+ "sdio_d2",
+ "sdio_d3",
+ "sdio_clk",
+ "sdio_cmd";
+ function = "sdio";
+ bias-pull-up;
+ };
+ };
+
+ sdio_clk_gate_pins: sdio_clk_gate {
+ mux {
+ groups = "GPIOX_4";
+ function = "gpio_periphs";
+ bias-pull-up;
+ };
+ };
};
gpio_intc: interrupt-controller@4080 {
--
2.49.0
^ permalink raw reply related
* [PATCH v3 4/9] arm64: dts: amlogic: t7: Add PWM pinctrl nodes
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau
In-Reply-To: <20260323-add-emmc-t7-vim4-v3-0-5159d90a984c@aliel.fr>
These pinctrl nodes are required by the PWM drivers to configure
pin muxing at runtime.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 136 ++++++++++++++++++++++++++++
1 file changed, 136 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index b3898669c9571..6d41de6f895b4 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -307,6 +307,142 @@ mux {
};
};
+ pwm_a_pins: pwm-a {
+ mux {
+ groups = "pwm_a";
+ function = "pwm_a";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_a_pins: pwm-ao-a {
+ mux {
+ groups = "pwm_ao_a";
+ function = "pwm_ao_a";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_b_pins: pwm-ao-b {
+ mux {
+ groups = "pwm_ao_b";
+ function = "pwm_ao_b";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_c_pins: pwm-ao-c {
+ mux {
+ groups = "pwm_ao_c";
+ function = "pwm_ao_c";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_c_hiz_pins: pwm-ao-c-hiz {
+ mux {
+ groups = "pwm_ao_c_hiz";
+ function = "pwm_ao_c_hiz";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_d_pins: pwm-ao-d {
+ mux {
+ groups = "pwm_ao_d";
+ function = "pwm_ao_d";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_e_pins: pwm-ao-e {
+ mux {
+ groups = "pwm_ao_e";
+ function = "pwm_ao_e";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_f_pins: pwm-ao-f {
+ mux {
+ groups = "pwm_ao_f";
+ function = "pwm_ao_f";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_g_pins: pwm-ao-g {
+ mux {
+ groups = "pwm_ao_g";
+ function = "pwm_ao_g";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_g_hiz_pins: pwm-ao-g-hiz {
+ mux {
+ groups = "pwm_ao_g_hiz";
+ function = "pwm_ao_g_hiz";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_h_pins: pwm-ao-h {
+ mux {
+ groups = "pwm_ao_h";
+ function = "pwm_ao_h";
+ bias-disable;
+ };
+ };
+
+ pwm_b_pins: pwm-b {
+ mux {
+ groups = "pwm_b";
+ function = "pwm_b";
+ bias-disable;
+ };
+ };
+
+ pwm_c_pins: pwm-c {
+ mux {
+ groups = "pwm_c";
+ function = "pwm_c";
+ bias-disable;
+ };
+ };
+
+ pwm_d_pins: pwm-d {
+ mux {
+ groups = "pwm_d";
+ function = "pwm_d";
+ bias-disable;
+ };
+ };
+
+ pwm_e_pins: pwm-e {
+ mux {
+ groups = "pwm_e";
+ function = "pwm_e";
+ bias-disable;
+ };
+ };
+
+ pwm_f_pins: pwm-f {
+ mux {
+ groups = "pwm_f";
+ function = "pwm_f";
+ bias-disable;
+ };
+ };
+
+ pwm_vs_pins: pwm-vs {
+ mux {
+ groups = "pwm_vs";
+ function = "pwm_vs";
+ bias-disable;
+ };
+ };
+
sdcard_pins: sdcard {
mux {
groups = "sdcard_d0",
--
2.49.0
^ permalink raw reply related
* [PATCH v3 9/9] arm64: dts: amlogic: t7: khadas-vim4: Add MMC nodes
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau
In-Reply-To: <20260323-add-emmc-t7-vim4-v3-0-5159d90a984c@aliel.fr>
Enable and configure the three MMC controllers for the Khadas VIM4 board:
- sd_emmc_a: SDIO interface for the BCM43752 Wi-Fi module
- sd_emmc_b: SD card slot
- sd_emmc_c: eMMC storage
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
.../dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 90 +++++++++++++++++++++-
1 file changed, 89 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
index 770f06b0b16c7..5a73ae081036c 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
@@ -14,7 +14,10 @@ / {
compatible = "khadas,vim4", "amlogic,a311d2", "amlogic,t7";
aliases {
- serial0 = &uart_a;
+ serial0 = &uart_a;
+ mmc0 = &sd_emmc_c;
+ mmc1 = &sd_emmc_b;
+ mmc2 = &sd_emmc_a;
};
memory@0 {
@@ -159,6 +162,91 @@ &pwm_ab {
pinctrl-names = "default";
};
+/* SDIO */
+&sd_emmc_a {
+ status = "okay";
+ pinctrl-0 = <&sdio_pins>;
+ pinctrl-1 = <&sdio_clk_gate_pins>;
+ pinctrl-names = "default", "clk-gate";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ bus-width = <4>;
+ cap-sd-highspeed;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
+ cap-sdio-irq;
+ max-frequency = <200000000>;
+ non-removable;
+ disable-wp;
+ no-mmc;
+ no-sd;
+
+ power-domains = <&pwrc PWRC_T7_SDIO_A_ID>;
+
+ keep-power-in-suspend;
+
+ mmc-pwrseq = <&sdio_pwrseq>;
+
+ vmmc-supply = <&vddao_3v3>;
+ vqmmc-supply = <&vddao_1v8>;
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm43752-fmac", "brcm,bcm4329-fmac";
+ };
+};
+
+/* SD card */
+&sd_emmc_b {
+ status = "okay";
+ pinctrl-0 = <&sdcard_pins>;
+ pinctrl-1 = <&sdcard_clk_gate_pins>;
+ pinctrl-names = "default", "clk-gate";
+
+ bus-width = <4>;
+ cap-sd-highspeed;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
+ max-frequency = <200000000>;
+ disable-wp;
+ no-sdio;
+ no-mmc;
+
+ power-domains = <&pwrc PWRC_T7_SDIO_B_ID>;
+
+ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <&sd_3v3>;
+ vqmmc-supply = <&vddio_c>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+ status = "okay";
+ pinctrl-0 = <&emmc_ctrl_pins>, <&emmc_data_8b_pins>, <&emmc_ds_pins>;
+ pinctrl-1 = <&emmc_clk_gate_pins>;
+ pinctrl-names = "default", "clk-gate";
+
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ mmc-ddr-1_8v;
+ mmc-hs200-1_8v;
+ max-frequency = <200000000>;
+ disable-wp;
+ non-removable;
+ no-sdio;
+ no-sd;
+
+ power-domains = <&pwrc PWRC_T7_EMMC_ID>;
+
+ vmmc-supply = <&vddio_3v3>;
+ vqmmc-supply = <&vddio_1v8>;
+};
+
&uart_a {
status = "okay";
clocks = <&xtal>, <&xtal>, <&xtal>;
--
2.49.0
^ permalink raw reply related
* [PATCH v3 8/9] dt-bindings: net: wireless: brcm: Add compatible for bcm43752
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau
In-Reply-To: <20260323-add-emmc-t7-vim4-v3-0-5159d90a984c@aliel.fr>
Add bcm43752 compatible with its bcm4329 compatible fallback.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml
index 3be7576787644..81fd3e37452a6 100644
--- a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml
@@ -42,6 +42,7 @@ properties:
- brcm,bcm4356-fmac
- brcm,bcm4359-fmac
- brcm,bcm4366-fmac
+ - brcm,bcm43752-fmac
- cypress,cyw4373-fmac
- cypress,cyw43012-fmac
- infineon,cyw43439-fmac
--
2.49.0
^ permalink raw reply related
* [PATCH v3 7/9] arm64: dts: amlogic: t7: khadas-vim4: Add SDIO power sequence and WiFi clock
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau
In-Reply-To: <20260323-add-emmc-t7-vim4-v3-0-5159d90a984c@aliel.fr>
Add the SDIO power sequence node using mmc-pwrseq-simple and a
32.768kHz PWM-based clock required by the Wi-Fi module.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
.../dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
index 2450084d37642..770f06b0b16c7 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
@@ -67,6 +67,15 @@ sd_3v3: regulator-sdcard-3v3 {
regulator-always-on;
};
+ sdio_pwrseq: sdio-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <500>;
+ power-off-delay-us = <200000>;
+ clocks = <&wifi32k>;
+ clock-names = "ext_clock";
+ };
+
vcc5v: regulator-vcc-5v {
compatible = "regulator-fixed";
regulator-name = "VCC5V";
@@ -135,6 +144,19 @@ vddio_c: regulator-gpio-c {
states = <1800000 1
3300000 0>;
};
+
+ wifi32k: wifi32k {
+ compatible = "pwm-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ pwms = <&pwm_ab 0 30518 0>;
+ };
+};
+
+&pwm_ab {
+ status = "okay";
+ pinctrl-0 = <&pwm_a_pins>;
+ pinctrl-names = "default";
};
&uart_a {
--
2.49.0
^ permalink raw reply related
* [PATCH v3 5/9] arm64: dts: amlogic: t7: Add PWM controller nodes
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau, Nick Xie
In-Reply-To: <20260323-add-emmc-t7-vim4-v3-0-5159d90a984c@aliel.fr>
Add device tree nodes for the seven PWM controllers available
on the Amlogic T7 SoC, using amlogic,meson-s4-pwm as fallback compatible.
All nodes are disabled by default and should be
enabled in the board-specific DTS file.
Co-developed-by: Nick Xie <nick@khadas.com>
Signed-off-by: Nick Xie <nick@khadas.com>
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 63 +++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index 6d41de6f895b4..a0261cd8eadfc 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -511,6 +511,69 @@ sec_ao: ao-secure@10220 {
amlogic,has-chip-id;
};
+ pwm_ao_ef: pwm@30000 {
+ compatible = "amlogic,t7-pwm", "amlogic,meson-s4-pwm";
+ reg = <0x0 0x30000 0x0 0x24>;
+ clocks = <&clkc_periphs CLKID_PWM_AO_E>,
+ <&clkc_periphs CLKID_PWM_AO_F>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_ao_gh: pwm@32000 {
+ compatible = "amlogic,t7-pwm", "amlogic,meson-s4-pwm";
+ reg = <0x0 0x32000 0x0 0x24>;
+ clocks = <&clkc_periphs CLKID_PWM_AO_G>,
+ <&clkc_periphs CLKID_PWM_AO_H>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_ab: pwm@58000 {
+ compatible = "amlogic,t7-pwm", "amlogic,meson-s4-pwm";
+ reg = <0x0 0x58000 0x0 0x24>;
+ clocks = <&clkc_periphs CLKID_PWM_A>,
+ <&clkc_periphs CLKID_PWM_B>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_cd: pwm@5a000 {
+ compatible = "amlogic,t7-pwm", "amlogic,meson-s4-pwm";
+ reg = <0x0 0x5a000 0x0 0x24>;
+ clocks = <&clkc_periphs CLKID_PWM_C>,
+ <&clkc_periphs CLKID_PWM_D>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_ef: pwm@5c000 {
+ compatible = "amlogic,t7-pwm", "amlogic,meson-s4-pwm";
+ reg = <0x0 0x5c000 0x0 0x24>;
+ clocks = <&clkc_periphs CLKID_PWM_E>,
+ <&clkc_periphs CLKID_PWM_F>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_ao_ab: pwm@5e000 {
+ compatible = "amlogic,t7-pwm", "amlogic,meson-s4-pwm";
+ reg = <0x0 0x5e000 0x0 0x24>;
+ clocks = <&clkc_periphs CLKID_PWM_AO_A>,
+ <&clkc_periphs CLKID_PWM_AO_B>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_ao_cd: pwm@60000 {
+ compatible = "amlogic,t7-pwm", "amlogic,meson-s4-pwm";
+ reg = <0x0 0x60000 0x0 0x24>;
+ clocks = <&clkc_periphs CLKID_PWM_AO_C>,
+ <&clkc_periphs CLKID_PWM_AO_D>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
sd_emmc_a: mmc@88000 {
compatible = "amlogic,t7-mmc", "amlogic,meson-axg-mmc";
reg = <0x0 0x88000 0x0 0x800>;
--
2.49.0
^ permalink raw reply related
* [PATCH v3 6/9] arm64: dts: amlogic: t7: khadas-vim4: Add power regulators
From: Ronald Claveau @ 2026-03-23 9:55 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Johannes Berg, van Spriel
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
linux-mmc, linux-wireless, Ronald Claveau
In-Reply-To: <20260323-add-emmc-t7-vim4-v3-0-5159d90a984c@aliel.fr>
Add voltage regulator nodes describing the VIM4 power tree,
required by peripheral nodes such as the SD card controller.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
.../dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 90 ++++++++++++++++++++++
1 file changed, 90 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
index fffdab96b12eb..2450084d37642 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
@@ -6,6 +6,8 @@
/dts-v1/;
#include "amlogic-t7.dtsi"
+#include <dt-bindings/gpio/amlogic,t7-periphs-pinctrl.h>
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Khadas vim4";
@@ -45,6 +47,94 @@ xtal: xtal-clk {
#clock-cells = <0>;
};
+ dc_in: regulator-dc-in {
+ compatible = "regulator-fixed";
+ regulator-name = "DC_IN";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ sd_3v3: regulator-sdcard-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "SD_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vddao_3v3>;
+ gpio = <&gpio GPIOD_11 GPIO_ACTIVE_LOW>;
+ regulator-boot-on;
+ enable-active-low;
+ regulator-always-on;
+ };
+
+ vcc5v: regulator-vcc-5v {
+ compatible = "regulator-fixed";
+ regulator-name = "VCC5V";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&dc_in>;
+
+ gpio = <&gpio GPIOH_4 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vcc5v0_usb: regulator-vcc-usb {
+ compatible = "regulator-fixed";
+ regulator-name = "VCC5V0_USB";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc5v>;
+
+ gpio = <&gpio GPIOY_5 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vddao_1v8: regulator-vddao-1v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "VDDAO_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vddao_3v3>;
+ regulator-always-on;
+ };
+
+ vddao_3v3: regulator-vddao-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "VDDAO_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&dc_in>;
+ regulator-always-on;
+ };
+
+ vddio_1v8: regulator-vddio-1v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "VDDIO_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vddio_3v3>;
+ regulator-always-on;
+ };
+
+ vddio_3v3: regulator-vddio-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "VDDIO_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vddao_3v3>;
+ regulator-always-on;
+ };
+
+ vddio_c: regulator-gpio-c {
+ compatible = "regulator-gpio";
+ regulator-name = "VDDIO_C";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vddio_3v3>;
+ gpios = <&gpio GPIOD_9 GPIO_ACTIVE_HIGH>;
+ states = <1800000 1
+ 3300000 0>;
+ };
};
&uart_a {
--
2.49.0
^ permalink raw reply related
* pull request: mt76-next 2026-03-23
From: Felix Fietkau @ 2026-03-23 9:33 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
Hi,
Here's my mt76 pull request for 7.1
- Felix
The following changes since commit 9ac76f3d0bb2940db3a9684d596b9c8f301ef315:
Merge tag 'wireless-next-2026-03-19' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next (2026-03-19 15:30:20 +0100)
are available in the Git repository at:
https://github.com/nbd168/wireless tags/mt76-next-2026-03-23
for you to fetch changes up to 61fe246f396e411b356535a5f8a3ad2412e1dfa8:
wifi: mt76: mt7996: Destroy active sta links in mt7996_mac_sta_remove() (2026-03-23 09:23:05 +0000)
----------------------------------------------------------------
mt76 patches for 7.1
- fixes
- mt7996/mt7925 MLO fixes/improvements
- mt7996 NPU support
- mt7996 external EEPROM support
----------------------------------------------------------------
Allen Ye (1):
wifi: mt76: fix backoff fields and max_power calculation
Alok Tiwari (1):
wifi: mt76: mt7996: fix FCS error flag check in RX descriptor
Chad Monroe (5):
wifi: mt76: fix deadlock in remain-on-channel
wifi: mt76: mt7996: reset device after MCU message timeout
wifi: mt76: mt7996: increase txq memory limit to 32 MiB
wifi: mt76: fix multi-radio on-channel scanning
wifi: mt76: support upgrading passive scans to active
Christian Hewitt (1):
wifi: mt7601u: check multiple firmware paths
Colin Ian King (1):
wifi: mt76: mt7996: Fix spelling mistake "retriving" -> "retrieving"
David Bauer (2):
wifi: mt76: mt76x02: wake queues after reconfig
wifi: mt76: don't return TXQ when exceeding max non-AQL packets
Duoming Zhou (2):
wifi: mt76: mt7915: fix use-after-free bugs in mt7915_mac_dump_work()
wifi: mt76: mt7996: fix use-after-free bugs in mt7996_mac_dump_work()
Felix Fietkau (9):
wifi: mt76: add offchannel check to mt76_roc_complete
wifi: mt76: check chanctx before restoring channel after ROC
wifi: mt76: abort ROC on chanctx changes
wifi: mt76: optimize ROC for same-channel case
wifi: mt76: send nullfunc PS frames on offchannel transitions
wifi: mt76: flush pending TX before channel switch
wifi: mt76: route nullfunc frames to PSD/ALTX queue
wifi: mt76: wait for firmware TX completion of mgmt frames before channel switch
wifi: mt76: add per-link beacon monitoring for MLO
Howard Hsu (1):
wifi: mt76: mt7996: support critical packet mode for MT7990 chipsets
Leon Yen (5):
wifi: mt76: mt7925: introduce CSA support in non-MLO mode
wifi: mt76: mt7925: Fix incorrect MLO mode in firmware control
wifi: mt76: mt792x: Fix a potential deadlock in high-load situations
wifi: mt76: mt7921: fix a potential clc buffer length underflow
wifi: mt76: mt7925: fix tx power setting failure after chip reset
Lorenzo Bianconi (30):
wifi: mt76: mt7996: Set mtxq->wcid just for primary link
wifi: mt76: mt7996: Reset mtxq->idx if primary link is removed in mt7996_vif_link_remove()
wifi: mt76: mt7996: Switch to the secondary link if the default one is removed
wifi: mt76: mt7996: Clear wcid pointer in mt7996_mac_sta_deinit_link()
wifi: mt76: mt7996: Reset ampdu_state state in case of failure in mt7996_tx_check_aggr()
wifi: mt76: Fix memory leak destroying device
wifi: mt76: mt7996: Fix NPU stop procedure
wifi: mt76: npu: Add missing rx_token_size initialization
wifi: mt76: always enable RRO queues for non-MT7992 chipset
wifi: mt76: mt7996: Fix BAND2 tx queues initialization when NPU is enabled
wifi: mt76: mt7996: Fix wdma_idx for MT7996 device if NPU is enabled
wifi: mt76: mt7996: Add mt7992_npu_txrx_offload_init routine
wifi: mt76: mt7996: Rename mt7996_npu_rxd_init() in mt7992_npu_rxd_init()
wifi: mt76: mt7996: Add NPU support for MT7990 chipset
wifi: mt76: mt7996: Integrate NPU in RRO session management
wifi: mt76: mt7996: Integrate MT7990 init configuration for NPU
wifi: mt76: mt7996: Integrate MT7990 dma configuration for NPU
wifi: mt76: mt7996: Add __mt7996_npu_hw_init routine
wifi: mt76: mt7996: Move RRO dma start in a dedicated routine
wifi: mt76: Do not reset idx for NPU tx queues during reset
wifi: mt76: mt7996: Do not schedule RRO and TxFree queues during reset for NPU
wifi: mt76: mt7996: Store DMA mapped buffer addresses in mt7996_npu_hw_init()
wifi: mt76: Enable NPU support for MT7996 devices
wifi: mt76: mt7996: Add missing CHANCTX_STA_CSA property
wifi: mt76: mt7996: Remove link pointer dependency in mt7996_mac_sta_remove_links()
wifi: mt76: mt7996: Remove unnecessary phy filed in mt7996_vif_link struct
wifi: mt76: mt7996: Decrement sta counter removing the link in mt7996_mac_reset_sta_iter()
wifi: mt76: mt7996: Rely on msta_link link_id in mt7996_vif_link_remove()
wifi: mt76: mt7996: Destroy vif active links in mt7996_remove_interface()
wifi: mt76: mt7996: Destroy active sta links in mt7996_mac_sta_remove()
Madhur Kumar (1):
wifi: mt76: mt7921: Replace deprecated PCI function
MeiChia Chiu (1):
wifi: mt76: mt7996: Add eMLSR support
Michael Lo (2):
wifi: mt76: mt7925: Skip scan process during suspend.
wifi: mt76: mt7921: fix 6GHz regulatory update on connection
Ming Yen Hsieh (3):
wifi: mt76: mt7925: fix incorrect length field in txpower command
wifi: mt76: mt7925: prevent NULL pointer dereference in mt7925_tx_check_aggr()
wifi: mt76: mt7925: prevent NULL vif dereference in mt7925_mac_write_txwi
Peter Chiu (3):
wifi: mt76: mt7996: fix RRO EMU configuration
wifi: mt76: mt7996: update WFSYS reset flow for MT7990 chipsets
wifi: mt76: mt7996: fix frequency separation for station STR mode
Quan Zhou (3):
wifi: mt76: mt7925: fix AMPDU state handling in mt7925_tx_check_aggr
wifi: mt76: mt7921: fix ROC abort flow interruption in mt7921_roc_work
wifi: mt76: mt7925: fix incorrect TLV length in CLC command
Rex Lu (1):
wifi: mt76: mt7996: adjust timeout value for boot-up calibration commands
Rory Little (1):
wifi: mt76: mt7921: Place upper limit on station AID
Ryder Lee (6):
wifi: mt76: mt7615: fix use_cts_prot support
wifi: mt76: mt7915: fix use_cts_prot support
wifi: mt76: mt7996: add support for ERP CTS & HT protection
dt-bindings: net: wireless: mt76: add mt79 PCI devices
dt-bindings: net: wireless: mt76: clarify backoff limit usage
wifi: mt76: mt7996: Disable Rx hdr_trans in monitor mode
Sean Wang (36):
wifi: mt76: mt7921: Reset ampdu_state state in case of failure in mt76_connac2_tx_check_aggr()
wifi: mt76: mt7925: drop puncturing handling from BSS change path
wifi: mt76: mt7925: fix potential deadlock in mt7925_roc_abort_sync
wifi: mt76: mt7921: fix potential deadlock in mt7921_roc_abort_sync
wifi: mt76: connac: use is_connac2() to replace is_mt7921() checks
wifi: mt76: mt7921: use mt76_for_each_q_rx() in reset path
wifi: mt76: mt7921: handle MT7902 irq_map quirk with mutable copy
wifi: mt76: mt7921: add MT7902e DMA layout support
wifi: mt76: connac: mark MT7902 as hw txp devices
wifi: mt76: mt792x: add PSE handling barrier for the large MCU cmd
wifi: mt76: mt792x: ensure MCU ready before ROM patch download
wifi: mt76: mt7921: add MT7902 MCU support
wifi: mt76: mt792x: add MT7902 WFDMA prefetch configuration
wifi: mt76: mt7921: add MT7902 PCIe device support
wifi: mt76: mt7921: add MT7902 SDIO device support
wifi: mt76: mt792x: describe USB WFSYS reset with a descriptor
wifi: mt76: mt792x: fix mt7925u USB WFSYS reset handling
wifi: mt76: mt7925: pass mlink to sta_amsdu_tlv()
wifi: mt76: mt7925: pass WCID indices to bss_basic_tlv()
wifi: mt76: mt7925: pass mlink and mconf to sta_mld_tlv()
wifi: mt76: mt7925: pass mlink to mcu_sta_update()
wifi: mt76: mt7925: resolve primary mlink via def_wcid
wifi: mt76: mt7925: pass mlink to mac_link_sta_remove()
wifi: mt76: mt7925: pass mlink to sta_hdr_trans_tlv()
wifi: mt76: mt7925: validate mlink in sta_hdr_trans_tlv()
wifi: mt76: mt7925: pass mlink to wtbl_update_hdr_trans()
wifi: mt76: mt7925: pass mlink to set_link_key()
wifi: mt76: mt7925: resolve link after acquiring mt76 mutex
wifi: mt76: mt7925: pass mconf and mlink to wtbl_update_hdr_trans()
wifi: mt76: mt7925: make WCID cleanup unconditional in sta_remove_links()
wifi: mt76: mt7925: unwind WCID setup on link STA add failure
wifi: mt76: mt7925: drop WCID reinit after publish
wifi: mt76: mt7925: move WCID teardown into link_sta_remove()
wifi: mt76: mt7925: switch link STA allocation to RCU lifetime
wifi: mt76: mt7925: publish msta->link after successful link add
wifi: mt76: mt7925: host-only unwind published links on add failure
Shayne Chen (8):
wifi: mt76: mt7996: extend CSA and CCA support for MLO
wifi: mt76: mt7996: add duplicated WTBL command
wifi: mt76: mt7996: fix iface combination for different chipsets
wifi: mt76: mt7996: add variant for MT7992 chipsets
wifi: mt76: mt7996: fix wrong DMAD length when using MAC TXP
wifi: mt76: mt7996: Account active links in valid_links fields
wifi: mt76: mt7996: Move mlink deallocation in mt7996_vif_link_remove()
wifi: mt76: mt7996: Add mcu APIs to enable/disable vif links.
StanleyYP Wang (10):
wifi: mt76: mt7996: fix the behavior of radar detection
wifi: mt76: mt7996: set specific BSSINFO and STAREC commands after channel switch
wifi: mt76: mt7996: abort CCA when CSA is starting
wifi: mt76: mt7996: offload radar threshold initialization
wifi: mt76: add external EEPROM support for mt799x chipsets
wifi: mt76: mt7996: apply calibration-free data from OTP
wifi: mt76: mt7996: fix struct mt7996_mcu_uni_event
wifi: mt76: avoid to set ACK for MCU command if wait_resp is not set
wifi: mt76: mt7996: fix queue pause after scan due to wrong channel switch reason
wifi: mt76: mt7996: fix issues with manually triggered radar detection
Zac Bowling (1):
wifi: mt76: fix list corruption in mt76_wcid_cleanup
Zilin Guan (1):
wifi: mt76: Fix memory leak after mt76_connac_mcu_alloc_sta_req()
Ziyi Guo (1):
wifi: mt76: add missing lock protection in mt76_sta_state for sta_event callback
Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml | 21 ++
drivers/net/wireless/mediatek/mt76/channel.c | 39 ++-
drivers/net/wireless/mediatek/mt76/dma.c | 33 +-
drivers/net/wireless/mediatek/mt76/dma.h | 4 +-
drivers/net/wireless/mediatek/mt76/eeprom.c | 154 ++++++---
drivers/net/wireless/mediatek/mt76/mac80211.c | 230 ++++++++++++-
drivers/net/wireless/mediatek/mt76/mcu.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76.h | 47 ++-
drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 15 -
drivers/net/wireless/mediatek/mt76/mt7615/main.c | 7 +-
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 47 +++
drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 5 +-
drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 2 -
drivers/net/wireless/mediatek/mt76/mt76_connac.h | 11 +-
drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 28 +-
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 46 ++-
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 15 +-
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 +
drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 +
drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 13 -
drivers/net/wireless/mediatek/mt76/mt7915/main.c | 9 +-
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 66 +++-
drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 11 +
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 4 +
drivers/net/wireless/mediatek/mt76/mt7921/init.c | 4 +-
drivers/net/wireless/mediatek/mt76/mt7921/main.c | 29 +-
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 3 +
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 16 +
drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 70 +++-
drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c | 6 +-
drivers/net/wireless/mediatek/mt76/mt7921/sdio.c | 4 +
drivers/net/wireless/mediatek/mt76/mt7925/init.c | 2 +
drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 18 +-
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 394 ++++++++++++++++++----
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 194 ++++++-----
drivers/net/wireless/mediatek/mt76/mt7925/mcu.h | 7 +
drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h | 13 +-
drivers/net/wireless/mediatek/mt76/mt7925/regd.c | 3 +-
drivers/net/wireless/mediatek/mt76/mt792x.h | 7 +
drivers/net/wireless/mediatek/mt76/mt792x_core.c | 14 +-
drivers/net/wireless/mediatek/mt76/mt792x_dma.c | 18 +-
drivers/net/wireless/mediatek/mt76/mt792x_mac.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt792x_regs.h | 6 +
drivers/net/wireless/mediatek/mt76/mt792x_usb.c | 51 ++-
drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c | 36 +-
drivers/net/wireless/mediatek/mt76/mt7996/dma.c | 208 +++++++-----
drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 64 ++--
drivers/net/wireless/mediatek/mt76/mt7996/init.c | 110 +++++--
drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 161 +++------
drivers/net/wireless/mediatek/mt76/mt7996/mac.h | 5 -
drivers/net/wireless/mediatek/mt76/mt7996/main.c | 439 +++++++++++++++++++------
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 823 ++++++++++++++++++++++++++++++++++++++--------
drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 112 ++++++-
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 70 +++-
drivers/net/wireless/mediatek/mt76/mt7996/npu.c | 469 ++++++++++++++++++++------
drivers/net/wireless/mediatek/mt76/mt7996/regs.h | 11 +
drivers/net/wireless/mediatek/mt76/npu.c | 37 ++-
drivers/net/wireless/mediatek/mt76/scan.c | 70 +++-
drivers/net/wireless/mediatek/mt76/tx.c | 34 +-
drivers/net/wireless/mediatek/mt7601u/mcu.c | 15 +-
drivers/net/wireless/mediatek/mt7601u/usb.h | 1 +
61 files changed, 3368 insertions(+), 969 deletions(-)
^ permalink raw reply
* RE: [PATCH v2] wifi: rtw89: usb: fix TX flow control by tracking in-flight URBs
From: Ping-Ke Shih @ 2026-03-23 9:31 UTC (permalink / raw)
To: Lucid Duck, linux-wireless@vger.kernel.org; +Cc: Bitterblue Smith
In-Reply-To: <20260321040000.31192-1-lucid_duck@justthetip.ca>
Lucid Duck <lucid_duck@justthetip.ca> wrote:
> From: Lucid Duck <lucid_duck@justthetip.ca>
> Date: Thu, 20 Mar 2026 20:00:00 -0700
> Subject: [PATCH v2] wifi: rtw89: usb: fix TX flow control by tracking
> in-flight URBs
What is your mailer? Not 'git send-email'?
I'm not sure if I can apply this by patchwork tool.
>
> rtw89_usb_ops_check_and_reclaim_tx_resource() returns a hardcoded
> placeholder value (42) instead of actual TX resource availability.
> This violates mac80211's flow control contract, preventing backpressure
> and causing uncontrolled URB accumulation under sustained TX load.
>
> Fix by adding per-channel atomic counters (tx_inflight[]) that track
> in-flight URBs:
>
> - Increment before usb_submit_urb() with rollback on failure
> - Decrement in completion callback
> - Return (MAX_URBS - inflight) to mac80211, or 0 when at capacity
> - Exclude firmware command channel (CH12) from tracking
>
> The pre-increment pattern prevents a race where the USB core completes
> the URB (possibly on another CPU) before the submitting code increments
> the counter.
>
> Tested on D-Link DWA-X1850 (RTL8832AU), kernel 6.18.3:
>
> Unpatched -> Patched
> USB3 5GHz DL: 494 -> 709 Mbps (+44%)
> USB3 5GHz retx: 8 -> 1 (-88%)
> USB3 2.4GHz DL: 54 -> 68 Mbps (+25%)
> USB2 5GHz DL: 196 -> 225 Mbps (+15%)
> USB2 2.4GHz DL: 123 -> 131 Mbps (+6%)
As this patch does TX flow control, could you share the uplink data
as well?
>
> Signed-off-by: Lucid Duck <lucid_duck@justthetip.ca>
> ---
> Resending v2. This was prepared in late January after addressing v1
> review feedback, but the send failed silently (SMTP misconfiguration)
> and never appeared on lore.kernel.org. Apologies for the delay.
>
> Changes since v1:
> - Removed duplicate "TX flow control" comment (Ping-Ke Shih)
> - Added test results to commit message (Ping-Ke Shih)
>
> Bitterblue's CH12 question from v1: the CH12 guards in tx_kick_off()
> and write_port_complete() are a matched pair. tx_kick_off() skips
> atomic_inc for CH12, so the completion handler must skip atomic_dec
> to match. Removing only the completion side causes counter underflow.
>
> Additional validation: 100-iteration stress test, 50-iteration
> teardown (rmmod/modprobe under load), 10x hot-unplug during active
> TX, and 30-minute soak -- all pass with counters balanced at idle.
>
> The 32-URB-per-channel limit is based on similar USB wireless drivers
> (mt76, ath9k_htc). The fixed value works well for both USB2 and USB3.
Can increasing 32 get better performance? The stress test with small
packets might yield low throughput? (Just a question)
>
> drivers/net/wireless/realtek/rtw89/usb.c | 26 ++++++++++++++++++-----
> drivers/net/wireless/realtek/rtw89/usb.h | 6 ++++++
> 2 files changed, 27 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/wireless/realtek/rtw89/usb.c
> b/drivers/net/wireless/realtek/rtw89/usb.c
> index eb489df..faafa3c 100644
> --- a/drivers/net/wireless/realtek/rtw89/usb.c
> +++ b/drivers/net/wireless/realtek/rtw89/usb.c
> @@ -161,16 +161,25 @@ static u32
> rtw89_usb_ops_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
> u8 txch)
> {
> + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
> + int inflight;
> +
> + /* Firmware command channel is not tracked */
> if (txch == RTW89_TXCH_CH12)
> return 1;
>
> - return 42; /* TODO some kind of calculation? */
> + inflight = atomic_read(&rtwusb->tx_inflight[txch]);
> + if (inflight >= RTW89_USB_MAX_TX_URBS_PER_CH)
Out of curiosity. Is it possible inflight > RTW89_USB_MAX_TX_URBS_PER_CH?
> + return 0;
> +
> + return RTW89_USB_MAX_TX_URBS_PER_CH - inflight;
> }
>
> static void rtw89_usb_write_port_complete(struct urb *urb)
> {
> struct rtw89_usb_tx_ctrl_block *txcb = urb->context;
> struct rtw89_dev *rtwdev = txcb->rtwdev;
> + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
> struct ieee80211_tx_info *info;
> struct rtw89_txwd_body *txdesc;
> struct sk_buff *skb;
> @@ -229,6 +238,10 @@ static void rtw89_usb_write_port_complete(struct urb *urb)
> break;
> }
>
> + /* Decrement in-flight counter (skip firmware command channel) */
> + if (txcb->txch != RTW89_TXCH_CH12)
> + atomic_dec(&rtwusb->tx_inflight[txcb->txch]);
> +
> kfree(txcb);
> }
>
> @@ -306,9 +319,17 @@ static void rtw89_usb_ops_tx_kick_off(struct rtw89_dev
> *rtwdev, u8 txch)
>
> skb_queue_tail(&txcb->tx_ack_queue, skb);
>
> + /* Increment BEFORE submit to avoid race with completion */
> + if (txch != RTW89_TXCH_CH12)
> + atomic_inc(&rtwusb->tx_inflight[txch]);
> +
> ret = rtw89_usb_write_port(rtwdev, txch, skb->data, skb->len,
> txcb);
> if (ret) {
> + /* Rollback increment on failure */
> + if (txch != RTW89_TXCH_CH12)
> + atomic_dec(&rtwusb->tx_inflight[txch]);
> +
> if (ret != -ENODEV)
> rtw89_err(rtwdev, "write port txch %d failed:
> %d\n",
> txch, ret);
> @@ -666,8 +687,10 @@ static void rtw89_usb_init_tx(struct rtw89_dev *rtwdev)
> struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
> int i;
>
> - for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++)
> + for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) {
> skb_queue_head_init(&rtwusb->tx_queue[i]);
> + atomic_set(&rtwusb->tx_inflight[i], 0);
> + }
> }
>
> static void rtw89_usb_deinit_tx(struct rtw89_dev *rtwdev)
> diff --git a/drivers/net/wireless/realtek/rtw89/usb.h
> b/drivers/net/wireless/realtek/rtw89/usb.h
> index 9f554b5..1459122 100644
> --- a/drivers/net/wireless/realtek/rtw89/usb.h
> +++ b/drivers/net/wireless/realtek/rtw89/usb.h
> @@ -20,6 +20,9 @@
> #define RTW89_MAX_ENDPOINT_NUM 9
> #define RTW89_MAX_BULKOUT_NUM 7
>
> +/* TX flow control: max in-flight URBs per channel */
I think the code self-explain this already. No need this comment.
It'd be helpful if you can explain how you decide 32.
(In commit message, you mentioned this imitate other drivers, so
no need comment about that.)
> +#define RTW89_USB_MAX_TX_URBS_PER_CH 32
> +
> struct rtw89_usb_info {
> u32 usb_host_request_2;
> u32 usb_wlan0_1;
> @@ -63,6 +66,9 @@ struct rtw89_usb {
> struct usb_anchor tx_submitted;
>
> struct sk_buff_head tx_queue[RTW89_TXCH_NUM];
> +
> + /* TX flow control: track in-flight URBs per channel */
I'd not prefer this comment neither.
> + atomic_t tx_inflight[RTW89_TXCH_NUM];
> };
>
> static inline struct rtw89_usb *rtw89_usb_priv(struct rtw89_dev *rtwdev)
> --
> 2.53.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- 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