Linux wireless drivers development
 help / color / mirror / Atom feed
* RE: [RFC PATCH v3 3/4] wifi: rtl8xxxu: update max report mac id on station add / remove for 8188e chips
From: Ping-Ke Shih @ 2026-03-16  7:07 UTC (permalink / raw)
  To: Georg Müller, Jes.Sorensen@gmail.com,
	rtl8821cerfe2@gmail.com
  Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <20260313135321.3196688-4-georgmueller@gmx.net>

Georg Müller <georgmueller@gmx.net> wrote:

remember to add commit messages when you send formal patch.

> 
> ---
>  drivers/net/wireless/realtek/rtl8xxxu/core.c | 23 +++++++++++++++++++-
>  1 file changed, 22 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c
> b/drivers/net/wireless/realtek/rtl8xxxu/core.c
> index 5ad23c5c9305..15fc4843edb2 100644
> --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c
> +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c
> @@ -3884,6 +3884,15 @@ void rtl8xxxu_init_burst(struct rtl8xxxu_priv *priv)
>         rtl8xxxu_write8(priv, REG_RSV_CTRL, val8);
>  }
> 
> +static u8 rtl8xxxu_max_acquired_macid(struct rtl8xxxu_priv *priv)
> +{
> +       u8 macid;
> +
> +       macid = find_last_bit(priv->mac_id_map, RTL8XXXU_MAX_MAC_ID_NUM);
> +
> +       return macid;
> +}
> +
>  static u8 rtl8xxxu_acquire_macid(struct rtl8xxxu_priv *priv)
>  {
>         u8 macid;
> @@ -7499,6 +7508,7 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw,
>         struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info
> *)sta->drv_priv;
>         struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
>         struct rtl8xxxu_priv *priv = hw->priv;
> +       u8 max_mac_id;
> 
>         mutex_lock(&priv->sta_mutex);
>         ewma_rssi_init(&sta_info->avg_rssi);
> @@ -7510,6 +7520,11 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw,
>                         return -ENOSPC;
>                 }
> 
> +               if (priv->rtl_chip == RTL8188E) {
> +                       max_mac_id = rtl8xxxu_max_acquired_macid(priv);
> +                       rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL + 1,
> max_mac_id + 1);
> +               }
> +
>                 rtl8xxxu_refresh_rate_mask(priv, 0, sta, true);
>                 priv->fops->report_connect(priv, sta_info->macid,
> H2C_MACID_ROLE_STA, true);
>         } else {
> @@ -7535,10 +7550,16 @@ static int rtl8xxxu_sta_remove(struct ieee80211_hw *hw,
>  {
>         struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info
> *)sta->drv_priv;
>         struct rtl8xxxu_priv *priv = hw->priv;
> +       u8 max_mac_id;
> 
>         mutex_lock(&priv->sta_mutex);
> -       if (vif->type == NL80211_IFTYPE_AP)
> +       if (vif->type == NL80211_IFTYPE_AP) {
>                 rtl8xxxu_release_macid(priv, sta_info->macid);
> +               if (priv->rtl_chip == RTL8188E) {
> +                       max_mac_id = rtl8xxxu_max_acquired_macid(priv);
> +                       rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL + 1,
> max_mac_id + 1);
> +               }
> +       }

At first glance, I'd say should we consider STA+AP concurrent case? 
Because days ago, we talked about that in another thread. 

It looks like MAC ID is another problem for concurrent case, because
rtl8xxxu_max_acquired_macid() returns MAC ID starting from 0.

But special MAC IDs are defined for non-AP vif:

#define RTL8XXXU_BC_MC_MACID	0
#define RTL8XXXU_BC_MC_MACID1	1

(But this is not scope of this patch.)

>         mutex_unlock(&priv->sta_mutex);
> 
>         return 0;
> --
> 2.53.0
> 


^ permalink raw reply

* Re: [PATCH v2 02/15] firmware: qcom: Add a generic PAS service
From: Krzysztof Kozlowski @ 2026-03-16  7:51 UTC (permalink / raw)
  To: Sumit Garg, linux-arm-msm, devicetree, dri-devel, freedreno,
	linux-media, netdev, linux-wireless, ath12k, linux-remoteproc
  Cc: andersson, konradybcio, robh, krzk+dt, conor+dt, robin.clark,
	sean, akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
	airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
	elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
	mathieu.poirier, trilokkumar.soni, mukesh.ojha, pavan.kondeti,
	jorge.ramirez, tonyh, vignesh.viswanathan, srinivas.kandagatla,
	amirreza.zarrabi, jens.wiklander, op-tee, apurupa, skare,
	linux-kernel, Sumit Garg
In-Reply-To: <20260312062756.694390-3-sumit.garg@kernel.org>

On 12/03/2026 07:27, Sumit Garg wrote:
> From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> 
> Qcom platforms has the legacy of using non-standard SCM calls
> splintered over the various kernel drivers. These SCM calls aren't
> compliant with the standard SMC calling conventions which is a
> prerequisite to enable migration to the FF-A specifications from Arm.
> 
> OP-TEE as an alternative trusted OS to Qualcomm TEE (QTEE) can't
> support these non-standard SCM calls. And even for newer architectures
> with S-EL2 and Hafnium support, QTEE won't be able to support SCM
> calls either with FF-A requirements coming in. And with both OP-TEE
> and QTEE drivers well integrated in the TEE subsystem, it makes further
> sense to reuse the TEE bus client drivers infrastructure.
> 
> The added benefit of TEE bus infrastructure is that there is support
> for discoverable/enumerable services. With that client drivers don't
> have to manually invoke a special SCM call to know the service status.
> 
> So enable the generic Peripheral Authentication Service (PAS) provided
> by the firmware. It acts as the common layer with different TZ
> backends plugged in whether it's an SCM implementation or a proper
> TEE bus based PAS service implementation.
> 
> Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> ---
>  drivers/firmware/qcom/Kconfig          |   8 +
>  drivers/firmware/qcom/Makefile         |   1 +
>  drivers/firmware/qcom/qcom_pas.c       | 298 +++++++++++++++++++++++++
>  drivers/firmware/qcom/qcom_pas.h       |  53 +++++
>  include/linux/firmware/qcom/qcom_pas.h |  41 ++++
>  5 files changed, 401 insertions(+)
>  create mode 100644 drivers/firmware/qcom/qcom_pas.c
>  create mode 100644 drivers/firmware/qcom/qcom_pas.h
>  create mode 100644 include/linux/firmware/qcom/qcom_pas.h
> 
> diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
> index b477d54b495a..8653639d06db 100644
> --- a/drivers/firmware/qcom/Kconfig
> +++ b/drivers/firmware/qcom/Kconfig
> @@ -6,6 +6,14 @@
>  
>  menu "Qualcomm firmware drivers"
>  
> +config QCOM_PAS
> +	tristate
> +	help
> +	  Enable the generic Peripheral Authentication Service (PAS) provided
> +	  by the firmware. It acts as the common layer with different TZ
> +	  backends plugged in whether it's an SCM implementation or a proper
> +	  TEE bus based PAS service implementation.
> +
>  config QCOM_SCM
>  	select QCOM_TZMEM
>  	tristate
> diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
> index 0be40a1abc13..dc5ab45f906a 100644
> --- a/drivers/firmware/qcom/Makefile
> +++ b/drivers/firmware/qcom/Makefile
> @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
>  obj-$(CONFIG_QCOM_TZMEM)	+= qcom_tzmem.o
>  obj-$(CONFIG_QCOM_QSEECOM)	+= qcom_qseecom.o
>  obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
> +obj-$(CONFIG_QCOM_PAS)		+= qcom_pas.o
> diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c
> new file mode 100644
> index 000000000000..beb1bae55546
> --- /dev/null
> +++ b/drivers/firmware/qcom/qcom_pas.c
> @@ -0,0 +1,298 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <linux/device/devres.h>
> +#include <linux/firmware/qcom/qcom_pas.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include "qcom_pas.h"
> +
> +struct qcom_pas_ops *ops_ptr;

Same comment as before. Don't create singletons. And for sure not global
ones.

Best regards,
Krzysztof

^ permalink raw reply

* [wireless:for-next] BUILD SUCCESS 7d73872d949c488a1d7c308031d6a9d89b5e0a8b
From: kernel test robot @ 2026-03-16  7:56 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git for-next
branch HEAD: 7d73872d949c488a1d7c308031d6a9d89b5e0a8b  wifi: mac80211: check tdls flag in ieee80211_tdls_oper

elapsed time: 762m

configs tested: 60
configs skipped: 0

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                   allnoconfig    gcc-15.2.0
alpha                  allyesconfig    gcc-15.2.0
arc                    allmodconfig    gcc-15.2.0
arc                     allnoconfig    gcc-15.2.0
arc                    allyesconfig    gcc-15.2.0
arm                     allnoconfig    clang-23
arm                    allyesconfig    gcc-15.2.0
arm64                  allmodconfig    clang-19
arm64                   allnoconfig    gcc-15.2.0
csky                   allmodconfig    gcc-15.2.0
csky                    allnoconfig    gcc-15.2.0
hexagon                allmodconfig    clang-17
hexagon                 allnoconfig    clang-23
i386                   allmodconfig    gcc-14
i386                    allnoconfig    gcc-14
i386                   allyesconfig    gcc-14
loongarch              allmodconfig    clang-19
loongarch               allnoconfig    clang-23
m68k                   allmodconfig    gcc-15.2.0
m68k                    allnoconfig    gcc-15.2.0
m68k                   allyesconfig    gcc-15.2.0
microblaze              allnoconfig    gcc-15.2.0
microblaze             allyesconfig    gcc-15.2.0
mips                   allmodconfig    gcc-15.2.0
mips                    allnoconfig    gcc-15.2.0
mips                   allyesconfig    gcc-15.2.0
nios2                  allmodconfig    gcc-11.5.0
nios2                   allnoconfig    gcc-11.5.0
openrisc               allmodconfig    gcc-15.2.0
openrisc                allnoconfig    gcc-15.2.0
parisc                 allmodconfig    gcc-15.2.0
parisc                  allnoconfig    gcc-15.2.0
parisc                 allyesconfig    gcc-15.2.0
powerpc                allmodconfig    gcc-15.2.0
powerpc                 allnoconfig    gcc-15.2.0
riscv                  allmodconfig    clang-23
riscv                   allnoconfig    gcc-15.2.0
riscv                  allyesconfig    clang-16
s390                   allmodconfig    clang-18
s390                    allnoconfig    clang-23
s390                   allyesconfig    gcc-15.2.0
sh                     allmodconfig    gcc-15.2.0
sh                      allnoconfig    gcc-15.2.0
sh                     allyesconfig    gcc-15.2.0
sparc                   allnoconfig    gcc-15.2.0
sparc       randconfig-001-20260316    gcc-8.5.0
sparc       randconfig-002-20260316    gcc-12.5.0
sparc64                allmodconfig    clang-23
sparc64     randconfig-001-20260316    gcc-8.5.0
sparc64     randconfig-002-20260316    gcc-15.2.0
um                     allmodconfig    clang-19
um                      allnoconfig    clang-23
um                     allyesconfig    gcc-14
um          randconfig-001-20260316    gcc-14
x86_64                 allmodconfig    clang-20
x86_64                  allnoconfig    clang-20
x86_64                 allyesconfig    clang-20
x86_64                rhel-9.4-rust    clang-20
xtensa                  allnoconfig    gcc-15.2.0
xtensa                 allyesconfig    gcc-15.2.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* [REGRESSION] mac80211 WARN during CSA finalize on mt7915e after 20240129194108.bad8ec1e76c8
From: Kaushal Kansara @ 2026-03-16  8:11 UTC (permalink / raw)
  To: johannes
  Cc: linux-wireless, miriam.rachel.korenblit, johannes.berg,
	kaushal.kansara

Hi all,

I’m reporting a regression seen on mt7915e during AP channel switch
handling and it is related to:

https://lore.kernel.org/all/20240129194108.bad8ec1e76c8.I12287452f42c54baf75821e75491cf6d021af20a@changeid/#t


Environment:


Kernel: 6.6.116

Driver/chipset: mt7915e

Platform: Sophos XGS

Trigger: concurrent AP CSA activity (e.g. WLAN9/WLAN10)

Observed warning:


WARNING at chan.c:92

Function in trace: ieee80211_vif_use_reserved_switch

Worker context: ieee80211_csa_finalize_work

Relevant log excerpt:


WLAN9: IEEE 802.11 driver starting channel switch: ... width=3 (80
MHz), cf1=5210, cf2=0

WLAN10: IEEE 802.11 driver starting channel switch: ... width=3 (80
MHz), cf1=5210, cf2=0

WARNING: CPU: 2 PID: 8713 at linux-kernel/net/mac80211/chan.c#L92
ieee80211_vif_use_reserved_switch+0x546/0x8d0 [mac80211]

Call trace:

ieee80211_link_use_reserved_context

__ieee80211_csa_finalize

ieee80211_csa_finalize_work

process_one_work

worker_thread


I can consistently reproduce this under CSA churn; please let me know
if you want full dmesg, .config, or additional instrumentation around
reserved channel-context transitions.


If I revert this patch, the warning goes away.

#regzbot introduced: 20240129194108.bad8ec1e76c8

#regzbot title: mac80211 WARN in ieee80211_vif_use_reserved_switch on
mt7915e during CSA finalize

#regzbot link: https://lore.kernel.org/all/20240129194108.bad8ec1e76c8.I12287452f42c54baf75821e75491cf6d021af20a@changeid/#t


Thanks,

Kaushal Kansara

^ permalink raw reply

* Re: [PATCH v4] wifi: ath9k: Obtain system GPIOS from descriptors
From: Bartosz Golaszewski @ 2026-03-16  9:09 UTC (permalink / raw)
  To: Linus Walleij
  Cc: linux-wireless, brcm80211-dev-list.pdl, linux-gpio, Kalle Valo,
	Andy Shevchenko, Arnd Bergmann, Alban Bedel, Bartosz Golaszewski,
	Toke Høiland-Jørgensen, Michał Kępień
In-Reply-To: <20260313-descriptors-wireless-v4-1-07ab47c89a98@kernel.org>

On Fri, 13 Mar 2026 22:53:43 +0100, Linus Walleij <linusw@kernel.org> said:
> The ath9k has an odd use of system-wide GPIOs: if the chip
> does not have internal GPIO capability, it will try to obtain a
> GPIO line from the system GPIO controller:
>
>   if (BIT(gpio) & ah->caps.gpio_mask)
>         ath9k_hw_gpio_cfg_wmac(...);
>   else if (AR_SREV_SOC(ah))
>         ath9k_hw_gpio_cfg_soc(ah, gpio, out, label);
>
> Where ath9k_hw_gpio_cfg_soc() will attempt to issue
> gpio_request_one() passing the local GPIO number of the controller
> (0..31) to gpio_request_one().
>
> This is somewhat peculiar and possibly even dangerous: there is
> nowadays no guarantee of the numbering of these system-wide
> GPIOs, and assuming that GPIO 0..31 as used by ath9k would
> correspond to GPIOs 0..31 on the system as a whole seems a bit
> wild.
>
> Register all 32 GPIOs at index 0..31 directly in the ATH79K
> GPIO driver and associate with the NULL device (making them
> widely available) if and only if we are probing ATH79K wifi
> from the AHB bus (used for SoCs). We obtain these offsets from
> the NULL device if necessary.
>
> These GPIOs should ideally be defined in the device tree
> instead, but we have no control over that for the legacy
> code path.
>
> Testcompiled with the ath79 defconfig.
>
> Reported-by: Michał Kępień <kernel@kempniu.pl>
> Acked-by: Toke Høiland-Jørgensen <toke@toke.dk>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Linus Walleij <linusw@kernel.org>
> ---
> This patch set is a long standing attempt to get rid of the global
> GPIO numbers from the ath9k Wireless driver.
>
> Maybe Kalle can merge this to the Wireless tree if we agree on this
> hack solution.
>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> Changes in v4:
> - Fix review comments from Andy.
> - Collect ACKs.

I think this did not work. :)

