Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH v2 0/4] Use the QMI service IDs from the QMI header
From: Greg Kroah-Hartman @ 2026-03-17  9:07 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Jakub Kicinski, konradybcio, andersson, linux-kernel, Alex Elder,
	Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
	Jeff Johnson, Mathieu Poirier, Srinivas Kandagatla,
	Jaroslav Kysela, Takashi Iwai, Kees Cook, Arnd Bergmann,
	Mark Brown, Wesley Cheng, netdev, linux-wireless, ath10k, ath11k,
	ath12k, linux-arm-msm, linux-remoteproc, linux-sound
In-Reply-To: <8757aec7-8c36-446a-9a34-f0717f64202a@oss.qualcomm.com>

On Tue, Mar 17, 2026 at 09:51:32AM +0100, Daniel Lezcano wrote:
> On 3/17/26 01:22, Jakub Kicinski wrote:
> > On Mon, 16 Mar 2026 18:14:10 +0100 Daniel Lezcano wrote:
> > > 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 ?
> > 
> > Wait for the dependency to appear in respective trees after the merge
> > window then repost the patches individually. I'm starting to get
> > annoyed with all this cross-tree QMI/MHI noise.
> 
> An ack is simpler for everyone, especially when they are trivial

Why isn't this 4 different patches, all for different branches/trees as
there does not seem to be any dependencies here?

confused,

greg k-h

^ permalink raw reply

* Re: [PATCH v2 4/4] ALSA: usb-audio: qcom: Use the unified QMI service ID instead of defining it locally
From: Takashi Iwai @ 2026-03-17  9:07 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: konradybcio, andersson, 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, Dan Carpenter
In-Reply-To: <20260316171419.2619620-5-daniel.lezcano@oss.qualcomm.com>

On Mon, 16 Mar 2026 18:14:14 +0100,
Daniel Lezcano wrote:
> 
> 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>

For the sound bits,

Reviewed-by: Takashi Iwai <tiwai@suse.de>


thanks,

Takashi

^ permalink raw reply

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



On 3/17/2026 4:47 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>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH v2 0/4] Use the QMI service IDs from the QMI header
From: Daniel Lezcano @ 2026-03-17  8:51 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: konradybcio, andersson, linux-kernel, Alex Elder, Andrew Lunn,
	David S. Miller, Eric Dumazet, 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
In-Reply-To: <20260316172251.2d57d0aa@kernel.org>

On 3/17/26 01:22, Jakub Kicinski wrote:
> On Mon, 16 Mar 2026 18:14:10 +0100 Daniel Lezcano wrote:
>> 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 ?
> 
> Wait for the dependency to appear in respective trees after the merge
> window then repost the patches individually. I'm starting to get
> annoyed with all this cross-tree QMI/MHI noise.

An ack is simpler for everyone, especially when they are trivial

^ permalink raw reply

* [PATCH ath-next v4] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Nicolas Escande @ 2026-03-17  8:47 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 v3:
  - simplified ath12k_core_init() with a single statement
  - move perpcu.h include directly to wmi.c

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 |  13 ++
 drivers/net/wireless/ath/ath12k/wmi.c  | 201 ++++++++-----------------
 drivers/net/wireless/ath/ath12k/wmi.h  |   3 +
 3 files changed, 78 insertions(+), 139 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index c31c47fb5a73..6c034071cc6d 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -2321,5 +2321,18 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
 	return NULL;
 }
 
+static int ath12k_init(void)
+{
+	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/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 8e13c3ec1cc7..e74b9ff3956d 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -15,6 +15,7 @@
 #include <linux/time.h>
 #include <linux/of.h>
 #include <linux/cleanup.h>
+#include <linux/percpu.h>
 #include "core.h"
 #include "debugfs.h"
 #include "debug.h"
@@ -134,6 +135,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 +292,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 +3904,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 +5708,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 +5718,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 +5801,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 +5811,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 +5840,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 +5849,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 +5873,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 +5980,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 +6013,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 +6031,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 +6045,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 +6079,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 +6089,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 +6099,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 +6108,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 +6119,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 +6129,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 +6145,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 +6155,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 +6171,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 +6181,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 +6324,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 +6334,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 +6343,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 +6505,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 +6515,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 +6526,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 +6536,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 +6546,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 +6553,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 +6563,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 +6573,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 +6580,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 +6613,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 +6623,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 +6639,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 +6650,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 +6660,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 +6677,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 +6688,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 +6698,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 +6707,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 +6717,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 +6727,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 +6750,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 +6759,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 +6771,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 +8522,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 +8532,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 +8545,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 +8616,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 +8628,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 +8637,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 +8648,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 +8659,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 +8697,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 +8707,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 +8718,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 +8735,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 +8744,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 +8776,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 +8788,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 +8803,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 +8816,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 +8823,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 +8834,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 +8844,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 +8868,6 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
 
 unlock:
 	rcu_read_unlock();
-out:
-	kfree(tb);
 	return ret;
 }
 
@@ -8948,7 +8878,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 +8886,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 +8900,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 +8915,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 +8926,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 +8941,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 +8952,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 +9030,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 +9040,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 +9049,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 +9064,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 +9075,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 +9086,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 +9104,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 +9118,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 +9126,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 +11161,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

* [PATCH v6] wifi: ath9k: Obtain system GPIOS from descriptors
From: Linus Walleij @ 2026-03-17  8:45 UTC (permalink / raw)
  To: Jeff Johnson, Andy Shevchenko, Arnd Bergmann, Alban Bedel,
	Bartosz Golaszewski, Toke Høiland-Jørgensen,
	Michał Kępień
  Cc: linux-wireless, brcm80211-dev-list.pdl, linux-gpio,
	Bartosz Golaszewski, Linus Walleij

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>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.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 Jeff can merge this to the Wireless tree if we agree on this
hack solution.

Michal: can you test this? It would be great.
---
Changes in v6:
- Fix the kernel test robot warning that I missed...
- Link to v5: https://lore.kernel.org/r/20260316-descriptors-wireless-v5-1-3f791c6b0cba@kernel.org

Changes in v5:
- Collect Bartosz ACK
- Switch Kalle->Jeff as maintainer.
- Link to v4: https://lore.kernel.org/r/20260313-descriptors-wireless-v4-1-07ab47c89a98@kernel.org

Changes in v4:
- Fix review comments from Andy.
- Collect ACKs.
- 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
---
 drivers/gpio/gpio-ath79.c           | 57 ++++++++++++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath9k/hw.c | 33 ++++++++++++++-------
 drivers/net/wireless/ath/ath9k/hw.h |  3 +-
 3 files changed, 80 insertions(+), 13 deletions(-)

diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 2ad9f6ac6636..85bd994d15d4 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -11,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/gpio/driver.h>
 #include <linux/gpio/generic.h>
+#include <linux/gpio/machine.h> /* For WLAN GPIOs */
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/mod_devicetable.h>
@@ -214,6 +215,56 @@ static const struct of_device_id ath79_gpio_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
 
+#if IS_ENABLED(CONFIG_ATH9K_AHB)
+/*
+ * This registers all of the ath79k GPIOs as descriptors to be picked
+ * directly from the ATH79K wifi driver if the two are jitted together
+ * in the same SoC.
+ */
+#define ATH79K_WIFI_DESCS 32
+static int ath79_gpio_register_wifi_descriptors(struct device *dev,
+						const char *label)
+{
+	struct gpiod_lookup_table *lookup;
+	int i;
+
+	/* Create a gpiod lookup using gpiochip-local offsets + 1 for NULL */
+	lookup = devm_kzalloc(dev,
+			      struct_size(lookup, table, ATH79K_WIFI_DESCS + 1),
+			      GFP_KERNEL);
+	if (!lookup)
+		return -ENOMEM;
+
+	/*
+	 * Ugly system-wide lookup for the NULL device: we know this
+	 * is already NULL but explicitly assign it here for people to
+	 * know what is going on. (Yes this is an ugly legacy hack, live
+	 * with it.)
+	 */
+	lookup->dev_id = NULL;
+
+	for (i = 0; i < ATH79K_WIFI_DESCS; i++) {
+		lookup->table[i] =
+			/*
+			 * Set the HW offset on the chip and the lookup
+			 * index to the same value, so looking up index 0
+			 * will get HW offset 0, index 1 HW offset 1 etc.
+			 */
+			GPIO_LOOKUP_IDX(label, i, "ath9k", i, GPIO_ACTIVE_HIGH);
+	}
+
+	gpiod_add_lookup_table(lookup);
+
+	return 0;
+}
+#else
+static int ath79_gpio_register_wifi_descriptors(struct device *dev,
+						const char *label)
+{
+	return 0;
+}
+#endif
+
 static int ath79_gpio_probe(struct platform_device *pdev)
 {
 	struct gpio_generic_chip_config config;
@@ -276,7 +327,11 @@ static int ath79_gpio_probe(struct platform_device *pdev)
 		girq->handler = handle_simple_irq;
 	}
 
-	return devm_gpiochip_add_data(dev, &ctrl->chip.gc, ctrl);
+	err = devm_gpiochip_add_data(dev, &ctrl->chip.gc, ctrl);
+	if (err)
+		return err;
+
+	return ath79_gpio_register_wifi_descriptors(dev, ctrl->chip.gc.label);
 }
 
 static struct platform_driver ath79_gpio_driver = {
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index a45351afcf6e..05c95e67a853 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -21,7 +21,7 @@
 #include <linux/time.h>
 #include <linux/bitops.h>
 #include <linux/etherdevice.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/unaligned.h>
 
 #include "hw.h"
@@ -2719,19 +2719,28 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type)
 static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out,
 				  const char *label)
 {
+	enum gpiod_flags flags = out ? GPIOD_OUT_LOW : GPIOD_IN;
+	struct gpio_desc *gpiod;
 	int err;
 
-	if (ah->caps.gpio_requested & BIT(gpio))
+	if (ah->gpiods[gpio])
 		return;
 
-	err = devm_gpio_request_one(ah->dev, gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label);
+	/*
+	 * Obtains a system specific GPIO descriptor from another GPIO controller.
+	 * Ideally this should come from the device tree, this is a legacy code
+	 * path.
+	 */
+	gpiod = gpiod_get_index(NULL, "ath9k", gpio, flags);
+	err = PTR_ERR_OR_ZERO(gpiod);
 	if (err) {
 		ath_err(ath9k_hw_common(ah), "request GPIO%d failed:%d\n",
 			gpio, err);
 		return;
 	}
 
-	ah->caps.gpio_requested |= BIT(gpio);
+	gpiod_set_consumer_name(gpiod, label);
+	ah->gpiods[gpio] = gpiod;
 }
 
 static void ath9k_hw_gpio_cfg_wmac(struct ath_hw *ah, u32 gpio, bool out,
@@ -2791,10 +2800,12 @@ void ath9k_hw_gpio_free(struct ath_hw *ah, u32 gpio)
 	if (!AR_SREV_SOC(ah))
 		return;
 
-	WARN_ON(gpio >= ah->caps.num_gpio_pins);
+	if (ah->gpiods[gpio]) {
+		gpiod_put(ah->gpiods[gpio]);
+		ah->gpiods[gpio] = NULL;
+	}
 
-	if (ah->caps.gpio_requested & BIT(gpio))
-		ah->caps.gpio_requested &= ~BIT(gpio);
+	WARN_ON(gpio >= ah->caps.num_gpio_pins);
 }
 EXPORT_SYMBOL(ath9k_hw_gpio_free);
 
@@ -2822,8 +2833,8 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
 			val = REG_READ(ah, AR_GPIO_IN(ah)) & BIT(gpio);
 		else
 			val = MS_REG_READ(AR, gpio);
-	} else if (BIT(gpio) & ah->caps.gpio_requested) {
-		val = gpio_get_value(gpio) & BIT(gpio);
+	} else if (ah->gpiods[gpio]) {
+		val = gpiod_get_value(ah->gpiods[gpio]);
 	} else {
 		WARN_ON(1);
 	}
@@ -2846,8 +2857,8 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
 			AR7010_GPIO_OUT : AR_GPIO_IN_OUT(ah);
 
 		REG_RMW(ah, out_addr, val << gpio, BIT(gpio));
-	} else if (BIT(gpio) & ah->caps.gpio_requested) {
-		gpio_set_value(gpio, val);
+	} else if (ah->gpiods[gpio]) {
+		gpiod_set_value(ah->gpiods[gpio], val);
 	} else {
 		WARN_ON(1);
 	}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index eaa07d6dbde0..d9d2f64c5570 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -19,6 +19,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/io.h>
 #include <linux/firmware.h>
 
