[PATCH v4 6/6] firmware: qcom: scm: introduce keep_mdt_buf flag in PAS context
From: Mukesh Ojha
Date: Thu Apr 30 2026 - 15:15:34 EST
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 <mukesh.ojha@xxxxxxxxxxxxxxxx>
---
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