> - Link to v3: https://lore.kernel.org/r/20260312-descriptors-wireless-v3-1-5230e0870c31@kernel.org
>
> Changes in v3:
> - Rebased on kernel v7.0-rc1
> - Fix up issues as pointed out by Michał Kępień
> - Link to v2: https://lore.kernel.org/r/20240423-descriptors-wireless-v2-1-6d1d03b30bfa@linaro.org
>
> Changes in v2:
> - Define all the descriptors directly in the ATH79K
>   GPIO driver in case the driver want to request them directly.
> - Link to v1: https://lore.kernel.org/r/20240131-descriptors-wireless-v1-0-e1c7c5d68746@linaro.org
> ---

Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH v4] wifi: ath9k: Obtain system GPIOS from descriptors
From: Andy Shevchenko @ 2026-03-16  9:29 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, linux-wireless, brcm80211-dev-list.pdl, linux-gpio,
	Kalle Valo, Arnd Bergmann, Alban Bedel, Bartosz Golaszewski,
	Toke Høiland-Jørgensen, Michał Kępień
In-Reply-To: <CAMRc=MdJXhXyid1a4ycmKv6nwOf3FYd=rFEaBqQ7k3SFq_j4FQ@mail.gmail.com>

On Mon, Mar 16, 2026 at 05:09:22AM -0400, Bartosz Golaszewski wrote:
> On Fri, 13 Mar 2026 22:53:43 +0100, Linus Walleij <linusw@kernel.org> said:
> > The ath9k has an odd use of system-wide GPIOs: if the chip
> > does not have internal GPIO capability, it will try to obtain a
> > GPIO line from the system GPIO controller:
> >
> >   if (BIT(gpio) & ah->caps.gpio_mask)
> >         ath9k_hw_gpio_cfg_wmac(...);
> >   else if (AR_SREV_SOC(ah))
> >         ath9k_hw_gpio_cfg_soc(ah, gpio, out, label);
> >
> > Where ath9k_hw_gpio_cfg_soc() will attempt to issue
> > gpio_request_one() passing the local GPIO number of the controller
> > (0..31) to gpio_request_one().
> >
> > This is somewhat peculiar and possibly even dangerous: there is
> > nowadays no guarantee of the numbering of these system-wide
> > GPIOs, and assuming that GPIO 0..31 as used by ath9k would
> > correspond to GPIOs 0..31 on the system as a whole seems a bit
> > wild.
> >
> > Register all 32 GPIOs at index 0..31 directly in the ATH79K
> > GPIO driver and associate with the NULL device (making them
> > widely available) if and only if we are probing ATH79K wifi
> > from the AHB bus (used for SoCs). We obtain these offsets from
> > the NULL device if necessary.
> >
> > These GPIOs should ideally be defined in the device tree
> > instead, but we have no control over that for the legacy
> > code path.
> >
> > Testcompiled with the ath79 defconfig.
> >
> > Reported-by: Michał Kępień <kernel@kempniu.pl>
> > Acked-by: Toke Høiland-Jørgensen <toke@toke.dk>
> > Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > Signed-off-by: Linus Walleij <linusw@kernel.org>
> > ---
> > This patch set is a long standing attempt to get rid of the global
> > GPIO numbers from the ath9k Wireless driver.
> >
> > Maybe Kalle can merge this to the Wireless tree if we agree on this
> > hack solution.
> >
> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> > ---
> > Changes in v4:
> > - Fix review comments from Andy.
> > - Collect ACKs.
> 
> I think this did not work. :)

It's just extra SoB where it's not needed, but the tags are collected in
the proper commit message.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* Re: [RFC PATCH v3 1/4] wifi: rtl8xxxu: move dynamic_tx_rpt_timing_counter from ra_info to priv
From: Georg Müller @ 2026-03-16  9:30 UTC (permalink / raw)
  To: Ping-Ke Shih, Jes.Sorensen@gmail.com, rtl8821cerfe2@gmail.com
  Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <fbd2420985544f858374468d25e848f5@realtek.com>


Am 16.03.26 um 07:17 schrieb Ping-Ke Shih:
> 
> Georg Müller <georgmueller@gmx.net> wrote:
>> dynamic_tx_rpt_timing_counter is not per mac_id, but used across all
>> mac_ids.
> 
> I don't know the purpose of dynamic_tx_rpt_timing_counter. Could you
> share your study?
> 
It is used globally (not per mac) like this in the vendor driver as well [1][2].
Bitterblue Smith gave the hint that this should not be per macid [3], so it should move
out of struct ra_info.

[1] https://github.com/lwfinger/rtl8188eu/blob/master/hal/Hal8188ERateAdaptive.c#L248
[2] https://github.com/lwfinger/rtl8188eu/blob/v5.2.2.4/hal8188erateadaptive.c#L285
[3] https://lore.kernel.org/linux-wireless/938ae608-a865-4056-06de-c230d74e1847@gmail.com/


^ permalink raw reply

* Re: [PATCH ath-next v2] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Nicolas Escande @ 2026-03-16  9:35 UTC (permalink / raw)
  To: Baochen Qiang, Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <55358f82-f0ba-4671-90ed-8061f6ffbabf@oss.qualcomm.com>

On Mon Mar 16, 2026 at 3:27 AM CET, Baochen Qiang wrote:
[...]
> or alternately you can define ath12k_wmi_tb in wmi.c and add alloc/free functions in
> wmi.c, then call them in core.c. this helps modularity IMO?

I'll add new functions to wmi.c and make ath12k_wmi_tb static to that file.
>
> either way works for me!
>
[...]
>> +static int ath12k_init(void)
>> +{
>> +	ath12k_wmi_tb = __alloc_percpu(WMI_TAG_MAX * sizeof(void *),
>> +				       __alignof__(void *));
>> +	if (!ath12k_wmi_tb) {
>> +		pr_warn("Failed to alloc ath12k WMI tb\n");
>
> generally we don't log memory allocation failure

sure will fix

>
>> +		return -ENOMEM;
>> +	}
>> +
>> +	return 0;
>> +}

[...]

>> @@ -9215,11 +9127,8 @@ static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab,
>>  	ev = tb[WMI_TAG_MLO_TEARDOWN_COMPLETE];
>>  	if (!ev) {
>>  		ath12k_warn(ab, "failed to fetch teardown complete event\n");
>> -		kfree(tb);
>>  		return;
>
> nit: better to remove return as well

Indeed this slipped through the cracks will fix

>
>>  	}
>> -
>> -	kfree(tb);
>>  }
>>  
>>  #ifdef CONFIG_ATH12K_DEBUGFS


^ permalink raw reply

* Re: [RFC PATCH v3 2/4] wifi: rtl8xxxu: handle rate control for 8188e a per mac_id
From: Georg Müller @ 2026-03-16  9:41 UTC (permalink / raw)
  To: Ping-Ke Shih, Jes.Sorensen@gmail.com, rtl8821cerfe2@gmail.com
  Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <34bfaf9b86184047b5591d03517bcc7c@realtek.com>