@@ -302,7 +303,6 @@ struct ath9k_hw_capabilities {
 	u8 max_rxchains;
 	u8 num_gpio_pins;
 	u32 gpio_mask;
-	u32 gpio_requested;
 	u8 rx_hp_qdepth;
 	u8 rx_lp_qdepth;
 	u8 rx_status_len;
@@ -783,6 +783,7 @@ struct ath_hw {
 	struct ath9k_hw_capabilities caps;
 	struct ath9k_channel channels[ATH9K_NUM_CHANNELS];
 	struct ath9k_channel *curchan;
+	struct gpio_desc *gpiods[32];
 
 	union {
 		struct ar5416_eeprom_def def;

---
base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
change-id: 20240122-descriptors-wireless-b8da95dcab35

Best regards,
-- 
Linus Walleij <linusw@kernel.org>


^ permalink raw reply related

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

> On 17 Mar 2026, at 5:37 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> 
> Christian Hewitt <christianshewitt@gmail.com> wrote:
>>> 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.
> 
> My changes do retry for 5 times, because your patch does 3 times retry plus
> additional 500ms delay. I feel you want around 5 seconds for loading BT module.

Understood.

> Did you mean for now you can't reproduce the situation that long loading
> time of BT module? (But it took long time days ago?)

I’ve never noticed a long loading time for the BT module and timings seem
to be consistent both with and without the patch (and not a problem).

>> Would you like me to send a v2 using your revised version? - or?
> 
> Yes, please help v2.

Thanks, will send v2 later today.

Christian

^ permalink raw reply

* Re: [PATCH ath-next v3] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Baochen Qiang @ 2026-03-17  3:32 UTC (permalink / raw)
  To: Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <DH45I9X47H77.74AIOL6V8R49@gmail.com>



On 3/16/2026 6:57 PM, Nicolas Escande wrote:
> 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.

I would prefer a direct return for now. After all We can always change to your style if
necessary in the future.

> 
>>
>>> +}
>>> +
>>> +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: RTL8852BE fails to power on: "xtal si not ready" on ASUS TUF GAMING B650-PLUS WIFI
From: Ping-Ke Shih @ 2026-03-17  3:03 UTC (permalink / raw)
  To: Jason Kakandris, linux-wireless@vger.kernel.org
In-Reply-To: <CAFR=mzkTDNVwypi_PvUw2PX0MM_ck0H61+PUAdJoo6h3yZfggw@mail.gmail.com>

Jason Kakandris <ikakandris@gmail.com> wrote:
> 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/d2f175eafa0a4ef9cc65e7073a77e60238c
> ae614)
> 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)

It looks like you didn't encounter D3Cold problem, but I think you can
give it a try [1].

[1] https://bugzilla.kernel.org/show_bug.cgi?id=221213

> 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

These messages appear when first booting or after system resume?
Recently we update something related to suspend/resume problem.
Please use the latest driver (kernel 7.0-rc4) with the latest
firmware (v0.29.29.15).

> 
> 
> 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

As you try this, please ensure that add a configuration file to /etc/module.d/,
and cold reboot.

> 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: [RFC PATCH v3 1/4] wifi: rtl8xxxu: move dynamic_tx_rpt_timing_counter from ra_info to priv
From: Ping-Ke Shih @ 2026-03-17  2:52 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: <3724d77a-8aa4-40ec-9a4a-644cb1439837@gmx.net>

Georg Müller <georgmueller@gmx.net> wrote:
> 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#L
> 285
> [3]
> https://lore.kernel.org/linux-wireless/938ae608-a865-4056-06de-c230d74e1847@
> gmail.com/
> 

Thanks for the info. I can't find the log internally, so let's keep it 
as github does.

Ping-Ke


^ permalink raw reply

* RE: [PATCH] wifi: rtw89: retry efuse physical map dump on transient failure
From: Ping-Ke Shih @ 2026-03-17  1:37 UTC (permalink / raw)
  To: Christian Hewitt
  Cc: Bitterblue Smith, linux-wireless@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <86F91944-A4B0-46D6-B2DE-7391EB5B38A7@gmail.com>


Christian Hewitt <christianshewitt@gmail.com> wrote:
> > 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.

My changes do retry for 5 times, because your patch does 3 times retry plus
additional 500ms delay. I feel you want around 5 seconds for loading BT module.

Did you mean for now you can't reproduce the situation that long loading
time of BT module? (But it took long time days ago?)

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

Yes, please help v2.

Ping-Ke


^ permalink raw reply

* RE: [PATCH rtw-next] wifi: rtw88: add quirks to disable PCI ASPM and deep LPS for HP P3S95EA#ACB
From: Ping-Ke Shih @ 2026-03-17  1:31 UTC (permalink / raw)
  To: LB F; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <CALdGYqTbH1NVW7HT8JaUJ2xay5190WmpOm1TH7YJP9LfoHoFLw@mail.gmail.com>

