Re: [RFC PATCH 1/1] wifi: ath12k: avoid dynamic alloc when parsing wmi tb

Pablo MARTIN-GOMEZ
2026-02-26T19:48:07Z

Hello,

On 26/02/2026 17:55, 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, stored in the struct
> ath12k_base, that is reused accros calls. The ath12k_wmi_tlv_parse_alloc()
> is also renamed into / merged with ath12k_wmi_tlv_parse() as it no longer
> allocs memory but returns the existing per-cpu one.
>
> Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
> ---
> drivers/net/wireless/ath/ath12k/core.c | 7 +
> drivers/net/wireless/ath/ath12k/core.h | 2 +
> drivers/net/wireless/ath/ath12k/wmi.c | 170 ++++++-------------------
> 3 files changed, 49 insertions(+), 130 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index 9d6c50a94e64..961c9df69aa1 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -2237,6 +2237,7 @@ void ath12k_core_free(struct ath12k_base *ab)
> timer_delete_sync(&ab->rx_replenish_retry);
> destroy_workqueue(ab->workqueue_aux);
> destroy_workqueue(ab->workqueue);
> + free_percpu(ab->wmi_tb);
> kfree(ab);
> }
>
> @@ -2249,6 +2250,11 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
> if (!ab)
> return NULL;
>
> + ab->wmi_tb = __alloc_percpu(WMI_TAG_MAX * sizeof(void *),
> + __alignof__(void *));
> + if (!ab->wmi_tb)
> + goto err_sc_free;
If `!ab->wmi_tb`, you're going to `free_percpu(ab->wmi_tb)`; it works but it's not super pretty.
> +
> init_completion(&ab->driver_recovery);
>
> ab->workqueue = create_singlethread_workqueue("ath12k_wq");
> @@ -2296,6 +2302,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
> err_free_wq:
> destroy_workqueue(ab->workqueue);
> err_sc_free:
> + free_percpu(ab->wmi_tb);
> kfree(ab);
> return NULL;
> }
[...]
> @@ -6795,11 +6749,9 @@ ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, struct sk_buff *skb,
> ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT];
> if (!ev) {
> ath12k_warn(ab, "failed to fetch pdev temp ev");
> - kfree(tb);
> return -EPROTO;
> }
>
> - kfree(tb);
> return 0;
> }
You're missing a change on `ath12k_reg_11d_new_cc_event` (was added by 591de41d7008585f2e7c35dbcf5922fcb4d79e39)

[...]

Best regards,
Pablo MG