Am 16.03.26 um 07:35 schrieb Ping-Ke Shih:
> Georg Müller <georgmueller@gmx.net> wrote:
>> convert member ra_info to an array with one entry per mac id. This
>> allows having different rate control settings per connected station
>> in ap mode.
>>
>> The max_macid_num is conservative. The old driver used 32 [1], some
>> other sources said 64 [2]. I have not enough adapters to test any of the
>> higher values. Given the usage of this chipset in nano dongles, I think
>> the 16 might be high enough.
>>
>> [1]
>> https://github.com/lwfinger/rtl8188eu/blob/f5d1c8df2e2d8b217ea0113bf2cf3e37d
>> f8cb716/include/sta_info.h#L28
>> [2]
>> https://lore.kernel.org/linux-wireless/27e83382-4c84-1841-c428-d1e5143ea20c@
>> gmail.com/
>>
>> Signed-off-by: Georg Müller <georgmueller@gmx.net>
>> ---
>>   drivers/net/wireless/realtek/rtl8xxxu/8188e.c | 12 ++++++------
>>   drivers/net/wireless/realtek/rtl8xxxu/core.c  | 19 ++++++++++++++-----
>>   .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h  |  3 ++-
>>   3 files changed, 22 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/8188e.c
>> b/drivers/net/wireless/realtek/rtl8xxxu/8188e.c
>> index de2837a91bbe..607ca62194fc 100644
>> --- a/drivers/net/wireless/realtek/rtl8xxxu/8188e.c
>> +++ b/drivers/net/wireless/realtek/rtl8xxxu/8188e.c
>> @@ -1468,9 +1468,8 @@ static void rtl8188e_reset_ra_counter(struct
>> rtl8xxxu_ra_info *ra)
>>          ra->nsc_down = (n_threshold_high[rate_id] + n_threshold_low[rate_id])
>>>> 1;
>>   }
>>
>> -static void rtl8188e_rate_decision(struct rtl8xxxu_ra_info *ra)
>> +static void rtl8188e_rate_decision(struct rtl8xxxu_priv *priv, struct
>> rtl8xxxu_ra_info *ra)
>>   {
>> -       struct rtl8xxxu_priv *priv = container_of(ra, struct rtl8xxxu_priv,
>> ra_info);
>>          const u8 *retry_penalty_idx_0;
>>          const u8 *retry_penalty_idx_1;
>>          const u8 *retry_penalty_up_idx;
>> @@ -1669,7 +1668,7 @@ void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv
>> *priv, struct sk_buff *s
>>          u32 *_rx_desc = (u32 *)(skb->data - sizeof(struct rtl8xxxu_rxdesc16));
>>          struct rtl8xxxu_rxdesc16 *rx_desc = (struct rtl8xxxu_rxdesc16
>> *)_rx_desc;
>>          struct device *dev = &priv->udev->dev;
>> -       struct rtl8xxxu_ra_info *ra = &priv->ra_info;
>> +       struct rtl8xxxu_ra_info *ra;
>>          u32 tx_rpt_len = rx_desc->pktlen & 0x3ff;
>>          u32 items = tx_rpt_len / TX_RPT2_ITEM_SIZE;
> 
> The 'items' should be smaller or equal to RTL8188E_MAX_MAC_ID_NUM.

I will add a check.

>>          u64 macid_valid = ((u64)_rx_desc[5] << 32) | _rx_desc[4];
>> @@ -1688,6 +1687,7 @@ void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv
>> *priv, struct sk_buff *s
>>
>>          for (macid = 0; macid < items; macid++) {
>>                  valid = false;
>> +               ra = &priv->ra_info[macid];
>>
>>                  if (macid < 64)
>>                          valid = macid_valid & BIT(macid);
>> @@ -1704,7 +1704,7 @@ void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv
>> *priv, struct sk_buff *s
>>
>>                          if (ra->total > 0) {
>>                                  if (ra->ra_stage < 5)
>> -                                       rtl8188e_rate_decision(ra);
>> +                                       rtl8188e_rate_decision(priv, ra);
>>                                  else if (ra->ra_stage == 5)
>>
>> rtl8188e_power_training_try_state(ra);
>>                                  else /* ra->ra_stage == 6 */
>> @@ -1781,7 +1781,7 @@ rtl8188e_update_rate_mask(struct rtl8xxxu_priv *priv,
>>                            u32 ramask, u8 rateid, int sgi, int txbw_40mhz,
>>                            u8 macid)
>>   {
>> -       struct rtl8xxxu_ra_info *ra = &priv->ra_info;
>> +       struct rtl8xxxu_ra_info *ra = &priv->ra_info[macid];
>>
>>          ra->rate_id = rateid;
>>          ra->rate_mask = ramask;
>> @@ -1792,7 +1792,7 @@ rtl8188e_update_rate_mask(struct rtl8xxxu_priv *priv,
>>
>>   static void rtl8188e_ra_set_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi)
>>   {
>> -       priv->ra_info.rssi_sta_ra = rssi;
>> +       priv->ra_info[macid].rssi_sta_ra = rssi;
>>   }
>>
>>   void rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info *ra)
>> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c
>> b/drivers/net/wireless/realtek/rtl8xxxu/core.c
>> index 794187d28caa..5ad23c5c9305 100644
>> --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c
>> +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c
>> @@ -3921,6 +3921,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
>>          struct device *dev = &priv->udev->dev;
>>          struct rtl8xxxu_fileops *fops = priv->fops;
>>          bool macpower;
>> +       u16 mac_id;
>>          int ret;
>>          u8 val8;
>>          u16 val16;
>> @@ -4393,9 +4394,16 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
>>                  priv->cfo_tracking.crystal_cap = priv->default_crystal_cap;
>>          }
>>
>> -       if (priv->rtl_chip == RTL8188E)
>> -               rtl8188e_ra_info_init_all(&priv->ra_info);
>> -
>> +       if (priv->rtl_chip == RTL8188E) {
>> +               priv->ra_info = kmalloc_array(RTL8188E_MAX_MAC_ID_NUM,
>> sizeof(*priv->ra_info), GFP_KERNEL);
> 
> How about devm_ series? Then, no need to free on error path or disconnection.

I didn't know about these and will change it in the next version.

>> +               if (!priv->ra_info) {
>> +                       ret = -ENOMEM;
>> +                       goto exit;
>> +               }
>> +               for (mac_id = 0; mac_id < RTL8188E_MAX_MAC_ID_NUM; mac_id++) {
>> +                       rtl8188e_ra_info_init_all(&priv->ra_info[mac_id]);
>> +               }
> 
> no need brace for single line statement.

I will change it in the next version.

>> +       }
>>          set_bit(RTL8XXXU_BC_MC_MACID, priv->mac_id_map);
>>          set_bit(RTL8XXXU_BC_MC_MACID1, priv->mac_id_map);
>>
>> @@ -5338,7 +5346,7 @@ rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct
>> ieee80211_hdr *hdr,
>>   {
>>          struct rtl8xxxu_priv *priv = hw->priv;
>>          struct device *dev = &priv->udev->dev;
>> -       struct rtl8xxxu_ra_info *ra = &priv->ra_info;
>> +       struct rtl8xxxu_ra_info *ra = &priv->ra_info[macid];
>>          u8 *qc = ieee80211_get_qos_ctl(hdr);
>>          u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
>>          u32 rate = 0;
>> @@ -7895,6 +7903,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
>>   err_set_intfdata:
>>          usb_set_intfdata(interface, NULL);
>>
>> +       kfree(priv->ra_info);
>>          kfree(priv->fw_data);
>>          mutex_destroy(&priv->usb_buf_mutex);
>>          mutex_destroy(&priv->syson_indirect_access_mutex);
>> @@ -7924,7 +7933,7 @@ static void rtl8xxxu_disconnect(struct usb_interface
>> *interface)
>>          usb_set_intfdata(interface, NULL);
>>
>>          dev_info(&priv->udev->dev, "disconnecting\n");
>> -
>> +       kfree(priv->ra_info);
>>          kfree(priv->fw_data);
>>          mutex_destroy(&priv->usb_buf_mutex);
>>          mutex_destroy(&priv->syson_indirect_access_mutex);
>> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>> b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>> index 4a744b5c1aec..9ce820ff4793 100644
>> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
>> @@ -76,6 +76,7 @@
>>   #define RTL_FW_PAGE_SIZE               4096
>>   #define RTL8XXXU_FIRMWARE_POLL_MAX     1000
>>
>> +#define RTL8188E_MAX_MAC_ID_NUM                16
>>   #define RTL8723A_CHANNEL_GROUPS                3
>>   #define RTL8723A_MAX_RF_PATHS          2
>>   #define RTL8723B_CHANNEL_GROUPS                6
>> @@ -1915,7 +1916,7 @@ struct rtl8xxxu_priv {
>>          struct rtl8xxxu_btcoex bt_coex;
>>          struct rtl8xxxu_ra_report ra_report;
>>          struct rtl8xxxu_cfo_tracking cfo_tracking;
>> -       struct rtl8xxxu_ra_info ra_info;
>> +       struct rtl8xxxu_ra_info *ra_info;
> 
> It looks like this is also 8188e specific. Could you add comment by the way?
> (but please /**/ style)

ok

>>          u8 dynamic_tx_rpt_timing_counter; // 8188e specific
>>
>>          bool led_registered;
>> --
>> 2.53.0
>>
> 


^ permalink raw reply

* [PATCH ath-next v3] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Nicolas Escande @ 2026-03-16 10:32 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless

On each WMI message received from the hardware, we alloc a temporary array
of WMI_TAG_MAX entries of type void *. This array is then populated with
pointers of parsed structs depending on the WMI type, and then freed. This
alloc can fail when memory pressure in the system is high enough.

Given the fact that it is scheduled in softirq with the system_bh_wq, we
should not be able to parse more than one WMI message per CPU at any time.

So instead lets move to a per cpu allocated array, that is reused across
calls: ath12K_wmi_tb that lives in wmi.c of the ath12K module. To alloc &
free we added two new module_init/exit functions for the module and two
new wmi functions to alloc/free this memory.

ath12k_wmi_tlv_parse_alloc() and ath12k_wmi_tlv_parse() are merged
together as it no longer allocs mem but returns the existing per-cpu one.

Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
---
changes from v2:
  - removed now superfluous return in ath12k_wmi_event_teardown_complete()
  - moved ath12k_wmi_tb declaration to wmi.c & added two functions to
    alloc / free it
  - removed useless error message on memory allocation failure

changes from v1:
  - rebased on ath-next 27401c9b1432
  - changed wording according to Jeff's comment
  - moved alloc/cleanup to new module_init/exit functions in the
    ath12k module as per Baochen's comment

changes from RFC:
  - rebased on ath-next 8e0ab5b9adb7
  - converted missing call sites ath12k_wmi_obss_color_collision_event()
    & ath12k_wmi_pdev_temperature_event()
  - changed alloc order & cleanup path in ath12k_core_alloc() as it seems
    it confused people
  - used sizeof(*tb) in ath12k_wmi_tlv_parse()
---
 drivers/net/wireless/ath/ath12k/core.c |  19 +++
 drivers/net/wireless/ath/ath12k/core.h |   1 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 200 ++++++++-----------------
 drivers/net/wireless/ath/ath12k/wmi.h  |   3 +
 4 files changed, 84 insertions(+), 139 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index c31c47fb5a73..16815a27f8f2 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -2321,5 +2321,24 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
 	return NULL;
 }
 
+static int ath12k_init(void)
+{
+	int ret;
+
+	ret = ath12k_wmi_alloc();
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void ath12k_exit(void)
+{
+	ath12k_wmi_free();
+}
+
+module_init(ath12k_init);
+module_exit(ath12k_exit);
+
 MODULE_DESCRIPTION("Driver support for Qualcomm Technologies WLAN devices");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 59c193b24764..02ee6c718621 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -19,6 +19,7 @@
 #include <linux/average.h>
 #include <linux/of.h>
 #include <linux/rhashtable.h>
+#include <linux/percpu.h>
 #include "qmi.h"
 #include "htc.h"
 #include "wmi.h"
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 8e13c3ec1cc7..b322f6375b5b 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -134,6 +134,8 @@ struct wmi_pdev_set_obss_bitmap_arg {
 	const char *label;
 };
 
+static void __percpu *ath12k_wmi_tb;
+
 static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
 	[WMI_TAG_ARRAY_BYTE] = { .min_len = 0 },
 	[WMI_TAG_ARRAY_UINT32] = { .min_len = 0 },
@@ -289,29 +291,19 @@ static int ath12k_wmi_tlv_iter_parse(struct ath12k_base *ab, u16 tag, u16 len,
 	return 0;
 }
 
-static int ath12k_wmi_tlv_parse(struct ath12k_base *ar, const void **tb,
-				const void *ptr, size_t len)
-{
-	return ath12k_wmi_tlv_iter(ar, ptr, len, ath12k_wmi_tlv_iter_parse,
-				   (void *)tb);
-}
-
 static const void **
-ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab,
-			   struct sk_buff *skb, gfp_t gfp)
+ath12k_wmi_tlv_parse(struct ath12k_base *ab, struct sk_buff *skb)
 {
 	const void **tb;
 	int ret;
 
-	tb = kzalloc_objs(*tb, WMI_TAG_MAX, gfp);
-	if (!tb)
-		return ERR_PTR(-ENOMEM);
+	tb = this_cpu_ptr(ath12k_wmi_tb);
+	memset(tb, 0, WMI_TAG_MAX * sizeof(*tb));
 
-	ret = ath12k_wmi_tlv_parse(ab, tb, skb->data, skb->len);
-	if (ret) {
-		kfree(tb);
+	ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,
+				  ath12k_wmi_tlv_iter_parse, (void *)tb);
+	if (ret)
 		return ERR_PTR(ret);
-	}
 
 	return tb;
 }
@@ -3911,9 +3903,10 @@ ath12k_wmi_obss_color_collision_event(struct ath12k_base *ab, struct sk_buff *sk
 	const struct wmi_obss_color_collision_event *ev;
 	struct ath12k_link_vif *arvif;
 	u32 vdev_id, evt_type;
+	const void **tb;
 	u64 bitmap;
 
-	const void **tb __free(kfree) = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ath12k_warn(ab, "failed to parse OBSS color collision tlv %ld\n",
 			    PTR_ERR(tb));
@@ -5714,7 +5707,7 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf
 	const struct wmi_vdev_start_resp_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5724,13 +5717,11 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf
 	ev = tb[WMI_TAG_VDEV_START_RESPONSE_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch vdev start resp ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
 	*vdev_rsp = *ev;
 
-	kfree(tb);
 	return 0;
 }
 
@@ -5809,7 +5800,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 
 	ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n");
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5819,7 +5810,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch reg chan list ext update ev\n");
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -5849,7 +5839,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 	if (num_2g_reg_rules > MAX_REG_RULES || num_5g_reg_rules > MAX_REG_RULES) {
 		ath12k_warn(ab, "Num reg rules for 2G/5G exceeds max limit (num_2g_reg_rules: %d num_5g_reg_rules: %d max_rules: %d)\n",
 			    num_2g_reg_rules, num_5g_reg_rules, MAX_REG_RULES);
-		kfree(tb);
 		return -EINVAL;
 	}
 
@@ -5859,7 +5848,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 		if (num_6g_reg_rules_ap[i] > MAX_6GHZ_REG_RULES) {
 			ath12k_warn(ab, "Num 6G reg rules for AP mode(%d) exceeds max limit (num_6g_reg_rules_ap: %d, max_rules: %d)\n",
 				    i, num_6g_reg_rules_ap[i], MAX_6GHZ_REG_RULES);
-			kfree(tb);
 			return -EINVAL;
 		}
 
@@ -5884,14 +5872,12 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 		    num_6g_reg_rules_cl[WMI_REG_VLP_AP][i] >  MAX_6GHZ_REG_RULES) {
 			ath12k_warn(ab, "Num 6g client reg rules exceeds max limit, for client(type: %d)\n",
 				    i);
-			kfree(tb);
 			return -EINVAL;
 		}
 	}
 
 	if (!total_reg_rules) {
 		ath12k_warn(ab, "No reg rules available\n");
-		kfree(tb);
 		return -EINVAL;
 	}
 
@@ -5993,7 +5979,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 						      ext_wmi_reg_rule);
 
 		if (!reg_info->reg_rules_2g_ptr) {
-			kfree(tb);
 			ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n");
 			return -ENOMEM;
 		}