LB F <goainwo@gmail.com> wrote:
> 
> Ping-Ke Shih <pkshih@realtek.com> wrote:
> > On an HP laptop (P3S95EA#ACB) equipped with a Realtek RTL8821CE 802.11ac
> > PCIe adapter (PCI ID: 10ec:c821), the system experiences a hard lockup
> > (complete freeze of the UI and kernel, sysrq doesn't work, requires
> > holding the power button) when the WiFi adapter enters the power
> > saving state. Disable PCI ASPM to avoid system freeze.
> > In addition, driver throws messages periodically. Though this doesn't
> > always cause unstable connection, missing H2C commands might cause
> > unpredictable results. Disable deep LPS to avoid this as well.
> 
> Tested on HP Notebook P3S95EA#ACB (kernel 6.19.7-1-cachyos):
> 
>   - No hard freeze observed during idle or active usage.
>   - Zero h2c or lps errors in dmesg across idle (10 min),
>     load stress (100MB download), and suspend/resume cycle.
>   - Both quirk flags confirmed active via sysfs without any
>     manual modprobe parameters.

Thanks for your test. I'd add this information to commit message
during getting merged. 

> 
> Tested-by: Oleksandr Havrylov <goainwo@gmail.com>
> 

As well as your Tested-by.

Ping-Ke


^ permalink raw reply

* RE: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: Ping-Ke Shih @ 2026-03-17  1:28 UTC (permalink / raw)
  To: LB F; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CALdGYqSMUPnPfW-_q1RgYr0_SjoXUejAaJJr-o+jpwCk1S7ndQ@mail.gmail.com>

LB F <goainwo@gmail.com> wrote:
> 
> Ping-Ke Shih <pkshih@realtek.com> wrote:
> > Not sure if this is because PCIE bridge has no ASPM capability?
> 
> That could indeed be the case -- I do not have a way to confirm
> without further hardware-level inspection.
> 
> > LN5491 (kernel v6.19.6) is:
> >                 case RX_ENC_VHT:
> >                         if (WARN_ONCE(status->rate_idx > 11 ||
> >                                       !status->nss ||
> >                                       status->nss > 8,
> >                                       "Rate marked as a VHT rate but data is
> invalid: MCS: %d, NSS: %d\n",
> >                                       status->rate_idx, status->nss))
> >                                 goto drop;
> >                         break;
> > Looks like driver reports improper VHT nss/rate? But this warns once, and
> > you message isn't like this.
> > Could you check the source code LN5491 you are using?
> 
> The file net/mac80211/rx.c is not available on disk on my system
> (CachyOS ships only .h files in the headers package), but I located
> the exact warning message in journalctl:
> 
>   Rate marked as a VHT rate but data is invalid: MCS: 0, NSS: 0
> 
> This confirms that line 5491 in my kernel matches exactly what you
> showed from v6.19.6 -- the RX_ENC_VHT case checking for
> status->nss == 0. The offset in my trace is slightly different
> (+0x183 vs +0x177), which is likely due to CachyOS's LTO/AutoFDO
> compiler optimizations.
> 
> The warning appeared once in my initial test session:
> 
>   Rate marked as a VHT rate but data is invalid: MCS: 0, NSS: 0
>   WARNING: net/mac80211/rx.c:5491 at ieee80211_rx_list+0x183/0x1020 [mac80211]
> 
> However, in subsequent module reload and reconnect cycles I was unable
> to reproduce it. This is consistent with WARN_ONCE behavior -- it
> likely fired on the first invalid nss=0 packet after the initial
> driver load and has not triggered since. I cannot confirm it as a
> reliable symptom.

To reproduce this reliable, you need to remove driver ko and mac80211.ko,
and reinstall them.

However, you have confirmed this is the symptom. I think only if you
want to dig why the rate reported by hardware is weird, otherwise we
can ignore this warning.

> 
> ---
> 
> Regarding patch stability: the results below are from testing your
> original RFT patch [1], not any newer submission. I want to be
> explicit to avoid confusion:
> 
>   [1]
> https://lore.kernel.org/linux-wireless/20260311020816.7065-1-pkshih@realtek.
> com/
> 
> This is the exact diff I compiled and tested:
> 
> --- a/drivers/net/wireless/realtek/rtw88/pci.c
> +++ b/drivers/net/wireless/realtek/rtw88/pci.c
> @@ -2,6 +2,7 @@
>  /* Copyright(c) 2018-2019  Realtek Corporation
>   */
> 
> +#include <linux/dmi.h>
>  #include <linux/module.h>
>  #include <linux/pci.h>
>  #include "main.h"
> @@ -1744,6 +1745,34 @@ const struct pci_error_handlers rtw_pci_err_handler = {
>  };
>  EXPORT_SYMBOL(rtw_pci_err_handler);
> 
> +enum rtw88_quirk_dis_pci_caps {
> + QUIRK_DIS_PCI_CAP_ASPM,
> +};
> +
> +static int disable_pci_caps(const struct dmi_system_id *dmi)
> +{
> + uintptr_t dis_caps = (uintptr_t)dmi->driver_data;
> +
> + if (dis_caps & BIT(QUIRK_DIS_PCI_CAP_ASPM))
> + rtw_pci_disable_aspm = true;
> +
> + return 1;
> +}
> +
> +static const struct dmi_system_id rtw88_pci_quirks[] = {
> + {
> + .callback = disable_pci_caps,
> + .ident = "HP Notebook - P3S95EA#ACB",
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "HP"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "HP Notebook"),
> + DMI_MATCH(DMI_PRODUCT_SKU, "P3S95EA#ACB"),
> + },
> + .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM),
> + },
> + {}
> +};
> +
>  int rtw_pci_probe(struct pci_dev *pdev,
>     const struct pci_device_id *id)
>  {
> @@ -1808,6 +1837,7 @@ int rtw_pci_probe(struct pci_dev *pdev,
>       bridge && bridge->vendor == PCI_VENDOR_ID_INTEL)
>   rtwpci->rx_no_aspm = true;
> 
> + dmi_check_system(rtw88_pci_quirks);
>   rtw_pci_phy_cfg(rtwdev);
> 
>   ret = rtw_register_hw(rtwdev, hw);
> 
> Results with only this patch applied:
> 
>   - The hard freeze lockup is gone.
>   - However, during idle the logs are flooded with:
> 
>       rtw88_8821ce 0000:13:00.0: failed to send h2c command
>       rtw88_8821ce 0000:13:00.0: firmware failed to leave lps state
> 
>   - To give a concrete sense of the volume: over an ~80-minute
>     observation window after a clean module reload, I recorded
>     11,757 "failed to send h2c command" events and 2 "firmware
>     failed to leave lps state" events -- approximately 110 errors
>     per minute during active periods.
>   - These errors cause Bluetooth audio stuttering and WiFi
>     throughput drops.
> 
> When I additionally set disable_lps_deep=Y alongside your ASPM patch,
> all h2c errors vanish completely and Bluetooth/WiFi remain fully
> stable. This confirms that disabling LPS Deep is necessary for
> complete stability on this specific HP SKU.
> 
> I also noticed what appears to be a new patch in a separate mailing
> list thread. I will test it shortly and report back with the results.

Thanks for your experiments in detail. :)

Ping-Ke


^ permalink raw reply

* Re: [PATCH rtw-next] wifi: rtw88: add quirks to disable PCI ASPM and deep LPS for HP P3S95EA#ACB
From: LB F @ 2026-03-17  0:48 UTC (permalink / raw)
  To: Ping-Ke Shih; +Cc: linux-wireless
In-Reply-To: <20260316035635.16550-1-pkshih@realtek.com>

