[PATCH ath-next] wifi: ath12k: add support to load shared firmware on multiPD
Vasanthakumar Thiagarajan
vasanthakumar.thiagarajan at oss.qualcomm.com
Tue Aug 11 02:08:28 PDT 2026
On 8/11/2026 11:13 AM, Aaradhana Sahu wrote:
> IPQ5332 platform uses a MultiPD architecture where multiple firmware
> instances share common read-only code segments. The driver currently
> loads only the per-UserPD firmware, which leaves the shared read-only
> firmware unloaded.
>
> Add support for loading the shared read-only firmware once before the
> UserPDs are powered up. The shared segment contains common code that is
> identical across all UserPDs and reduces the total firmware memory
> requirement.
>
> Store the reserved memory mapping in struct ath12k_ahb_rproc_info so it can
> be shared by all UserPDs and mapped only once. Keep the mapping valid
> across UserPD power cycles, and unmap it when the last UserPD is removed.
>
> Shut down the shared firmware from the rproc deconfiguration path when the
> last UserPD is removed.
>
> Also, pass NULL for the reloc_base parameter because the driver uses fixed
> memory regions configured through device tree and does not need the
> adjusted physical address after relocation.
>
> Tested-on: IPQ5332 hw1.0 AHB WLAN.WBE.1.6-01275-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Aaradhana Sahu <aaradhana.sahu at oss.qualcomm.com>
> ---
> drivers/net/wireless/ath/ath12k/ahb.c | 166 +++++++++++++++++---
> drivers/net/wireless/ath/ath12k/ahb.h | 9 ++
> drivers/net/wireless/ath/ath12k/wifi7/ahb.c | 3 +
> 3 files changed, 157 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c
> index 0fc55c9169e1..3985f4e1c067 100644
> --- a/drivers/net/wireless/ath/ath12k/ahb.c
> +++ b/drivers/net/wireless/ath/ath12k/ahb.c
> @@ -347,35 +347,60 @@ static void ath12k_ahb_stop(struct ath12k_base *ab)
> ath12k_ce_cleanup_pipes(ab);
> }
>
> +static int ath12k_ahb_get_fw_load_region(struct ath12k_base *ab)
> +{
> + struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
> + struct ath12k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
> + struct device *dev = ab->dev;
> + struct resource res;
> + int ret;
> +
> + if (rproc_info->mem_region)
> + return 0;
> +
> + ret = of_reserved_mem_region_to_resource_byname(dev->of_node, "q6-region", &res);
> + if (ret)
> + return ret;
> +
> + rproc_info->mem_phys = res.start;
> + rproc_info->mem_size = resource_size(&res);
> + rproc_info->mem_region = memremap(rproc_info->mem_phys, rproc_info->mem_size,
> + MEMREMAP_WC);
> + if (!rproc_info->mem_region) {
> + ath12k_err(ab, "unable to map memory region: %pa+%zx\n",
> + &res.start, rproc_info->mem_size);
> + rproc_info->mem_phys = 0;
> + rproc_info->mem_size = 0;
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +static void ath12k_ahb_put_fw_load_region(struct ath12k_ahb_rproc_info *rproc_info)
> +{
> + memunmap(rproc_info->mem_region);
> + rproc_info->mem_region = NULL;
> + rproc_info->mem_phys = 0;
> + rproc_info->mem_size = 0;
> +}
> +
> static int ath12k_ahb_power_up(struct ath12k_base *ab)
> {
> struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
> + struct ath12k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
> char fw_name[ATH12K_USERPD_FW_NAME_LEN];
> char fw2_name[ATH12K_USERPD_FW_NAME_LEN];
> struct device *dev = ab->dev;
> const struct firmware *fw, *fw2;
> unsigned long time_left;
> - phys_addr_t mem_phys;
> - struct resource res;
> - void *mem_region;
> - size_t mem_size;
> u32 pasid;
> int ret;
>
> - ret = of_reserved_mem_region_to_resource_byname(dev->of_node, "q6-region",
> - &res);
> + ret = ath12k_ahb_get_fw_load_region(ab);
> if (ret)
> return ret;
>
> - mem_phys = res.start;
> - mem_size = resource_size(&res);
> - mem_region = devm_memremap(dev, mem_phys, mem_size, MEMREMAP_WC);
> - if (IS_ERR(mem_region)) {
> - ath12k_err(ab, "unable to map memory region: %pa+%zx\n",
> - &res.start, mem_size);
> - return PTR_ERR(mem_region);
> - }
> -
> snprintf(fw_name, sizeof(fw_name), "%s/%s/%s%d%s", ATH12K_FW_DIR,
> ab->hw_params->fw.dir, ATH12K_AHB_FW_PREFIX, ab_ahb->userpd_id,
> ATH12K_AHB_FW_SUFFIX);
> @@ -400,11 +425,13 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab)
>
> /* Load FW image to a reserved memory location */
> if (ab_ahb->scm_auth_enabled)
> - ret = qcom_mdt_load(dev, fw, fw_name, pasid, mem_region,
> - mem_phys, mem_size, &mem_phys);
> + ret = qcom_mdt_load(dev, fw, fw_name, pasid, rproc_info->mem_region,
> + rproc_info->mem_phys, rproc_info->mem_size,
> + NULL);
> else
> - ret = qcom_mdt_load_no_init(dev, fw, fw_name, mem_region,
> - mem_phys, mem_size, &mem_phys);
> + ret = qcom_mdt_load_no_init(dev, fw, fw_name, rproc_info->mem_region,
> + rproc_info->mem_phys, rproc_info->mem_size,
> + NULL);
> if (ret) {
> ath12k_err(ab, "Failed to load MDT segments: %d\n", ret);
> goto err_fw;
> @@ -428,8 +455,9 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab)
> goto err_fw2;
> }
>
> - ret = qcom_mdt_load_no_init(dev, fw2, fw2_name, mem_region, mem_phys,
> - mem_size, &mem_phys);
> + ret = qcom_mdt_load_no_init(dev, fw2, fw2_name, rproc_info->mem_region,
> + rproc_info->mem_phys, rproc_info->mem_size,
> + NULL);
> if (ret) {
> ath12k_err(ab, "Failed to load MDT segments: %d\n", ret);
> goto err_fw2;
> @@ -877,6 +905,7 @@ static struct ath12k_ahb_rproc_info *ath12k_ahb_rproc_info_alloc(struct ath12k_b
> rproc_info->rootpd_booted_by_driver = false;
> rproc_info->userpd[ab_ahb->userpd_id - 1] = ab_ahb;
> rproc_info->num_userpd = 1;
> + rproc_info->shared_fw_loaded = false;
> init_completion(&rproc_info->rootpd_ready);
> ab_ahb->rproc_info = rproc_info;
>
> @@ -961,6 +990,76 @@ static int ath12k_ahb_boot_root_pd(struct ath12k_base *ab)
> return 0;
> }
>
> +static int ath12k_ahb_load_auth_shared_fw(struct ath12k_base *ab,
> + struct ath12k_ahb_rproc_info *rproc_info,
> + const char *fw_name, u32 pasid)
> +{
> + int ret;
> +
nit: move this empty line below after the declaration part.
> + const struct firmware *fw __free(firmware) = NULL;
With that nit addressed
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan at oss.qualcomm.com>
More information about the ath12k
mailing list