@@ -6027,7 +6012,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 						      ext_wmi_reg_rule);
 
 		if (!reg_info->reg_rules_5g_ptr) {
-			kfree(tb);
 			ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n");
 			return -ENOMEM;
 		}
@@ -6046,7 +6030,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 						      ext_wmi_reg_rule);
 
 		if (!reg_info->reg_rules_6g_ap_ptr[i]) {
-			kfree(tb);
 			ath12k_warn(ab, "Unable to Allocate memory for 6g ap rules\n");
 			return -ENOMEM;
 		}
@@ -6061,7 +6044,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 							      ext_wmi_reg_rule);
 
 			if (!reg_info->reg_rules_6g_client_ptr[j][i]) {
-				kfree(tb);
 				ath12k_warn(ab, "Unable to Allocate memory for 6g client rules\n");
 				return -ENOMEM;
 			}
@@ -6096,7 +6078,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 
 	ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n");
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6107,7 +6088,7 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff *
 	const struct wmi_peer_delete_resp_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6117,7 +6098,6 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff *
 	ev = tb[WMI_TAG_PEER_DELETE_RESP_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch peer delete resp ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -6127,7 +6107,6 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff *
 	ether_addr_copy(peer_del_resp->peer_macaddr.addr,
 			ev->peer_macaddr.addr);
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6139,7 +6118,7 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab,
 	const struct wmi_vdev_delete_resp_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6149,13 +6128,11 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_VDEV_DELETE_RESP_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch vdev delete resp ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
 	*vdev_id = le32_to_cpu(ev->vdev_id);
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6167,7 +6144,7 @@ static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab,
 	const struct wmi_bcn_tx_status_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6177,14 +6154,12 @@ static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch bcn tx status ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
 	*vdev_id = le32_to_cpu(ev->vdev_id);
 	*tx_status = le32_to_cpu(ev->tx_status);
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6195,7 +6170,7 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_
 	const struct wmi_vdev_stopped_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6205,13 +6180,11 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_
 	ev = tb[WMI_TAG_VDEV_STOPPED_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch vdev stop ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
 	*vdev_id = le32_to_cpu(ev->vdev_id);
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6350,7 +6323,7 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab,
 	const struct wmi_mgmt_tx_compl_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6360,7 +6333,6 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_MGMT_TX_COMPL_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch mgmt tx compl ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -6370,7 +6342,6 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab,
 	param->ppdu_id = ev->ppdu_id;
 	param->ack_rssi = ev->ack_rssi;
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6533,7 +6504,7 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	const struct wmi_scan_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6543,7 +6514,6 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	ev = tb[WMI_TAG_SCAN_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch scan ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -6555,7 +6525,6 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	scan_evt_param->vdev_id = ev->vdev_id;
 	scan_evt_param->tsf_timestamp = ev->tsf_timestamp;
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6566,7 +6535,7 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf
 	const struct wmi_peer_sta_kickout_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6576,7 +6545,6 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf
 	ev = tb[WMI_TAG_PEER_STA_KICKOUT_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch peer sta kickout ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -6584,7 +6552,6 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf
 	arg->reason = le32_to_cpu(ev->reason);
 	arg->rssi = le32_to_cpu(ev->rssi);
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6595,7 +6562,7 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	const struct wmi_roam_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6605,7 +6572,6 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	ev = tb[WMI_TAG_ROAM_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch roam ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -6613,7 +6579,6 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	roam_ev->reason = ev->reason;
 	roam_ev->rssi = ev->rssi;
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6647,7 +6612,7 @@ static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	const struct wmi_chan_info_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6657,7 +6622,6 @@ static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	ev = tb[WMI_TAG_CHAN_INFO_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch chan info ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -6674,7 +6638,6 @@ static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	ch_info_ev->mac_clk_mhz = ev->mac_clk_mhz;
 	ch_info_ev->vdev_id = ev->vdev_id;
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6686,7 +6649,7 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	const struct wmi_pdev_bss_chan_info_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6696,7 +6659,6 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	ev = tb[WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch pdev bss chan info ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -6714,7 +6676,6 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
 	bss_ch_info_ev->rx_bss_cycle_count_low = ev->rx_bss_cycle_count_low;
 	bss_ch_info_ev->rx_bss_cycle_count_high = ev->rx_bss_cycle_count_high;
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6726,7 +6687,7 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk
 	const struct wmi_vdev_install_key_compl_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6736,7 +6697,6 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk
 	ev = tb[WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch vdev install key compl ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -6746,7 +6706,6 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk
 	arg->key_flags = le32_to_cpu(ev->key_flags);
 	arg->status = le32_to_cpu(ev->status);
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6757,7 +6716,7 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff
 	const struct wmi_peer_assoc_conf_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6767,14 +6726,12 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff
 	ev = tb[WMI_TAG_PEER_ASSOC_CONF_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch peer assoc conf ev");
-		kfree(tb);
 		return -EPROTO;
 	}
 
 	peer_assoc_conf->vdev_id = le32_to_cpu(ev->vdev_id);
 	peer_assoc_conf->macaddr = ev->peer_macaddr.addr;
 
-	kfree(tb);
 	return 0;
 }
 
@@ -6792,7 +6749,7 @@ static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *s
 	const void **tb;
 	int ret, i;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6801,7 +6758,6 @@ static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *s
 
 	ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT];
 	if (!ev) {
-		kfree(tb);
 		ath12k_warn(ab, "failed to fetch 11d new cc ev");
 		return -EPROTO;
 	}
@@ -6814,8 +6770,6 @@ static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *s
 		   ab->new_alpha2[0],
 		   ab->new_alpha2[1]);
 
-	kfree(tb);
-
 	for (i = 0; i < ab->num_radios; i++) {
 		pdev = &ab->pdevs[i];
 		ar = pdev->ar;
@@ -8567,7 +8521,7 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab,
 	const struct wmi_pdev_ctl_failsafe_chk_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -8577,7 +8531,6 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch pdev ctl failsafe check ev");
-		kfree(tb);
 		return;
 	}
 
@@ -8591,8 +8544,6 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab,
 	if (ev->ctl_failsafe_status != 0)
 		ath12k_warn(ab, "pdev ctl failsafe failure status %d",
 			    ev->ctl_failsafe_status);
-
-	kfree(tb);
 }
 
 static void
@@ -8664,7 +8615,7 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab,
 	const u32 *vdev_ids;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -8676,7 +8627,6 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab,
 
 	if (!ev || !vdev_ids) {
 		ath12k_warn(ab, "failed to fetch pdev csa switch count ev");
-		kfree(tb);
 		return;
 	}
 
@@ -8686,8 +8636,6 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab,
 		   ev->num_vdevs);
 
 	ath12k_wmi_process_csa_switch_count_event(ab, ev, vdev_ids);
-
-	kfree(tb);
 }
 
 static void
@@ -8699,7 +8647,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
 	struct ath12k *ar;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -8710,7 +8658,6 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
 
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch pdev dfs radar detected ev");
-		kfree(tb);
 		return;
 	}
 
@@ -8749,8 +8696,6 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
 
 exit:
 	rcu_read_unlock();
-
-	kfree(tb);
 }
 
 static void ath12k_tm_wmi_event_segmented(struct ath12k_base *ab, u32 cmd_id,
@@ -8761,7 +8706,7 @@ static void ath12k_tm_wmi_event_segmented(struct ath12k_base *ab, u32 cmd_id,
 	int ret;
 	u16 length;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
@@ -8772,14 +8717,11 @@ static void ath12k_tm_wmi_event_segmented(struct ath12k_base *ab, u32 cmd_id,
 	ev = tb[WMI_TAG_ARRAY_BYTE];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch ftm msg\n");
-		kfree(tb);
 		return;
 	}
 
 	length = skb->len - TLV_HDR_SIZE;
 	ath12k_tm_process_event(ab, cmd_id, ev, length);
-	kfree(tb);
-	tb = NULL;
 }
 
 static void
@@ -8792,7 +8734,7 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab,
 	int temp;
 	u32 pdev_id;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ath12k_warn(ab, "failed to parse tlv: %ld\n", PTR_ERR(tb));
 		return;
@@ -8801,15 +8743,12 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch pdev temp ev\n");
-		kfree(tb);
 		return;
 	}
 
 	temp = a_sle32_to_cpu(ev->temp);
 	pdev_id = le32_to_cpu(ev->pdev_id);
 
-	kfree(tb);
-
 	ath12k_dbg(ab, ATH12K_DBG_WMI,
 		   "pdev temperature ev temp %d pdev_id %u\n",
 		   temp, pdev_id);
@@ -8836,7 +8775,7 @@ static void ath12k_fils_discovery_event(struct ath12k_base *ab,
 	const struct wmi_fils_discovery_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab,
@@ -8848,15 +8787,12 @@ static void ath12k_fils_discovery_event(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_HOST_SWFDA_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch FILS discovery event\n");
-		kfree(tb);
 		return;
 	}
 
 	ath12k_warn(ab,
 		    "FILS discovery frame expected from host for vdev_id: %u, transmission scheduled at %u, next TBTT: %u\n",
 		    ev->vdev_id, ev->fils_tt, ev->tbtt);
-
-	kfree(tb);
 }
 
 static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
@@ -8866,7 +8802,7 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
 	const struct wmi_probe_resp_tx_status_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab,
@@ -8879,7 +8815,6 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
 	if (!ev) {
 		ath12k_warn(ab,
 			    "failed to fetch probe response transmission status event");
-		kfree(tb);
 		return;
 	}
 
@@ -8887,8 +8822,6 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
 		ath12k_warn(ab,
 			    "Probe response transmission failed for vdev_id %u, status %u\n",
 			    ev->vdev_id, ev->tx_status);
-
-	kfree(tb);
 }
 
 static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