Ping-Ke Shih <pkshih@realtek.com> wrote:
> On an HP laptop (P3S95EA#ACB) equipped with a Realtek RTL8821CE 802.11ac
> PCIe adapter (PCI ID: 10ec:c821), the system experiences a hard lockup
> (complete freeze of the UI and kernel, sysrq doesn't work, requires
> holding the power button) when the WiFi adapter enters the power
> saving state. Disable PCI ASPM to avoid system freeze.
> In addition, driver throws messages periodically. Though this doesn't
> always cause unstable connection, missing H2C commands might cause
> unpredictable results. Disable deep LPS to avoid this as well.

Tested on HP Notebook P3S95EA#ACB (kernel 6.19.7-1-cachyos):

  - No hard freeze observed during idle or active usage.
  - Zero h2c or lps errors in dmesg across idle (10 min),
    load stress (100MB download), and suspend/resume cycle.
  - Both quirk flags confirmed active via sysfs without any
    manual modprobe parameters.

Tested-by: Oleksandr Havrylov <goainwo@gmail.com>

Best regards,
Oleksandr Havrylov

^ permalink raw reply

* Re: [PATCH v2 0/4] Use the QMI service IDs from the QMI header
From: Jakub Kicinski @ 2026-03-17  0:22 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: konradybcio, andersson, linux-kernel, Alex Elder, Andrew Lunn,
	David S. Miller, Eric Dumazet, 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
In-Reply-To: <20260316171419.2619620-1-daniel.lezcano@oss.qualcomm.com>

On Mon, 16 Mar 2026 18:14:10 +0100 Daniel Lezcano wrote:
> 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 ?

Wait for the dependency to appear in respective trees after the merge
window then repost the patches individually. I'm starting to get
annoyed with all this cross-tree QMI/MHI noise.

^ permalink raw reply

* Re: [PATCH v2 02/15] firmware: qcom: Add a generic PAS service
From: Trilok Soni @ 2026-03-16 23:02 UTC (permalink / raw)
  To: Krzysztof Kozlowski, 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, 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: <28d63822-f191-400a-8005-5185dd480dbb@kernel.org>

On 3/16/2026 12:51 AM, Krzysztof Kozlowski wrote:
> 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.

I agree, no globals here please. 

> 
> Best regards,
> Krzysztof


^ permalink raw reply

* Re: [PATCH 46/61] vfio: Prefer IS_ERR_OR_NULL over manual NULL check
From: Alex Williamson @ 2026-03-16 22:10 UTC (permalink / raw)
  To: Philipp Hahn
  Cc: 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, alex
In-Reply-To: <20260310-b4-is_err_or_null-v1-46-bd63b656022d@avm.de>

On Tue, 10 Mar 2026 12:49:12 +0100
Philipp Hahn <phahn-oss@avm.de> wrote:

> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.
> 
> Change generated with coccinelle.
> 
> To: Alex Williamson <alex@shazbot.org>
> Cc: kvm@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
> ---
>  drivers/vfio/vfio_main.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
> index 742477546b15d4dbaf9ebcfb2e67627db71521e0..d71922dfde5885967398deddec3e9e04b05adfec 100644
> --- a/drivers/vfio/vfio_main.c
> +++ b/drivers/vfio/vfio_main.c
> @@ -923,7 +923,7 @@ vfio_ioctl_device_feature_mig_device_state(struct vfio_device *device,
>  
>  	/* Handle the VFIO_DEVICE_FEATURE_SET */
>  	filp = device->mig_ops->migration_set_state(device, mig.device_state);
> -	if (IS_ERR(filp) || !filp)
> +	if (IS_ERR_OR_NULL(filp))
>  		goto out_copy;
>  
>  	return vfio_ioct_mig_return_fd(filp, arg, &mig);
> 

As others have expressed in general, this doesn't seem to be cleaner
and tends to mask that we consider IS_ERR() and NULL as separate cases
in the goto.  This code looks like it could use some refactoring, and
likely that refactoring should handle the IS_ERR() and NULL cases
separately, but conflating them here is not an improvement.  Thanks,

Alex

^ permalink raw reply

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

On Mon, Mar 16, 2026 at 09:56:58PM +0100, Linus Walleij wrote:
> 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.

...

> Changes in v5:
> - Collect Bartosz ACK
> - Switch Kalle->Jeff as maintainer.
> - Link to v4: https://lore.kernel.org/r/20260313-descriptors-wireless-v4-1-07ab47c89a98@kernel.org

Seems you forgot to address the LKP report.

> +static int ath79_gpio_register_wifi_descriptors(struct device *dev,
> +						const char *label)
> +{

Should be return SOMETHING; here.

> +}
> +#endif


-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* [wireless-next:main] BUILD SUCCESS d3947aac97c3e57ee2f85fd1bef8e7674e609c45
From: kernel test robot @ 2026-03-16 21:15 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
branch HEAD: d3947aac97c3e57ee2f85fd1bef8e7674e609c45  wifi: nl80211: reject S1G/60G with HT chantype

elapsed time: 1560m

configs tested: 144
configs skipped: 3

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
arc                   randconfig-001-20260317    gcc-9.5.0
arc                   randconfig-002-20260317    gcc-13.4.0
arm                               allnoconfig    clang-23
arm                              allyesconfig    gcc-15.2.0
arm                       netwinder_defconfig    gcc-15.2.0
arm                   randconfig-001-20260317    clang-23
arm                   randconfig-002-20260317    clang-23
arm                   randconfig-003-20260317    clang-23
arm                   randconfig-004-20260317    clang-23
arm64                            allmodconfig    clang-19
arm64                             allnoconfig    gcc-15.2.0
arm64                 randconfig-001-20260317    clang-23
arm64                 randconfig-002-20260317    clang-23
arm64                 randconfig-003-20260317    clang-23
arm64                 randconfig-004-20260317    clang-16
csky                             allmodconfig    gcc-15.2.0
csky                              allnoconfig    gcc-15.2.0
csky                  randconfig-001-20260317    gcc-15.2.0
csky                  randconfig-002-20260317    gcc-15.2.0
hexagon                          allmodconfig    clang-17
hexagon                           allnoconfig    clang-23
hexagon               randconfig-001-20260317    clang-23
hexagon               randconfig-002-20260317    clang-23
i386                              allnoconfig    gcc-14
i386                             allyesconfig    gcc-14
i386        buildonly-randconfig-001-20260317    clang-20
i386        buildonly-randconfig-002-20260317    clang-20
i386        buildonly-randconfig-003-20260317    clang-20
i386        buildonly-randconfig-004-20260317    clang-20
i386        buildonly-randconfig-005-20260317    clang-20
i386        buildonly-randconfig-006-20260317    clang-20
i386                  randconfig-001-20260316    gcc-14
i386                  randconfig-002-20260316    clang-20
i386                  randconfig-003-20260316    gcc-14
i386                  randconfig-004-20260316    gcc-14
i386                  randconfig-005-20260316    clang-20
i386                  randconfig-006-20260316    gcc-12
i386                  randconfig-007-20260316    gcc-14
i386                  randconfig-011-20260317    gcc-14
i386                  randconfig-012-20260317    gcc-14
i386                  randconfig-013-20260317    gcc-14
i386                  randconfig-014-20260317    clang-20
i386                  randconfig-015-20260317    clang-20
i386                  randconfig-016-20260317    gcc-14
i386                  randconfig-017-20260317    clang-20
loongarch                        allmodconfig    clang-19
loongarch                         allnoconfig    clang-23
loongarch             randconfig-001-20260317    clang-23
loongarch             randconfig-002-20260317    clang-18
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
nios2                 randconfig-001-20260317    gcc-8.5.0
nios2                 randconfig-002-20260317    gcc-11.5.0
openrisc                         allmodconfig    gcc-15.2.0
openrisc                          allnoconfig    gcc-15.2.0
openrisc                            defconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    gcc-15.2.0
parisc                           allyesconfig    gcc-15.2.0
parisc                              defconfig    gcc-15.2.0
parisc                randconfig-001-20260316    gcc-8.5.0
parisc                randconfig-001-20260317    gcc-11.5.0
parisc                randconfig-002-20260316    gcc-12.5.0
parisc                randconfig-002-20260317    gcc-14.3.0
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    gcc-15.2.0
powerpc               randconfig-001-20260316    clang-23
powerpc               randconfig-001-20260317    gcc-8.5.0
powerpc               randconfig-002-20260316    clang-23
powerpc               randconfig-002-20260317    clang-23
powerpc64             randconfig-001-20260316    gcc-13.4.0
powerpc64             randconfig-001-20260317    gcc-8.5.0
powerpc64             randconfig-002-20260316    gcc-8.5.0
powerpc64             randconfig-002-20260317    clang-23
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    gcc-15.2.0
riscv                            allyesconfig    clang-16
riscv                               defconfig    clang-23
riscv                 randconfig-001-20260317    clang-23
riscv                 randconfig-002-20260317    gcc-8.5.0
s390                             allmodconfig    clang-18
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-15.2.0
s390                                defconfig    clang-23
s390                  randconfig-001-20260317    gcc-15.2.0
s390                  randconfig-002-20260317    clang-23
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    gcc-15.2.0
sh                               allyesconfig    gcc-15.2.0
sh                                  defconfig    gcc-15.2.0
sh                    randconfig-001-20260317    gcc-15.2.0
sh                    randconfig-002-20260317    gcc-10.5.0
sparc                             allnoconfig    gcc-15.2.0
sparc                               defconfig    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                                  defconfig    clang-23
um                    randconfig-001-20260316    gcc-14
um                    randconfig-002-20260316    clang-23
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-20
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20260317    clang-20
x86_64      buildonly-randconfig-002-20260317    gcc-14
x86_64      buildonly-randconfig-003-20260317    clang-20
x86_64      buildonly-randconfig-004-20260317    clang-20
x86_64      buildonly-randconfig-005-20260317    clang-20
x86_64      buildonly-randconfig-006-20260317    gcc-14
x86_64                randconfig-011-20260317    gcc-14
x86_64                randconfig-012-20260317    clang-20
x86_64                randconfig-013-20260317    clang-20
x86_64                randconfig-014-20260317    gcc-14
x86_64                randconfig-015-20260317    clang-20
x86_64                randconfig-016-20260317    clang-20
x86_64                randconfig-071-20260316    gcc-12
x86_64                randconfig-072-20260316    gcc-14
x86_64                randconfig-073-20260316    gcc-14
x86_64                randconfig-074-20260316    gcc-14
x86_64                randconfig-075-20260316    clang-20
x86_64                randconfig-076-20260316    clang-20
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    gcc-15.2.0
xtensa                           allyesconfig    gcc-15.2.0
xtensa                randconfig-001-20260316    gcc-15.2.0
xtensa                randconfig-002-20260316    gcc-15.2.0

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

^ permalink raw reply

* [PATCH v5] wifi: ath9k: Obtain system GPIOS from descriptors
From: Linus Walleij @ 2026-03-16 20:56 UTC (permalink / raw)
  To: Jeff Johnson, Andy Shevchenko, Arnd Bergmann, Alban Bedel,
	Bartosz Golaszewski, Toke Høiland-Jørgensen,
	Michał Kępień
  Cc: linux-wireless, brcm80211-dev-list.pdl, linux-gpio,
	Bartosz Golaszewski, Linus Walleij

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>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.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 Jeff can merge this to the Wireless tree if we agree on this
hack solution.

Michal: can you test this? It would be great.
---
Changes in v5:
- Collect Bartosz ACK
- Switch Kalle->Jeff as maintainer.
- Link to v4: https://lore.kernel.org/r/20260313-descriptors-wireless-v4-1-07ab47c89a98@kernel.org

Changes in v4:
- Fix review comments from Andy.
- Collect ACKs.
- 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
---
 drivers/gpio/gpio-ath79.c           | 56 ++++++++++++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath9k/hw.c | 33 ++++++++++++++--------
 drivers/net/wireless/ath/ath9k/hw.h |  3 +-
 3 files changed, 79 insertions(+), 13 deletions(-)

diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 2ad9f6ac6636..7c10fa282ad2 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -11,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/gpio/driver.h>
 #include <linux/gpio/generic.h>
+#include <linux/gpio/machine.h> /* For WLAN GPIOs */
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/mod_devicetable.h>
@@ -214,6 +215,55 @@ static const struct of_device_id ath79_gpio_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
 
+#if IS_ENABLED(CONFIG_ATH9K_AHB)
+/*
+ * This registers all of the ath79k GPIOs as descriptors to be picked
+ * directly from the ATH79K wifi driver if the two are jitted together
+ * in the same SoC.
+ */
+#define ATH79K_WIFI_DESCS 32
+static int ath79_gpio_register_wifi_descriptors(struct device *dev,
+						const char *label)
+{
+	struct gpiod_lookup_table *lookup;
+	int i;
+
+	/* Create a gpiod lookup using gpiochip-local offsets + 1 for NULL */
+	lookup = devm_kzalloc(dev,
+			      struct_size(lookup, table, ATH79K_WIFI_DESCS + 1),
+			      GFP_KERNEL);
+	if (!lookup)
+		return -ENOMEM;
+
+	/*
+	 * Ugly system-wide lookup for the NULL device: we know this
+	 * is already NULL but explicitly assign it here for people to
+	 * know what is going on. (Yes this is an ugly legacy hack, live
+	 * with it.)
+	 */
+	lookup->dev_id = NULL;
+
+	for (i = 0; i < ATH79K_WIFI_DESCS; i++) {
+		lookup->table[i] =
+			/*
+			 * Set the HW offset on the chip and the lookup
+			 * index to the same value, so looking up index 0
+			 * will get HW offset 0, index 1 HW offset 1 etc.
+			 */
+			GPIO_LOOKUP_IDX(label, i, "ath9k", i, GPIO_ACTIVE_HIGH);
+	}
+
+	gpiod_add_lookup_table(lookup);
+
+	return 0;
+}
+#else
+static int ath79_gpio_register_wifi_descriptors(struct device *dev,
+						const char *label)
+{
+}
+#endif
+
 static int ath79_gpio_probe(struct platform_device *pdev)
 {
 	struct gpio_generic_chip_config config;
@@ -276,7 +326,11 @@ static int ath79_gpio_probe(struct platform_device *pdev)
 		girq->handler = handle_simple_irq;
 	}
 
-	return devm_gpiochip_add_data(dev, &ctrl->chip.gc, ctrl);
+	err = devm_gpiochip_add_data(dev, &ctrl->chip.gc, ctrl);
+	if (err)
+		return err;
+
+	return ath79_gpio_register_wifi_descriptors(dev, ctrl->chip.gc.label);
 }
 
 static struct platform_driver ath79_gpio_driver = {
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index a45351afcf6e..05c95e67a853 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -21,7 +21,7 @@
 #include <linux/time.h>
 #include <linux/bitops.h>
 #include <linux/etherdevice.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/unaligned.h>
 
 #include "hw.h"
@@ -2719,19 +2719,28 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type)
 static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out,
 				  const char *label)
 {
+	enum gpiod_flags flags = out ? GPIOD_OUT_LOW : GPIOD_IN;
+	struct gpio_desc *gpiod;
 	int err;
 
-	if (ah->caps.gpio_requested & BIT(gpio))
+	if (ah->gpiods[gpio])
 		return;
 
-	err = devm_gpio_request_one(ah->dev, gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label);
+	/*
+	 * Obtains a system specific GPIO descriptor from another GPIO controller.
+	 * Ideally this should come from the device tree, this is a legacy code
+	 * path.
+	 */
+	gpiod = gpiod_get_index(NULL, "ath9k", gpio, flags);
+	err = PTR_ERR_OR_ZERO(gpiod);
 	if (err) {
 		ath_err(ath9k_hw_common(ah), "request GPIO%d failed:%d\n",
 			gpio, err);
 		return;
 	}
 
-	ah->caps.gpio_requested |= BIT(gpio);
+	gpiod_set_consumer_name(gpiod, label);
+	ah->gpiods[gpio] = gpiod;
 }
 
 static void ath9k_hw_gpio_cfg_wmac(struct ath_hw *ah, u32 gpio, bool out,
@@ -2791,10 +2800,12 @@ void ath9k_hw_gpio_free(struct ath_hw *ah, u32 gpio)
 	if (!AR_SREV_SOC(ah))
 		return;
 
-	WARN_ON(gpio >= ah->caps.num_gpio_pins);
+	if (ah->gpiods[gpio]) {
+		gpiod_put(ah->gpiods[gpio]);
+		ah->gpiods[gpio] = NULL;
+	}
 
-	if (ah->caps.gpio_requested & BIT(gpio))
-		ah->caps.gpio_requested &= ~BIT(gpio);
+	WARN_ON(gpio >= ah->caps.num_gpio_pins);
 }
 EXPORT_SYMBOL(ath9k_hw_gpio_free);
 
