The PAS image initialization path always retains the metadata buffer when a valid qcom_scm_pas_context is provided, even if the caller does not require it. This implicit behavior leads to unclear buffer ownership and forces new users of qcom_mdt_pas_load() to manually release metadata, which is error‑ prone and incorrect.
Add a keep_mdt_buf flag to struct qcom_scm_pas_context to make metadata retention explicit. Metadata buffers are now freed by default and are only preserved when this flag is set. qcom_q6v5_pas enables this during probe for contexts that require retained metadata for subsequent PAS operations, while existing callers continue to work unchanged. Signed-off-by: Mukesh Ojha <[email protected]> --- drivers/firmware/qcom/qcom_scm.c | 21 ++++++++++++++++++--- drivers/remoteproc/qcom_q6v5_pas.c | 2 ++ include/linux/firmware/qcom/qcom_scm.h | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 9b06a69d3a6d..2cae35e7c583 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -651,7 +651,7 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, mdata_phys = qcom_tzmem_to_phys(mdata_buf); ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res); - if (ret < 0) + if (ret < 0 || !ctx->keep_mdt_buf) qcom_tzmem_free(mdata_buf); else ctx->ptr = mdata_buf; @@ -707,9 +707,24 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, memcpy(mdata_buf, metadata, size); ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res); - if (ret < 0 || !ctx) { + + /* + * Some clients still pass the PAS context as NULL. Until all clients + * switch to qcom_mdt_pas_load() and provide a valid PAS context, check + * for NULL before dereferencing it. + * + * When a valid context is provided, metadata handling differs across + * clients. For example, modem clients pass metadata to TrustZone that + * must not be freed until the authentication and reset SMCs are + * invoked, as the buffers remain locked until then. + * + * Other clients free their metadata immediately after the PAS_INIT + * SMC call. Therefore, keep_mdt_buf should be set to true for modem + * clients and false for others. + */ + if (ret < 0 || !ctx || !ctx->keep_mdt_buf) { dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); - } else if (ctx) { + } else { ctx->ptr = mdata_buf; ctx->phys = mdata_phys; ctx->size = size; diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 5be3070fd52b..7858e14c0bee 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -669,6 +669,7 @@ static int qcom_pas_alloc_memory_region(struct qcom_pas *pas) return PTR_ERR(pas->pas_ctx); pas->pas_ctx->use_tzmem = rproc->has_iommu; + pas->pas_ctx->keep_mdt_buf = true; if (!pas->dtb_pas_id) return 0; @@ -688,6 +689,7 @@ static int qcom_pas_alloc_memory_region(struct qcom_pas *pas) return PTR_ERR(pas->dtb_pas_ctx); pas->dtb_pas_ctx->use_tzmem = rproc->has_iommu; + pas->dtb_pas_ctx->keep_mdt_buf = true; return 0; } diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 5747bd191bf1..6d8d3deb02e0 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -75,6 +75,7 @@ struct qcom_scm_pas_context { dma_addr_t phys; ssize_t size; bool use_tzmem; + bool keep_mdt_buf; }; struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, -- 2.53.0