@@ -8900,7 +8833,7 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
 	struct ath12k *ar;
 	int ret, vdev_id;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse P2P NoA TLV: %d\n", ret);
@@ -8910,10 +8843,8 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_P2P_NOA_EVENT];
 	noa = tb[WMI_TAG_P2P_NOA_INFO];
 
-	if (!ev || !noa) {
-		ret = -EPROTO;
-		goto out;
-	}
+	if (!ev || !noa)
+		return -EPROTO;
 
 	vdev_id = __le32_to_cpu(ev->vdev_id);
 
@@ -8936,8 +8867,6 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
 
 unlock:
 	rcu_read_unlock();
-out:
-	kfree(tb);
 	return ret;
 }
 
@@ -8948,7 +8877,7 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
 	const void **tb;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -8956,10 +8885,8 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
 	}
 
 	ev = tb[WMI_TAG_RFKILL_EVENT];
-	if (!ev) {
-		kfree(tb);
+	if (!ev)
 		return;
-	}
 
 	ath12k_dbg(ab, ATH12K_DBG_MAC,
 		   "wmi tlv rfkill state change gpio %d type %d radio_state %d\n",
@@ -8972,7 +8899,6 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
 	spin_unlock_bh(&ab->base_lock);
 
 	queue_work(ab->workqueue, &ab->rfkill_work);
-	kfree(tb);
 }
 
 static void
@@ -8988,7 +8914,7 @@ static void ath12k_wmi_twt_enable_event(struct ath12k_base *ab,
 	const struct wmi_twt_enable_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse wmi twt enable status event tlv: %d\n",
@@ -8999,15 +8925,12 @@ static void ath12k_wmi_twt_enable_event(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_TWT_ENABLE_COMPLETE_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch twt enable wmi event\n");
-		goto exit;
+		return;
 	}
 
 	ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt enable event pdev id %u status %u\n",
 		   le32_to_cpu(ev->pdev_id),
 		   le32_to_cpu(ev->status));
-
-exit:
-	kfree(tb);
 }
 
 static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab,
@@ -9017,7 +8940,7 @@ static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab,
 	const struct wmi_twt_disable_event *ev;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse wmi twt disable status event tlv: %d\n",
@@ -9028,15 +8951,12 @@ static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_TWT_DISABLE_COMPLETE_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch twt disable wmi event\n");
-		goto exit;
+		return;
 	}
 
 	ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt disable event pdev id %d status %u\n",
 		   le32_to_cpu(ev->pdev_id),
 		   le32_to_cpu(ev->status));
-
-exit:
-	kfree(tb);
 }
 
 static int ath12k_wmi_wow_wakeup_host_parse(struct ath12k_base *ab,
@@ -9109,7 +9029,7 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
 	const void **tb;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -9119,7 +9039,6 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_GTK_OFFLOAD_STATUS_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch gtk offload status ev");
-		kfree(tb);
 		return;
 	}
 
@@ -9129,7 +9048,6 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
 		rcu_read_unlock();
 		ath12k_warn(ab, "failed to get arvif for vdev_id:%d\n",
 			    le32_to_cpu(ev->vdev_id));
-		kfree(tb);
 		return;
 	}
 
@@ -9145,8 +9063,6 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
 				   (void *)&replay_ctr_be, GFP_ATOMIC);
 
 	rcu_read_unlock();
-
-	kfree(tb);
 }
 
 static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab,
@@ -9158,7 +9074,7 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab,
 	const void **tb;
 	int ret, i;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse mlo setup complete event tlv: %d\n",
@@ -9169,7 +9085,6 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab,
 	ev = tb[WMI_TAG_MLO_SETUP_COMPLETE_EVENT];
 	if (!ev) {
 		ath12k_warn(ab, "failed to fetch mlo setup complete event\n");
-		kfree(tb);
 		return;
 	}
 
@@ -9188,14 +9103,11 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab,
 	if (!ar) {
 		ath12k_warn(ab, "invalid pdev_id %d status %u in setup complete event\n",
 			    ev->pdev_id, ev->status);
-		goto out;
+		return;
 	}
 
 	ar->mlo_setup_status = le32_to_cpu(ev->status);
 	complete(&ar->mlo_setup_done);
-
-out:
-	kfree(tb);
 }
 
 static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab,
@@ -9205,7 +9117,7 @@ static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab,
 	const void **tb;
 	int ret;
 
-	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
+	tb = ath12k_wmi_tlv_parse(ab, skb);
 	if (IS_ERR(tb)) {
 		ret = PTR_ERR(tb);
 		ath12k_warn(ab, "failed to parse teardown complete event tlv: %d\n", ret);
@@ -9213,13 +9125,8 @@ static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab,
 	}
 
 	ev = tb[WMI_TAG_MLO_TEARDOWN_COMPLETE];
-	if (!ev) {
+	if (!ev)
 		ath12k_warn(ab, "failed to fetch teardown complete event\n");
-		kfree(tb);
-		return;
-	}
-
-	kfree(tb);
 }
 
 #ifdef CONFIG_ATH12K_DEBUGFS
@@ -11253,3 +11160,18 @@ int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab,
 	dev_kfree_skb(skb);
 	return ret;
 }
+
+int ath12k_wmi_alloc(void)
+{
+	ath12k_wmi_tb = __alloc_percpu(WMI_TAG_MAX * sizeof(void *),
+				       __alignof__(void *));
+	if (!ath12k_wmi_tb)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void ath12k_wmi_free(void)
+{
+	free_percpu(ath12k_wmi_tb);
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 0bf0a7941cd3..5e9d287dc9dc 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -6572,4 +6572,7 @@ int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
 				       struct ath12k_reg_tpc_power_info *param);
 int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab,
 					    struct wmi_mlo_link_set_active_arg *param);
+int ath12k_wmi_alloc(void);
+void ath12k_wmi_free(void);
+
 #endif
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v3 1/3] wifi: iwlwifi: pcie: optimize MSI-X interrupt affinity
From: Johannes Berg @ 2026-03-16 10:32 UTC (permalink / raw)
  To: Adrián García Casado, Miri Korenblit
  Cc: linux-wireless, linux-kernel, Miguel Ojeda
In-Reply-To: <20260315201647.15328-1-adriangarciacasado42@gmail.com>

Hi,

Somehow you messed up reposting this - the whole v2 series appears twice
and the v3 of this patch appears twice but without the rest of the
series?

> Implement a balanced RSS queue distribution by skipping CPU0 for
> high-rate MSI-X interrupts when multiple CPUs are online. This reduces
> contention with system housekeeping tasks on the boot core and improves
> overall throughput.

*Does* it improve throughput though? You should back up such claims with
numbers ... I doubt it would (unconditionally). It's not like the system
is going to be *really busy* all the time with housekeeping etc., and
the boot core is probably going to be a P-core, where you might have a
system with only 2 P-cores and 4-8 E (or even smaller) cores. This
likely also breaks some Intel-internal system requirements, but that
could be debated with the right folks.

Either way,

> --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
> +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
> @@ -1683,7 +1683,17 @@ static void iwl_pcie_irq_set_affinity(struct iwl_trans *trans,
>  		 * Get the cpu prior to the place to search
>  		 * (i.e. return will be > i - 1).
>  		 */
> +		/*
> +		 * Balanced distribution: skip CPU0 for high-rate RSS queues
> +		 * to avoid contention with system housekeeping.
> +		 */
>  		cpu = cpumask_next(i - offset, cpu_online_mask);
> +		if (cpu >= nr_cpu_ids)
> +			cpu = cpumask_first(cpu_online_mask);
> +
> +		if (cpu == 0 && num_online_cpus() > 1)
> +			cpu = cpumask_next(0, cpu_online_mask);
> +

this is wrong since you really then should allocate one queue less,
rather than mapping two queues to the same core.

johannes

^ permalink raw reply

* Re: [PATCH] wifi: mac80211: fix monitor mode frame capture for real chanctx drivers
From: Johannes Berg @ 2026-03-16 10:38 UTC (permalink / raw)
  To: 傅继晗
  Cc: linux-wireless, linux-kernel, stable, oscar.alfonso.diaz
In-Reply-To: <20260309104559.22252-1-fjhhz1997@gmail.com>

On Mon, 2026-03-09 at 10:45 +0000, 傅继晗 wrote:
> 
> I see the key difference between our approaches: your v2 iterates
> the chanctx_list and only proceeds when there is exactly one entry
> (going to fail_rcu if more than one exists), while mine blindly takes
> the first entry via list_first_entry_or_null(). Your approach is
> clearly safer -- in a multi-chanctx scenario, there is no way to know
> which channel the user intends to inject on, so refusing is the
> correct behaviour.

Oh, right, I hadn't even realised that at first.

> I have tested my patch on an MT7921AU (mt76, USB) adapter across
> v6.13, v6.19, and v7.0-rc2 with managed + monitor coexistence, and
> have not observed any crashes. However, my testing was limited to a
> single-chanctx scenario (one managed interface + one monitor
> interface), so it does not rule out crashes in multi-chanctx
> configurations.

Maybe Óscar can comment on which device/version he tested and got the
crash with? I just would like to avoid having crashes because of this,
but generally think that - perhaps optionally - we could have code like
this, since people _do_ want injection to work.

> Could you share some details about the crashes that were reported
> with your v2? For example, which devices/drivers were affected and
> what the crash signature looked like? That would help me understand
> whether the issue was specific to multi-chanctx usage or something
> more fundamental with accessing the chanctx_list in this code path.

No, it was specific to some driver implementation, but I don't have any
more information now.

> If you agree, I would like to send a v2 that combines both approaches:
> use list_first_entry_or_null() for simplicity, but add a
> list_is_singular() guard so we only proceed when there is exactly one
> chanctx -- matching the safety constraint from your v2:
> 
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -2399,10 +2399,24 @@
> -	if (chanctx_conf)
> +	if (chanctx_conf) {
>  		chandef = &chanctx_conf->def;
> -	else if (local->emulate_chanctx)
> +	} else if (local->emulate_chanctx) {
>  		chandef = &local->hw.conf.chandef;
> -	else
> -		goto fail_rcu;
> +	} else {
> +		struct ieee80211_chanctx *ctx;
> +
> +		ctx = list_first_entry_or_null(&local->chanctx_list,
> +					       struct ieee80211_chanctx,
> +					       list);
> +		if (ctx && list_is_singular(&local->chanctx_list))
> +			chandef = &ctx->conf.def;
> +		else
> +			goto fail_rcu;
> +	}
> 
> This avoids the ambiguity of picking an arbitrary chanctx in
> multi-chanctx scenarios while still fixing the common single-chanctx
> case (e.g. one managed + one monitor interface).

Seems reasonable, I think we could even drop the "if (emulate) part
(since in that case the list should always be singular). Just like I
said above - would like to understand the issue that had appeared with
it.

johannes

^ permalink raw reply

* Re: [PATCH ath-next v3] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Baochen Qiang @ 2026-03-16 10:42 UTC (permalink / raw)
  To: Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <20260316103248.3042158-1-nico.escande@gmail.com>



On 3/16/2026 6:32 PM, Nicolas Escande wrote:
> On each WMI message received from the hardware, we alloc a temporary array
> of WMI_TAG_MAX entries of type void *. This array is then populated with
> pointers of parsed structs depending on the WMI type, and then freed. This
> alloc can fail when memory pressure in the system is high enough.
> 
> Given the fact that it is scheduled in softirq with the system_bh_wq, we
> should not be able to parse more than one WMI message per CPU at any time.
> 
> So instead lets move to a per cpu allocated array, that is reused across
> calls: ath12K_wmi_tb that lives in wmi.c of the ath12K module. To alloc &
> free we added two new module_init/exit functions for the module and two
> new wmi functions to alloc/free this memory.
> 
> ath12k_wmi_tlv_parse_alloc() and ath12k_wmi_tlv_parse() are merged
> together as it no longer allocs mem but returns the existing per-cpu one.
> 
> Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
> ---
> changes from v2:
>   - removed now superfluous return in ath12k_wmi_event_teardown_complete()
>   - moved ath12k_wmi_tb declaration to wmi.c & added two functions to
>     alloc / free it
>   - removed useless error message on memory allocation failure
> 
> changes from v1:
>   - rebased on ath-next 27401c9b1432
>   - changed wording according to Jeff's comment
>   - moved alloc/cleanup to new module_init/exit functions in the
>     ath12k module as per Baochen's comment
> 
> changes from RFC:
>   - rebased on ath-next 8e0ab5b9adb7
>   - converted missing call sites ath12k_wmi_obss_color_collision_event()
>     & ath12k_wmi_pdev_temperature_event()
>   - changed alloc order & cleanup path in ath12k_core_alloc() as it seems
>     it confused people
>   - used sizeof(*tb) in ath12k_wmi_tlv_parse()
> ---
>  drivers/net/wireless/ath/ath12k/core.c |  19 +++
>  drivers/net/wireless/ath/ath12k/core.h |   1 +
>  drivers/net/wireless/ath/ath12k/wmi.c  | 200 ++++++++-----------------
>  drivers/net/wireless/ath/ath12k/wmi.h  |   3 +
>  4 files changed, 84 insertions(+), 139 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index c31c47fb5a73..16815a27f8f2 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -2321,5 +2321,24 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
>  	return NULL;
>  }
>  
> +static int ath12k_init(void)
> +{
> +	int ret;
> +
> +	ret = ath12k_wmi_alloc();
> +	if (ret)
> +		return ret;
> +
> +	return 0;

nit: you can simply

	return ath12k_wmi_alloc();

> +}
> +
> +static void ath12k_exit(void)
> +{
> +	ath12k_wmi_free();
> +}
> +
> +module_init(ath12k_init);
> +module_exit(ath12k_exit);
> +
>  MODULE_DESCRIPTION("Driver support for Qualcomm Technologies WLAN devices");
>  MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 59c193b24764..02ee6c718621 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -19,6 +19,7 @@
>  #include <linux/average.h>
>  #include <linux/of.h>
>  #include <linux/rhashtable.h>
> +#include <linux/percpu.h>