@@ -2822,8 +2833,8 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
 			val = REG_READ(ah, AR_GPIO_IN(ah)) & BIT(gpio);
 		else
 			val = MS_REG_READ(AR, gpio);
-	} else if (BIT(gpio) & ah->caps.gpio_requested) {
-		val = gpio_get_value(gpio) & BIT(gpio);
+	} else if (ah->gpiods[gpio]) {
+		val = gpiod_get_value(ah->gpiods[gpio]);
 	} else {
 		WARN_ON(1);
 	}
@@ -2846,8 +2857,8 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
 			AR7010_GPIO_OUT : AR_GPIO_IN_OUT(ah);
 
 		REG_RMW(ah, out_addr, val << gpio, BIT(gpio));
-	} else if (BIT(gpio) & ah->caps.gpio_requested) {
-		gpio_set_value(gpio, val);
+	} else if (ah->gpiods[gpio]) {
+		gpiod_set_value(ah->gpiods[gpio], val);
 	} else {
 		WARN_ON(1);
 	}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index eaa07d6dbde0..d9d2f64c5570 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -19,6 +19,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/io.h>
 #include <linux/firmware.h>
 
@@ -302,7 +303,6 @@ struct ath9k_hw_capabilities {
 	u8 max_rxchains;
 	u8 num_gpio_pins;
 	u32 gpio_mask;
-	u32 gpio_requested;
 	u8 rx_hp_qdepth;
 	u8 rx_lp_qdepth;
 	u8 rx_status_len;
@@ -783,6 +783,7 @@ struct ath_hw {
 	struct ath9k_hw_capabilities caps;
 	struct ath9k_channel channels[ATH9K_NUM_CHANNELS];
 	struct ath9k_channel *curchan;
+	struct gpio_desc *gpiods[32];
 
 	union {
 		struct ar5416_eeprom_def def;

---
base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
change-id: 20240122-descriptors-wireless-b8da95dcab35

Best regards,
-- 
Linus Walleij <linusw@kernel.org>


^ permalink raw reply related

* Re: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: LB F @ 2026-03-16 20:27 UTC (permalink / raw)
  To: Ping-Ke Shih; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <1bd495ffe57c47eb827eec084729afa2@realtek.com>

Ping-Ke Shih <pkshih@realtek.com> wrote:
> Not sure if this is because PCIE bridge has no ASPM capability?

That could indeed be the case -- I do not have a way to confirm
without further hardware-level inspection.

> LN5491 (kernel v6.19.6) is:
>                 case RX_ENC_VHT:
>                         if (WARN_ONCE(status->rate_idx > 11 ||
>                                       !status->nss ||
>                                       status->nss > 8,
>                                       "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n",
>                                       status->rate_idx, status->nss))
>                                 goto drop;
>                         break;
> Looks like driver reports improper VHT nss/rate? But this warns once, and
> you message isn't like this.
> Could you check the source code LN5491 you are using?

The file net/mac80211/rx.c is not available on disk on my system
(CachyOS ships only .h files in the headers package), but I located
the exact warning message in journalctl:

  Rate marked as a VHT rate but data is invalid: MCS: 0, NSS: 0

This confirms that line 5491 in my kernel matches exactly what you
showed from v6.19.6 -- the RX_ENC_VHT case checking for
status->nss == 0. The offset in my trace is slightly different
(+0x183 vs +0x177), which is likely due to CachyOS's LTO/AutoFDO
compiler optimizations.

The warning appeared once in my initial test session:

  Rate marked as a VHT rate but data is invalid: MCS: 0, NSS: 0
  WARNING: net/mac80211/rx.c:5491 at ieee80211_rx_list+0x183/0x1020 [mac80211]

However, in subsequent module reload and reconnect cycles I was unable
to reproduce it. This is consistent with WARN_ONCE behavior -- it
likely fired on the first invalid nss=0 packet after the initial
driver load and has not triggered since. I cannot confirm it as a
reliable symptom.

---

Regarding patch stability: the results below are from testing your
original RFT patch [1], not any newer submission. I want to be
explicit to avoid confusion:

  [1] https://lore.kernel.org/linux-wireless/20260311020816.7065-1-pkshih@realtek.com/

This is the exact diff I compiled and tested:

--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -2,6 +2,7 @@
 /* Copyright(c) 2018-2019  Realtek Corporation
  */

+#include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include "main.h"
@@ -1744,6 +1745,34 @@ const struct pci_error_handlers rtw_pci_err_handler = {
 };
 EXPORT_SYMBOL(rtw_pci_err_handler);

+enum rtw88_quirk_dis_pci_caps {
+ QUIRK_DIS_PCI_CAP_ASPM,
+};
+
+static int disable_pci_caps(const struct dmi_system_id *dmi)
+{
+ uintptr_t dis_caps = (uintptr_t)dmi->driver_data;
+
+ if (dis_caps & BIT(QUIRK_DIS_PCI_CAP_ASPM))
+ rtw_pci_disable_aspm = true;
+
+ return 1;
+}
+
+static const struct dmi_system_id rtw88_pci_quirks[] = {
+ {
+ .callback = disable_pci_caps,
+ .ident = "HP Notebook - P3S95EA#ACB",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Notebook"),
+ DMI_MATCH(DMI_PRODUCT_SKU, "P3S95EA#ACB"),
+ },
+ .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM),
+ },
+ {}
+};
+
 int rtw_pci_probe(struct pci_dev *pdev,
    const struct pci_device_id *id)
 {
@@ -1808,6 +1837,7 @@ int rtw_pci_probe(struct pci_dev *pdev,
      bridge && bridge->vendor == PCI_VENDOR_ID_INTEL)
  rtwpci->rx_no_aspm = true;

+ dmi_check_system(rtw88_pci_quirks);
  rtw_pci_phy_cfg(rtwdev);

  ret = rtw_register_hw(rtwdev, hw);

Results with only this patch applied:

  - The hard freeze lockup is gone.
  - However, during idle the logs are flooded with:

      rtw88_8821ce 0000:13:00.0: failed to send h2c command
      rtw88_8821ce 0000:13:00.0: firmware failed to leave lps state

  - To give a concrete sense of the volume: over an ~80-minute
    observation window after a clean module reload, I recorded
    11,757 "failed to send h2c command" events and 2 "firmware
    failed to leave lps state" events -- approximately 110 errors
    per minute during active periods.
  - These errors cause Bluetooth audio stuttering and WiFi
    throughput drops.

When I additionally set disable_lps_deep=Y alongside your ASPM patch,
all h2c errors vanish completely and Bluetooth/WiFi remain fully
stable. This confirms that disabling LPS Deep is necessary for
complete stability on this specific HP SKU.

I also noticed what appears to be a new patch in a separate mailing
list thread. I will test it shortly and report back with the results.

Best regards,
Oleksandr Havrylov

^ permalink raw reply

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

On 3/13/2026 2:53 PM, Linus Walleij wrote:
> 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>

Are all of the reported issues fixed? I cab add either a Link or Fixes tag,
presumably referencing:
https://lore.kernel.org/all/Z3t6coHFgd9PBCeb@larwa.hq.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.

-Kalle since he hasn't been a mainainer for a year now. I can take this
through the ath tree, but would love to have a Tested-by from Michał to verify
that the issues he saw have been addressed.

> 
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>


^ permalink raw reply

* [PATCH v2 4/4] ALSA: usb-audio: qcom: 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, Dan Carpenter
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>
---
 sound/usb/qcom/qc_audio_offload.c  | 2 +-
 sound/usb/qcom/usb_audio_qmi_v01.h | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c
index 01e6063c2207..38d36397bb40 100644
--- a/sound/usb/qcom/qc_audio_offload.c
+++ b/sound/usb/qcom/qc_audio_offload.c
@@ -1927,7 +1927,7 @@ static int qc_usb_audio_probe(struct auxiliary_device *auxdev,
 			      QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN,
 			      &uaudio_svc_ops_options,
 			      &uaudio_stream_req_handlers);
-	ret = qmi_add_server(svc->uaudio_svc_hdl, UAUDIO_STREAM_SERVICE_ID_V01,
+	ret = qmi_add_server(svc->uaudio_svc_hdl, QMI_SERVICE_ID_USB_AUDIO_STREAM,
 			     UAUDIO_STREAM_SERVICE_VERS_V01, 0);
 
 	uaudio_svc = svc;
diff --git a/sound/usb/qcom/usb_audio_qmi_v01.h b/sound/usb/qcom/usb_audio_qmi_v01.h
index a1298d75d9f8..c7eee03225ec 100644
--- a/sound/usb/qcom/usb_audio_qmi_v01.h
+++ b/sound/usb/qcom/usb_audio_qmi_v01.h
@@ -6,7 +6,6 @@
 #ifndef USB_QMI_V01_H
 #define USB_QMI_V01_H
 
-#define UAUDIO_STREAM_SERVICE_ID_V01 0x41D
 #define UAUDIO_STREAM_SERVICE_VERS_V01 0x01
 
 #define QMI_UAUDIO_STREAM_RESP_V01 0x0001
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 3/4] slimbus: qcom-ngd-ctrl: 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/slimbus/qcom-ngd-ctrl.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 9aa7218b4e8d..0b88b8577bdb 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -48,7 +48,6 @@
 				NGD_INT_RX_MSG_RCVD)
 
 /* Slimbus QMI service */
-#define SLIMBUS_QMI_SVC_ID	0x0301
 #define SLIMBUS_QMI_SVC_V1	1
 #define SLIMBUS_QMI_INS_ID	0
 #define SLIMBUS_QMI_SELECT_INSTANCE_REQ_V01	0x0020
@@ -1408,8 +1407,8 @@ static int qcom_slim_ngd_qmi_svc_event_init(struct qcom_slim_ngd_ctrl *ctrl)
 		return ret;
 	}
 
-	ret = qmi_add_lookup(&qmi->svc_event_hdl, SLIMBUS_QMI_SVC_ID,
-			SLIMBUS_QMI_SVC_V1, SLIMBUS_QMI_INS_ID);
+	ret = qmi_add_lookup(&qmi->svc_event_hdl, QMI_SERVICE_ID_SLIMBUS,
+			     SLIMBUS_QMI_SVC_V1, SLIMBUS_QMI_INS_ID);
 	if (ret < 0) {
 		dev_err(ctrl->dev, "qmi_add_lookup failed: %d\n", ret);
 		qmi_handle_release(&qmi->svc_event_hdl);
-- 
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