[PATCH v2] wifi: ath11k/ath12k: release QMI handles on late init failures

From: Guangshuo Li

Date: Wed Jul 15 2026 - 02:41:13 EST


ath11k and ath12k initialize their QMI handles before allocating the QMI
event workqueues and registering the service lookups.

If either of these later initialization steps fails, the functions
return without releasing the initialized QMI handles, leaking their
resources.

Release the QMI handles on the late failure paths in both drivers.

ath12k_qmi_deinit_service() uses ab->qmi.ab to determine whether QMI
service initialization completed successfully. Set it only after all
initialization steps succeed. Keep the ath11k assignment unchanged
because ath11k does not use it as an initialization-success guard.

Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Fixes: 088a099690e4 ("wifi: ath12k: fix error handling in creating hardware group")
Signed-off-by: Guangshuo Li <lgs201920130244@xxxxxxxxx>
---
v2:
- Set ath12k ab->qmi.ab only after QMI service initialization succeeds,
as suggested by Baochen Qiang.
- Fix the same late initialization QMI handle leak in ath11k, as
suggested by Vasanthakumar Thiagarajan.
- Drop the Reviewed-by tag due to the code changes.

drivers/net/wireless/ath/ath11k/qmi.c | 10 ++++++++--
drivers/net/wireless/ath/ath12k/qmi.c | 13 ++++++++++---
2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index 410a7ee076a0..6e3f82169d24 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -3329,7 +3329,8 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
ab->qmi.event_wq = alloc_ordered_workqueue("ath11k_qmi_driver_event", 0);
if (!ab->qmi.event_wq) {
ath11k_err(ab, "failed to allocate workqueue\n");
- return -EFAULT;
+ ret = -EFAULT;
+ goto err_release_qmi_handle;
}

INIT_LIST_HEAD(&ab->qmi.event_list);
@@ -3342,9 +3343,14 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
if (ret < 0) {
ath11k_warn(ab, "failed to add qmi lookup: %d\n", ret);
destroy_workqueue(ab->qmi.event_wq);
- return ret;
+ goto err_release_qmi_handle;
}

+ return ret;
+
+err_release_qmi_handle:
+ qmi_handle_release(&ab->qmi.handle);
+
return ret;
}

diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index fd762b5d7bb5..692f1b2c2031 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -4041,7 +4041,6 @@ int ath12k_qmi_init_service(struct ath12k_base *ab)

memset(&ab->qmi.target, 0, sizeof(struct target_info));
memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk));
- ab->qmi.ab = ab;

ab->qmi.target_mem_mode = ab->target_mem_mode;
ret = qmi_handle_init(&ab->qmi.handle, ATH12K_QMI_RESP_LEN_MAX,
@@ -4054,7 +4053,8 @@ int ath12k_qmi_init_service(struct ath12k_base *ab)
ab->qmi.event_wq = alloc_ordered_workqueue("ath12k_qmi_driver_event", 0);
if (!ab->qmi.event_wq) {
ath12k_err(ab, "failed to allocate workqueue\n");
- return -EFAULT;
+ ret = -EFAULT;
+ goto err_release_qmi_handle;
}

INIT_LIST_HEAD(&ab->qmi.event_list);
@@ -4067,9 +4067,16 @@ int ath12k_qmi_init_service(struct ath12k_base *ab)
if (ret < 0) {
ath12k_warn(ab, "failed to add qmi lookup\n");
destroy_workqueue(ab->qmi.event_wq);
- return ret;
+ goto err_release_qmi_handle;
}

+ ab->qmi.ab = ab;
+
+ return ret;
+
+err_release_qmi_handle:
+ qmi_handle_release(&ab->qmi.handle);
+
return ret;
}

--
2.43.0