does it make more sense to add this to wmi.c instead?


^ permalink raw reply

* Re: [PATCH ath-next v3] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Nicolas Escande @ 2026-03-16 10:57 UTC (permalink / raw)
  To: Baochen Qiang, Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <d38acb9f-60dc-4d37-a3b5-8cd09f76939e@oss.qualcomm.com>

On Mon Mar 16, 2026 at 11:42 AM CET, Baochen Qiang wrote:
[...]
>> --- a/drivers/net/wireless/ath/ath12k/core.c
>> +++ b/drivers/net/wireless/ath/ath12k/core.c
>> @@ -2321,5 +2321,24 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
>>  	return NULL;
>>  }
>>  
>> +static int ath12k_init(void)
>> +{
>> +	int ret;
>> +
>> +	ret = ath12k_wmi_alloc();
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>
> nit: you can simply
>
> 	return ath12k_wmi_alloc();

Yes we can, but I did this in case we need to add more stuff in that function at
some later point. It would generate less code chrun. But I'm ok with a direct
return statement if you think that's better. Just tell me and I'll send the v4.

>
>> +}
>> +
>> +static void ath12k_exit(void)
>> +{
>> +	ath12k_wmi_free();
>> +}
>> +
>> +module_init(ath12k_init);
>> +module_exit(ath12k_exit);
>> +
>>  MODULE_DESCRIPTION("Driver support for Qualcomm Technologies WLAN devices");
>>  MODULE_LICENSE("Dual BSD/GPL");
>> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
>> index 59c193b24764..02ee6c718621 100644
>> --- a/drivers/net/wireless/ath/ath12k/core.h
>> +++ b/drivers/net/wireless/ath/ath12k/core.h
>> @@ -19,6 +19,7 @@
>>  #include <linux/average.h>
>>  #include <linux/of.h>
>>  #include <linux/rhashtable.h>
>> +#include <linux/percpu.h>
>
> does it make more sense to add this to wmi.c instead?

Indeed it does. I'll fix it.

^ permalink raw reply

* Re: [PATCH] wifi: rtw89: retry efuse physical map dump on transient failure
From: Christian Hewitt @ 2026-03-16 11:03 UTC (permalink / raw)
  To: Ping-Ke Shih
  Cc: Bitterblue Smith, linux-wireless@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <a7d421b1d3074a00968f2902c9debb42@realtek.com>

> On 16 Mar 2026, at 9:32 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> 
> Christian Hewitt <christianshewitt@gmail.com> wrote:
>> On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse
>> physical map dump intermittently fails with -EBUSY during probe.
>> The failure occurs in rtw89_dump_physical_efuse_map_ddv() where
>> read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY
>> bit after 1 second.
>> 
>> The root cause is a timing race during boot: the WiFi driver's
>> chip initialization (firmware download via PCIe) overlaps with the
>> Bluetooth firmware download to the same combo chip over USB. This
>> can leave the efuse controller temporarily unavailable when the
>> WiFi driver attempts to read the efuse map.
>> 
>> Add a retry loop (up to 3 attempts with 500ms delays) around the
>> physical efuse map dump in rtw89_parse_efuse_map_ax(). The firmware
>> download path already retries up to 5 times, but the efuse read
>> that follows has no retry logic, making it the weak link in the
>> probe sequence.
> 
> I'd prefer adding a wrapper to retry 5 times without delay as bottom
> changes for reference. If you want to limit retry only for
> 'dav == false' case, it is also fine to me.
> 
>> 
>> Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
> 
> [...]
> 
>> 
>> drivers/net/wireless/realtek/rtw89/efuse.c | 13 ++++++++++++-
>> 1 file changed, 12 insertions(+), 1 deletion(-)
>> 
>> diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c
>> b/drivers/net/wireless/realtek/rtw89/efuse.c
>> index a2757a88d55d..d506f04ffd6c 100644
>> --- a/drivers/net/wireless/realtek/rtw89/efuse.c
>> +++ b/drivers/net/wireless/realtek/rtw89/efuse.c
>> @@ -270,6 +270,7 @@ int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev)
>>        u8 *log_map = NULL;
>>        u8 *dav_phy_map = NULL;
>>        u8 *dav_log_map = NULL;
>> +       int retry;
>>        int ret;
>> 
>>        if (rtw89_read16(rtwdev, R_AX_SYS_WL_EFUSE_CTRL) & B_AX_AUTOLOAD_SUS)
>> @@ -289,7 +290,17 @@ int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev)
>>                goto out_free;
>>        }
>> 
>> -       ret = rtw89_dump_physical_efuse_map(rtwdev, phy_map, 0, phy_size,
>> false);
>> +       for (retry = 0; retry < 3; retry++) {
>> +               if (retry) {
>> +                       rtw89_warn(rtwdev, "efuse dump failed, retrying
>> (%d)\n",
>> +                                  retry);
>> +                       fsleep(500000);
>> +               }
>> +               ret = rtw89_dump_physical_efuse_map(rtwdev, phy_map, 0,
>> +                                                   phy_size, false);
>> +               if (!ret)
>> +                       break;
>> +       }
>>        if (ret) {
>>                rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
>>                goto out_free;
>> --
>> 2.43.0
> 
> How about retrying 5 times without fsleep(500000)?
> 
> diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c
> index a2757a88d55d..89d4b1b865f8 100644
> --- a/drivers/net/wireless/realtek/rtw89/efuse.c
> +++ b/drivers/net/wireless/realtek/rtw89/efuse.c
> @@ -185,8 +185,8 @@ static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map,
>        return 0;
> }
> 
> -static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
> -                                        u32 dump_addr, u32 dump_size, bool dav)
> +static int __rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
> +                                          u32 dump_addr, u32 dump_size, bool dav)
> {
>        int ret;
> 
> @@ -208,6 +208,25 @@ static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
>        return 0;
> }
> 
> +static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
> +                                        u32 dump_addr, u32 dump_size, bool dav)
> +{
> +       int retry;
> +       int ret;
> +
> +       for (retry = 0; retry < 5; retry++) {
> +               ret = __rtw89_dump_physical_efuse_map(rtwdev, map, dump_addr,
> +                                                     dump_size, dav);
> +               if (!ret)
> +                       return 0;
> +
> +               rtw89_warn(rtwdev, "efuse dump (dav=%d) failed, retrying (%d)\n",
> +                          dav, retry);
> +       }
> +
> +       return ret;
> +}
> +
> #define invalid_efuse_header(hdr1, hdr2) \
>        ((hdr1) == 0xff || (hdr2) == 0xff)
> #define invalid_efuse_content(word_en, i) \

I’ve run some boot tests and this also resolves my efuse map use-case, e.g.

ROCK5B:~ # dmesg | grep rtw89
[    6.506375] rtw89_8852be 0002:21:00.0: loaded firmware rtw89/rtw8852b_fw-1.bin
[    6.506539] rtw89_8852be 0002:21:00.0: enabling device (0000 -> 0003)
[    6.516069] rtw89_8852be 0002:21:00.0: Firmware version 0.29.29.15 (6fb3ec41), cmd version 0, type 5
[    6.516083] rtw89_8852be 0002:21:00.0: Firmware version 0.29.29.15 (6fb3ec41), cmd version 0, type 3
[   10.153731] rtw89_8852be 0002:21:00.0: efuse dump (dav=0) failed, retrying (0)
[   10.405347] rtw89_8852be 0002:21:00.0: chip info CID: 0, CV: 1, AID: 0, ACV: 1, RFE: 1
[   10.408311] rtw89_8852be 0002:21:00.0: rfkill hardware state changed to enable

So far I haven’t observed more than 1x retry being required, and there are no
issues with loading the BT module.

Would you like me to send a v2 using your revised version? - or?

Christian

^ permalink raw reply

* [PATCH wireless-next] wifi: nl80211: use int for band coming from netlink
From: Johannes Berg @ 2026-03-16 11:30 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

This was pointed out before, but there are issues with just
removing the <0 check since enum representation isn't fixed,
nla_type() returns int but really can only return small
non-negative values, etc. Now newer versions of sparse are
also starting to warn on it. Just use int for the band var.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/wireless/nl80211.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d2ef13ab1a20..e15cd26f3a79 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5843,7 +5843,7 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
 	 */
 	BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
 	nla_for_each_nested(tx_rates, attrs[attr], rem) {
-		enum nl80211_band band = nla_type(tx_rates);
+		int band = nla_type(tx_rates);
 		int err;
 
 		if (band < 0 || band >= NUM_NL80211_BANDS)
@@ -10705,7 +10705,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 		nla_for_each_nested(attr,
 				    info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
 				    tmp) {
-			enum nl80211_band band = nla_type(attr);
+			int band = nla_type(attr);
 
 			if (band < 0 || band >= NUM_NL80211_BANDS) {
 				err = -EINVAL;
-- 
2.53.0


^ permalink raw reply related

* [PATCH mt76] wifi: mt76: mt7996: fix frequency separation for station STR mode
From: Lorenzo Bianconi @ 2026-03-16 11:44 UTC (permalink / raw)
  To: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
	Matthias Brugger, AngeloGioacchino Del Regno
  Cc: linux-wireless, linux-arm-kernel, linux-mediatek, Peter Chiu,
	Lorenzo Bianconi

From: Peter Chiu <chui-hao.chiu@mediatek.com>

Fix frequency separation field for STR in MLD capabilities
to allow prpl get correct chip capability.

Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/init.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index 8dfb81eabc9aef9b54fd3b34e13114a1d5214541..d6f9aa1ab52d1258e3923783c8eac2ad5daf2b90 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -99,6 +99,7 @@ static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = {
 		.extended_capabilities_mask = if_types_ext_capa_ap,
 		.extended_capabilities_len = sizeof(if_types_ext_capa_ap),
 		.mld_capa_and_ops =
+			FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND, 1) |
 			FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS,
 					 MT7996_MAX_RADIOS - 1),
 	},

---
base-commit: dab5edc5546c90674cfff033abc2b797b3ad4bf4
change-id: 20260316-mt7996-sta-str-38f7b4a49313

Best regards,
-- 
Lorenzo Bianconi <lorenzo@kernel.org>


^ permalink raw reply related

* Re: [PATCH 50/61] iommu: Prefer IS_ERR_OR_NULL over manual NULL check
From: Robin Murphy @ 2026-03-16 13:30 UTC (permalink / raw)
  To: Philipp Hahn, amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel,
	dri-devel, gfs2, intel-gfx, intel-wired-lan, iommu, kvm,
	linux-arm-kernel, linux-block, linux-bluetooth, linux-btrfs,
	linux-cifs, linux-clk, linux-erofs, linux-ext4, linux-fsdevel,
	linux-gpio, linux-hyperv, linux-input, linux-kernel, linux-leds,
	linux-media, linux-mips, linux-mm, linux-modules, linux-mtd,
	linux-nfs, linux-omap, linux-phy, linux-pm, linux-rockchip,
	linux-s390, linux-scsi, linux-sctp, linux-security-module,
	linux-sh, linux-sound, linux-stm32, linux-trace-kernel, linux-usb,
	linux-wireless, netdev, ntfs3, samba-technical, sched-ext,
	target-devel, tipc-discussion, v9fs
  Cc: Joerg Roedel, Will Deacon
In-Reply-To: <20260310-b4-is_err_or_null-v1-50-bd63b656022d@avm.de>

On 2026-03-10 11:49 am, Philipp Hahn wrote:
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.

AFAICS it doesn't look possible for the argument to be anything other 
than valid at both callsites, so *both* conditions here seem in fact to 
be entirely redundant.

> Change generated with coccinelle.

Please use coccinelle responsibly. Mechanical changes are great for 
scripted API updates, but for cleanup, whilst it's ideal for *finding* 
areas of code that are worth looking at, the code then wants actually 
looking at, in its whole context, because meaningful cleanup often goes 
deeper than trivial replacement.

In particular, anywhere IS_ERR_OR_NULL() is genuinely relevant is 
usually a sign of bad interface design, so if you're looking at this 
then you really should be looking first and foremost to remove any 
checks that are already unnecessary, and for the remainder, to see if 
the thing being checked can be improved to not mix the two different 
styles. That would be constructive and (usually) welcome cleanup. Simply 
churning a bunch of code with this ugly macro that's arguably less 
readable than what it replaces, not so much.

Thanks,
Robin.

> To: Joerg Roedel <joro@8bytes.org>
> To: Will Deacon <will@kernel.org>
> To: Robin Murphy <robin.murphy@arm.com>
> Cc: iommu@lists.linux.dev
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
> ---
>   drivers/iommu/omap-iommu.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
> index 8231d7d6bb6a9202025643639a6b28e6faa84659..500a42b57a997696ff37c76f028a717ab71d01f9 100644
> --- a/drivers/iommu/omap-iommu.c
> +++ b/drivers/iommu/omap-iommu.c
> @@ -881,7 +881,7 @@ static int omap_iommu_attach(struct omap_iommu *obj, u32 *iopgd)
>    **/
>   static void omap_iommu_detach(struct omap_iommu *obj)
>   {
> -	if (!obj || IS_ERR(obj))
> +	if (IS_ERR_OR_NULL(obj))
>   		return;
>   
>   	spin_lock(&obj->iommu_lock);
> 


^ permalink raw reply

* RTL8852BE fails to power on: "xtal si not ready" on ASUS TUF GAMING B650-PLUS WIFI
From: Jason Kakandris @ 2026-03-16 14:10 UTC (permalink / raw)
  To: linux-wireless

System Info

Distro: Linux Mint 22.3 Zena (Ubuntu 24.04 base)
Kernels tested: 6.14.0-37-generic, 6.17.0-14-generic (same failure on both)
Motherboard: ASUS TUF GAMING B650-PLUS WIFI (Rev 1.xx)
BIOS: v3827 (Feb 2026)
CPU: AMD Ryzen 7 7700X
Driver: rtw89 v7.0 (git commit d2f175e
https://github.com/morrownr/rtw89/commit/d2f175eafa0a4ef9cc65e7073a77e60238cae614)
WiFi works in Windows: Yes


Problem
The RTL8852BE WiFi card fails to initialize with xtal si not ready error. No
wireless interface is created.


dmesg output

rtw89_8852be_git 0000:08:00.0: loaded firmware rtw89/rtw8852b_fw-1.bin
rtw89_8852be_git 0000:08:00.0: enabling device (0000 -> 0003)
rtw89_8852be_git 0000:08:00.0: xtal si not ready(R): offset=41
rtw89_8852be_git 0000:08:00.0: xtal si not ready(W): offset=90 val=10 mask=10
rtw89_8852be_git 0000:08:00.0: failed to power on
rtw89_8852be_git 0000:08:00.0: failed to setup chip information
rtw89_8852be_git 0000:08:00.0: probe with driver rtw89_8852be_git failed with
error -110


lspci

08:00.0 Network controller [0280]: Realtek Semiconductor Co., Ltd. RTL8852BE
PCIe 802.11ax Wireless Network Controller [10ec:b852]
Subsystem: AzureWave RTL8852BE PCIe 802.11ax Wireless Network Controller
[1a3b:5471]

What I've tried

Kernel parameter pcie_aspm=off
Module parameters: disable_clkreq=Y disable_aspm_l1=Y disable_aspm_l1ss=Y
disable_ps_mode=y
Updated BIOS from v3057 to v3827
Updated firmware files via make install_fw
Tested on kernels 6.14 and 6.17 — same failure on both
In-kernel driver and morrownr out-of-tree driver — same failure
WiFi works fine in Windows on the same hardware

^ permalink raw reply

* Re: [PATCH RFC/RFT] vfio/pci-quirks: Quirk for ath wireless
From: James Prestwood @ 2026-03-16 14:58 UTC (permalink / raw)
  To: Jason Gunthorpe, Alex Williamson
  Cc: qemu-devel, kvm, quic_bqiang, kvalo, linux-wireless, ath11k,
	dwmw2, iommu, kernel, johannes, jtornosm
In-Reply-To: <20240815171935.GO3468552@ziepe.ca>

On 8/15/24 10:19 AM, Jason Gunthorpe wrote:
> On Thu, Aug 15, 2024 at 10:59:05AM -0600, Alex Williamson wrote:
>
>>> This is probably the only way to approach this, trap and emulate the
>>> places in the device that program additional interrupt sources and do
>>> a full MSI-like flow to set them up in the kernel.
>> Your last sentence here seems to agree with this approach, but
>> everything else suggests disapproval, so I don't know where you're
>> going here.
> Trapping and emulating is fine.
>
> My concern is really only about skipping SET_IRQ.
>
> That works because of the assumption that the IMS sources are going to
> re-use addr/data pairs setup in the MSI CAP.
>
> That assumption is frail, and won't work at all under the proper IMS
> support Linux now has.
>
> I really don't want to go down the road and have someone tell Thomas
> he can't convert the Linux driver to use irq_domain IMS because it
> will break this stuff here.
>
>> I have no specs for this device, nor any involvement from the device
>> vendor, so the idea of creating a vfio-pci variant driver to setup an
>> irq_domain and augment a device specific SET_IRQs ioctls not only sounds
>> tremendously more complicated (host and VMM), it's simply not possible
>> with the knowledge we have at hand.
> It seems like you have reverse engineered alot of the necessary
> information though??
>
> Maybe there is a more generic approach than a variant driver. If you
> wanted to use IMS from userspace generically you could imagine some
> kind of IMS focused "SET_IRQ" in generic VFIO. Where we'd create the
> needed irq_domains and pass the addr/data pair back to userspace?
>
>> I observe that the device configures MSI vectors and then writes that
>> same vector address/data elsewhere into the device.  Whether the device
>> can trigger those vectors based only on the MSI capability programming
>> and a secondary source piggybacks on those vectors or if this is just a
>> hack by Qualcomm to use an MSI capability to acquire some vectors which
>> are exclusively used by the secondary hardware, I have no idea.
> Well at least that should be testable - but it seems crazy if the
> device has registers for an addr/data pair and then somehow doesn't
> use the values that get put in them??
>
> Copying from the MSI is almost certainly a SW hack because IMS support
> has never really existed in an OS until now. I think your guess for
> why it is like this is pretty good.
>
>> I do not believe that introducing a vfio device feature that disables
>> virtualization of the MSI address/data _only_ at the vfio interface
>> (not to a QEMU VM) provides some implicit support of this device
>> behavior.  These values are already available to a privileged user in
>> the host and the same is available for an MSI-X use case by directly
>> reading the MSI-X vector table.
> To be clear, I'm not really worried about showing the data to
> userspace.
>
> Userspace just shouldn't be using it to implement an IMS technique!
>
> Jason

I see this thread went stale. Wondering if there was ever a final 
conclusion if this could get fixed for ath11k or not. I tried again on a 
recent kernel, 6.17, and see the same behavior.

Thanks,

James


^ permalink raw reply

* Re: [PATCH ath-next 0/2] wifi: ath12k: Clean up the WMI Unit Test functionality
From: Jeff Johnson @ 2026-03-16 15:37 UTC (permalink / raw)
  To: Jeff Johnson, Jeff Johnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260310-ath12k-unit-test-cleanup-v1-0-03e3df56f903@oss.qualcomm.com>


On Tue, 10 Mar 2026 08:16:11 -0700, Jeff Johnson wrote:
> Patch 1 updates the core Unit Test functionality to address multiple
> existing issues, and patch 2 removes unused DFS Unit Test definitions.
> 

Applied, thanks!

[1/2] wifi: ath12k: Clean up the WMI Unit Test command interface
      commit: e570593b568f74b8d8367d094400d71bc398118f
[2/2] wifi: ath12k: Remove unused DFS Unit Test definitions
      commit: 7bbb578fc43e7dcb8690cfc98844bd67bc311e8a

Best regards,
-- 
Jeff Johnson <jeff.johnson@oss.qualcomm.com>


^ permalink raw reply

* Re: [PATCH RFC/RFT] vfio/pci-quirks: Quirk for ath wireless
From: James Prestwood @ 2026-03-16 15:43 UTC (permalink / raw)
  To: Jason Gunthorpe, Alex Williamson
  Cc: qemu-devel, kvm, quic_bqiang, kvalo, linux-wireless, ath11k,
	dwmw2, iommu, kernel, johannes, jtornosm
In-Reply-To: <fb53b8fd-5d36-4df3-a9e6-fba7c0457e55@gmail.com>


On 3/16/26 7:58 AM, James Prestwood wrote:
> On 8/15/24 10:19 AM, Jason Gunthorpe wrote:
>> On Thu, Aug 15, 2024 at 10:59:05AM -0600, Alex Williamson wrote:
>>
>>>> This is probably the only way to approach this, trap and emulate the
>>>> places in the device that program additional interrupt sources and do
>>>> a full MSI-like flow to set them up in the kernel.
>>> Your last sentence here seems to agree with this approach, but
>>> everything else suggests disapproval, so I don't know where you're
>>> going here.
>> Trapping and emulating is fine.
>>
>> My concern is really only about skipping SET_IRQ.
>>
>> That works because of the assumption that the IMS sources are going to
>> re-use addr/data pairs setup in the MSI CAP.
>>
>> That assumption is frail, and won't work at all under the proper IMS
>> support Linux now has.
>>
>> I really don't want to go down the road and have someone tell Thomas
>> he can't convert the Linux driver to use irq_domain IMS because it
>> will break this stuff here.
>>
>>> I have no specs for this device, nor any involvement from the device
>>> vendor, so the idea of creating a vfio-pci variant driver to setup an
>>> irq_domain and augment a device specific SET_IRQs ioctls not only 
>>> sounds
>>> tremendously more complicated (host and VMM), it's simply not possible
>>> with the knowledge we have at hand.
>> It seems like you have reverse engineered alot of the necessary
>> information though??
>>
>> Maybe there is a more generic approach than a variant driver. If you
>> wanted to use IMS from userspace generically you could imagine some
>> kind of IMS focused "SET_IRQ" in generic VFIO. Where we'd create the
>> needed irq_domains and pass the addr/data pair back to userspace?
>>
>>> I observe that the device configures MSI vectors and then writes that
>>> same vector address/data elsewhere into the device.  Whether the device
>>> can trigger those vectors based only on the MSI capability programming
>>> and a secondary source piggybacks on those vectors or if this is just a
>>> hack by Qualcomm to use an MSI capability to acquire some vectors which
>>> are exclusively used by the secondary hardware, I have no idea.
>> Well at least that should be testable - but it seems crazy if the
>> device has registers for an addr/data pair and then somehow doesn't
>> use the values that get put in them??
>>
>> Copying from the MSI is almost certainly a SW hack because IMS support
>> has never really existed in an OS until now. I think your guess for
>> why it is like this is pretty good.
>>
>>> I do not believe that introducing a vfio device feature that disables
>>> virtualization of the MSI address/data _only_ at the vfio interface
>>> (not to a QEMU VM) provides some implicit support of this device
>>> behavior.  These values are already available to a privileged user in
>>> the host and the same is available for an MSI-X use case by directly
>>> reading the MSI-X vector table.
>> To be clear, I'm not really worried about showing the data to
>> userspace.
>>
>> Userspace just shouldn't be using it to implement an IMS technique!
>>
>> Jason
>
> I see this thread went stale. Wondering if there was ever a final 
> conclusion if this could get fixed for ath11k or not. I tried again on 
> a recent kernel, 6.17, and see the same behavior.
>
> Thanks,
>
> James
>
I addition, I've looked at various kernel version and see no time where 
there was ever a "hw/vfio/pci-quirks.c" file in the tree. I tried many 
versions between 6.17 and 5.11, I don't see the "hw" directory at all.

I'd like to try this patch out, but might need some guidance on what 
kernel version this was meant for and if files may have shuffled around.

Thanks,

James


^ permalink raw reply

* [PATCH v2 0/4] Use the QMI service IDs from the QMI header
From: Daniel Lezcano @ 2026-03-16 17:14 UTC (permalink / raw)
  To: konradybcio, andersson
  Cc: linux-kernel, Alex Elder, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jeff Johnson,
	Mathieu Poirier, Srinivas Kandagatla, Jaroslav Kysela,
	Takashi Iwai, Kees Cook, Greg Kroah-Hartman, Arnd Bergmann,
	Mark Brown, Wesley Cheng, netdev, linux-wireless, ath10k, ath11k,
	ath12k, linux-arm-msm, linux-remoteproc, linux-sound

The different subsystems implementing the QMI service protocol are
using their own definition of the service id. It is not a problem but
it results on having those duplicated with different names but the
same value and without consistency in their name.

The QMI service IDs are defined in the qmi.h header file. Use those
instead of defining the IDs in the protocol implementation file. It
will result in unifying and providing a consistent way to represent
the supported protocols.

This series is based on the immutable branch [1] containing the QMI
service id definitions along with some drivers using them.

How a patch can be merged ?

 * Add the Ack tag and let it go through the QCom's tree

   OR

 * Apply the patch on top of the immutable branch [1]

[1] https://lore.kernel.org/all/abdkE2qWX5Amf5Jo@baldur/


Changelog:

  v2:
   * Added Reviewed-by tags
   * Removed patches picked up by Bjorn
   * Rebase on top of the immutable branch from QCom's tree
   * Fixed up short description prefix for wifi changes
  v1:
   * Initial post

Cc: Alex Elder <elder@kernel.org>
Cc: Andrew Lunn <andrew+netdev@lunn.ch>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Jeff Johnson <jjohnson@kernel.org>
Cc: Bjorn Andersson <andersson@kernel.org>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Srinivas Kandagatla <srini@kernel.org>
Cc: Konrad Dybcio <konradybcio@kernel.org>
Cc: Jaroslav Kysela <perex@perex.cz>
Cc: Takashi Iwai <tiwai@suse.com>
Cc: Kees Cook <kees@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Mark Brown <broonie@kernel.org>
Cc: Wesley Cheng <quic_wcheng@quicinc.com>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-wireless@vger.kernel.org
Cc: ath10k@lists.infradead.org
Cc: ath11k@lists.infradead.org
Cc: ath12k@lists.infradead.org
Cc: linux-arm-msm@vger.kernel.org
Cc: linux-remoteproc@vger.kernel.org
Cc: linux-sound@vger.kernel.org
---
Daniel Lezcano (4):
  net: ipa: Use the unified QMI service ID instead of defining it
    locally
  wifi: ath: Use the unified QMI service ID instead of defining it
    locally
  slimbus: qcom-ngd-ctrl: Use the unified QMI service ID instead of
    defining it locally
  ALSA: usb-audio: qcom: Use the unified QMI service ID instead of
    defining it locally

 drivers/net/ipa/ipa_qmi.c                      | 6 ++----
 drivers/net/wireless/ath/ath10k/qmi.c          | 2 +-
 drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h | 1 -
 drivers/net/wireless/ath/ath11k/qmi.c          | 2 +-
 drivers/net/wireless/ath/ath11k/qmi.h          | 1 -
 drivers/net/wireless/ath/ath12k/qmi.c          | 2 +-
 drivers/net/wireless/ath/ath12k/qmi.h          | 1 -
 drivers/slimbus/qcom-ngd-ctrl.c                | 5 ++---
 sound/usb/qcom/qc_audio_offload.c              | 2 +-
 sound/usb/qcom/usb_audio_qmi_v01.h             | 1 -
 10 files changed, 8 insertions(+), 15 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [PATCH v2 1/4] net: ipa: Use the unified QMI service ID instead of defining it locally
From: Daniel Lezcano @ 2026-03-16 17:14 UTC (permalink / raw)
  To: konradybcio, andersson
  Cc: linux-kernel, Alex Elder, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jeff Johnson,
	Mathieu Poirier, Srinivas Kandagatla, Jaroslav Kysela,
	Takashi Iwai, Kees Cook, Greg Kroah-Hartman, Arnd Bergmann,
	Mark Brown, Wesley Cheng, netdev, linux-wireless, ath10k, ath11k,
	ath12k, linux-arm-msm, linux-remoteproc, linux-sound,
	Dmitry Baryshkov
In-Reply-To: <20260316171419.2619620-1-daniel.lezcano@oss.qualcomm.com>

Instead of defining a local macro with a custom name for the QMI
service identifier, use the one provided in qmi.h and remove the
locally defined macro.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
 drivers/net/ipa/ipa_qmi.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ipa/ipa_qmi.c b/drivers/net/ipa/ipa_qmi.c
index d771f3a71f94..37936ad132a2 100644
--- a/drivers/net/ipa/ipa_qmi.c
+++ b/drivers/net/ipa/ipa_qmi.c
@@ -66,11 +66,9 @@
  *   determination of when things are "ready"
  */
 
-#define IPA_HOST_SERVICE_SVC_ID		0x31
 #define IPA_HOST_SVC_VERS		1
 #define IPA_HOST_SERVICE_INS_ID		1
 
-#define IPA_MODEM_SERVICE_SVC_ID	0x31
 #define IPA_MODEM_SERVICE_INS_ID	2
 #define IPA_MODEM_SVC_VERS		1
 
@@ -484,7 +482,7 @@ int ipa_qmi_setup(struct ipa *ipa)
 	if (ret)
 		return ret;
 
-	ret = qmi_add_server(&ipa_qmi->server_handle, IPA_HOST_SERVICE_SVC_ID,
+	ret = qmi_add_server(&ipa_qmi->server_handle, QMI_SERVICE_ID_IPA,
 			     IPA_HOST_SVC_VERS, IPA_HOST_SERVICE_INS_ID);
 	if (ret)
 		goto err_server_handle_release;
@@ -501,7 +499,7 @@ int ipa_qmi_setup(struct ipa *ipa)
 	/* We need this ready before the service lookup is added */
 	INIT_WORK(&ipa_qmi->init_driver_work, ipa_client_init_driver_work);
 
-	ret = qmi_add_lookup(&ipa_qmi->client_handle, IPA_MODEM_SERVICE_SVC_ID,
+	ret = qmi_add_lookup(&ipa_qmi->client_handle, QMI_SERVICE_ID_IPA,
 			     IPA_MODEM_SVC_VERS, IPA_MODEM_SERVICE_INS_ID);
 	if (ret)
 		goto err_client_handle_release;
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 2/4] wifi: ath: Use the unified QMI service ID instead of defining it locally
From: Daniel Lezcano @ 2026-03-16 17:14 UTC (permalink / raw)
  To: konradybcio, andersson
  Cc: linux-kernel, Alex Elder, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jeff Johnson,
	Mathieu Poirier, Srinivas Kandagatla, Jaroslav Kysela,
	Takashi Iwai, Kees Cook, Greg Kroah-Hartman, Arnd Bergmann,
	Mark Brown, Wesley Cheng, netdev, linux-wireless, ath10k, ath11k,
	ath12k, linux-arm-msm, linux-remoteproc, linux-sound,
	Dmitry Baryshkov
In-Reply-To: <20260316171419.2619620-1-daniel.lezcano@oss.qualcomm.com>

Instead of defining a local macro with a custom name for the QMI
service identifier, use the one provided in qmi.h and remove the
locally defined macro.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/qmi.c          | 2 +-
 drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h | 1 -
 drivers/net/wireless/ath/ath11k/qmi.c          | 2 +-
 drivers/net/wireless/ath/ath11k/qmi.h          | 1 -
 drivers/net/wireless/ath/ath12k/qmi.c          | 2 +-
 drivers/net/wireless/ath/ath12k/qmi.h          | 1 -
 6 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index eebd78e7ff6b..4fdd0af415d5 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -1105,7 +1105,7 @@ int ath10k_qmi_init(struct ath10k *ar, u32 msa_size)
 	spin_lock_init(&qmi->event_lock);
 	INIT_WORK(&qmi->event_work, ath10k_qmi_driver_event_work);
 
-	ret = qmi_add_lookup(&qmi->qmi_hdl, WLFW_SERVICE_ID_V01,
+	ret = qmi_add_lookup(&qmi->qmi_hdl, QMI_SERVICE_ID_WLFW,
 			     WLFW_SERVICE_VERS_V01, 0);
 	if (ret)
 		goto err_qmi_lookup;
diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
index 9f311f3bc9e7..88d58f78989d 100644
--- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
+++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
@@ -7,7 +7,6 @@
 #ifndef WCN3990_QMI_SVC_V01_H
 #define WCN3990_QMI_SVC_V01_H
 
-#define WLFW_SERVICE_ID_V01 0x45
 #define WLFW_SERVICE_VERS_V01 0x01
 
 #define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index feebbc30f3df..1397756d6251 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -3337,7 +3337,7 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
 	spin_lock_init(&ab->qmi.event_lock);
 	INIT_WORK(&ab->qmi.event_work, ath11k_qmi_driver_event_work);
 
-	ret = qmi_add_lookup(&ab->qmi.handle, ATH11K_QMI_WLFW_SERVICE_ID_V01,
+	ret = qmi_add_lookup(&ab->qmi.handle, QMI_SERVICE_ID_WLFW,
 			     ATH11K_QMI_WLFW_SERVICE_VERS_V01,
 			     ab->qmi.service_ins_id);
 	if (ret < 0) {
diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h
index 7968ab122b65..eae416db8b52 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.h
+++ b/drivers/net/wireless/ath/ath11k/qmi.h
@@ -15,7 +15,6 @@
 #define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE	64
 #define ATH11K_QMI_CALDB_ADDRESS		0x4BA00000
 #define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01	128
-#define ATH11K_QMI_WLFW_SERVICE_ID_V01		0x45
 #define ATH11K_QMI_WLFW_SERVICE_VERS_V01	0x01
 #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01	0x02
 #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390	0x01
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index c11b84b56f8f..f31cba7af722 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -4061,7 +4061,7 @@ int ath12k_qmi_init_service(struct ath12k_base *ab)
 	spin_lock_init(&ab->qmi.event_lock);
 	INIT_WORK(&ab->qmi.event_work, ath12k_qmi_driver_event_work);
 
-	ret = qmi_add_lookup(&ab->qmi.handle, ATH12K_QMI_WLFW_SERVICE_ID_V01,
+	ret = qmi_add_lookup(&ab->qmi.handle, QMI_SERVICE_ID_WLFW,
 			     ATH12K_QMI_WLFW_SERVICE_VERS_V01,
 			     ab->qmi.service_ins_id);
 	if (ret < 0) {
diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h
index b5a4a01391cb..2a63e214eb42 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.h
+++ b/drivers/net/wireless/ath/ath12k/qmi.h
@@ -15,7 +15,6 @@
 #define ATH12K_QMI_MAX_BDF_FILE_NAME_SIZE	64
 #define ATH12K_QMI_CALDB_ADDRESS		0x4BA00000
 #define ATH12K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01	128
-#define ATH12K_QMI_WLFW_SERVICE_ID_V01		0x45
 #define ATH12K_QMI_WLFW_SERVICE_VERS_V01	0x01
 #define ATH12K_QMI_WLFW_SERVICE_INS_ID_V01	0x02
 #define ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_WCN7850 0x1
-- 
2.43.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox