[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250819165447.4149674-8-mukesh.ojha@oss.qualcomm.com>
Date: Tue, 19 Aug 2025 22:24:42 +0530
From: Mukesh Ojha <mukesh.ojha@....qualcomm.com>
To: Bjorn Andersson <andersson@...nel.org>,
Konrad Dybcio <konradybcio@...nel.org>,
Vikash Garodia <quic_vgarodia@...cinc.com>,
Dikshita Agarwal <quic_dikshita@...cinc.com>,
Mauro Carvalho Chehab <mchehab@...nel.org>,
Mathieu Poirier <mathieu.poirier@...aro.org>
Cc: Abhinav Kumar <abhinav.kumar@...ux.dev>,
"Bryan O'Donoghue" <bryan.odonoghue@...aro.org>,
linux-kernel@...r.kernel.org, linux-arm-msm@...r.kernel.org,
linux-media@...r.kernel.org, linux-remoteproc@...r.kernel.org,
Mukesh Ojha <mukesh.ojha@....qualcomm.com>
Subject: [PATCH v2 07/11] firmware: qcom_scm: Add qcom_scm_pas_get_rsc_table() to get resource table
Qualcomm remote processor may rely on both static and dynamic resources
for its functionality. Static resources typically refer to memory-mapped
addresses required by the subsystem and are often embedded within the
firmware binary and dynamic resources, such as shared memory in DDR
etc., are determined at runtime during the boot process.
On Qualcomm Technologies devices, it's possible that static resources
are not embedded in the firmware binary and instead are provided by
TrustZone However, dynamic resources are always expected to come from
TrustZone. This indicates that for Qualcomm devices, all resources
(static and dynamic) will be provided by TrustZone via the SMC call.
Add qcom_scm_pas_get_rsc_table() SMC call which will return resource table
including static and dynamic resource for a given PAS id in passed output
buffer of output size.
If the remote processor firmware binary does not include a resource table,
the caller of this function should set input_rt as NULL and input_rt_size
as zero respectively. If the firmware binary does contain static resources,
they should be passed in input_rt. These will be forwarded to TrustZone
for authentication. TrustZone will then append the dynamic resources and
return the complete resource table in output_rt.
More about documentation on resource table format can be found in
include/linux/rsc_table.h
Signed-off-by: Mukesh Ojha <mukesh.ojha@....qualcomm.com>
---
drivers/firmware/qcom/qcom_scm.c | 158 +++++++++++++++++++++++++
drivers/firmware/qcom/qcom_scm.h | 1 +
include/linux/firmware/qcom/qcom_scm.h | 5 +
3 files changed, 164 insertions(+)
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 301d440f62f3..1b45aafd6c05 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -27,6 +27,7 @@
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
+#include <linux/rsc_table.h>
#include <linux/sizes.h>
#include <linux/types.h>
@@ -111,6 +112,10 @@ enum qcom_scm_qseecom_tz_cmd_info {
QSEECOM_TZ_CMD_INFO_VERSION = 3,
};
+enum qcom_scm_rsctable_resp_type {
+ RSCTABLE_BUFFER_NOT_SUFFICIENT = 20,
+};
+
#define QSEECOM_MAX_APP_NAME_SIZE 64
#define SHMBRIDGE_RESULT_NOTSUPP 4
@@ -776,6 +781,159 @@ int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
}
EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
+static int __qcom_scm_pas_get_rsc_table(u32 peripheral, void *input_rt,
+ size_t input_rt_size, void **output_rt,
+ size_t *output_rt_size)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_GET_RSCTABLE,
+ .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RO, QCOM_SCM_VAL,
+ QCOM_SCM_RW, QCOM_SCM_VAL),
+ .args[0] = peripheral,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ void *input_rt_buf, *output_rt_buf;
+ struct resource_table *rsc;
+ struct qcom_scm_res res;
+ int ret;
+
+ ret = qcom_scm_clk_enable();
+ if (ret)
+ return ret;
+
+ ret = qcom_scm_bw_enable();
+ if (ret)
+ goto disable_clk;
+
+ /*
+ * TrustZone can not accept buffer as NULL value as argument Hence,
+ * we need to pass a input buffer indicating that subsystem firmware
+ * does not have resource table by filling resource table structure.
+ */
+ if (!input_rt)
+ input_rt_size = sizeof(*rsc);
+
+ input_rt_buf = qcom_tzmem_alloc(__scm->mempool, input_rt_size, GFP_KERNEL);
+ if (!input_rt_buf) {
+ ret = -ENOMEM;
+ goto disable_scm_bw;
+ }
+
+ if (!input_rt) {
+ rsc = input_rt_buf;
+ rsc->num = 0;
+ } else {
+ memcpy(input_rt_buf, input_rt, input_rt_size);
+ }
+
+ output_rt_buf = qcom_tzmem_alloc(__scm->mempool, *output_rt_size, GFP_KERNEL);
+ if (!output_rt_buf) {
+ ret = -ENOMEM;
+ goto free_input_rt_buf;
+ }
+
+ desc.args[1] = qcom_tzmem_to_phys(input_rt_buf);
+ desc.args[2] = input_rt_size;
+ desc.args[3] = qcom_tzmem_to_phys(output_rt_buf);
+ desc.args[4] = *output_rt_size;
+
+ /*
+ * Whether SMC fail or pass, res.result[2] will hold actual resource table
+ * size.
+ *
+ * if passed 'output_rt_size' buffer size is not sufficient to hold the
+ * resource table TrustZone sends, response code in res.result[1] as
+ * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call with
+ * output_rt buffer with res.result[2] size.
+ */
+ ret = qcom_scm_call(__scm->dev, &desc, &res);
+ *output_rt_size = res.result[2];
+ if (!ret)
+ memcpy(*output_rt, output_rt_buf, *output_rt_size);
+
+ if (ret && res.result[1] == RSCTABLE_BUFFER_NOT_SUFFICIENT)
+ ret = -EAGAIN;
+
+ qcom_tzmem_free(output_rt_buf);
+
+free_input_rt_buf:
+ qcom_tzmem_free(input_rt_buf);
+
+disable_scm_bw:
+ qcom_scm_bw_disable();
+
+disable_clk:
+ qcom_scm_clk_disable();
+
+ return ret ? : res.result[0];
+}
+
+/**
+ * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
+ * for a given peripheral.
+ *
+ * Qualcomm remote processor may rely on both static and dynamic resources for
+ * its functionality. Static resources typically refer to memory-mapped addresses
+ * required by the subsystem and are often embedded within the firmware binary
+ * and dynamic resources, such as shared memory in DDR etc., are determined at
+ * runtime during the boot process.
+ *
+ * On Qualcomm Technologies devices, it's possible that static resources are not
+ * embedded in the firmware binary and instead are provided by TrustZone However,
+ * dynamic resources are always expected to come from TrustZone. This indicates
+ * that for Qualcomm devices, all resources (static and dynamic) will be provided
+ * by TrustZone via the SMC call.
+ *
+ * If the remote processor firmware binary does contain static resources, they
+ * should be passed in input_rt. These will be forwarded to TrustZone for
+ * authentication. TrustZone will then append the dynamic resources and return
+ * the complete resource table in output_rt.
+ *
+ * If the remote processor firmware binary does not include a resource table,
+ * the caller of this function should set input_rt as NULL and input_rt_size
+ * as zero respectively.
+ *
+ * More about documentation on resource table data structures can be found in
+ * include/linux/rsc_table.h
+ *
+ * @ctx: PAS context
+ * @peripheral: peripheral id
+ * @input_rt: resource table buffer which is present in firmware binary
+ * @input_rt_size: size of the resource table present in firmware binary
+ * @output_rt: buffer to which the both static and dynamic resources will
+ * be returned.
+ * @output_rt_size: TrustZone expects caller should pass worst case size for
+ * the output_rt.
+ *
+ * Return: 0 on success and nonzero on failure.
+ *
+ * Upon successful return, output_rt will have the resource table and output_rt_size
+ * will have actual resource table size,
+ */
+int qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_ctx *ctx, void *input_rt,
+ size_t input_rt_size, void **output_rt,
+ size_t *output_rt_size)
+{
+ int ret;
+
+ do {
+ *output_rt = devm_kzalloc(ctx->dev, *output_rt_size, GFP_KERNEL);
+ if (!*output_rt)
+ return -ENOMEM;
+
+ ret = __qcom_scm_pas_get_rsc_table(ctx->peripheral, input_rt,
+ input_rt_size, output_rt,
+ output_rt_size);
+ if (ret)
+ devm_kfree(ctx->dev, *output_rt);
+
+ } while (ret == -EAGAIN);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table);
+
/**
* qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
* and reset the remote processor
diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h
index a56c8212cc0c..50d87c628d78 100644
--- a/drivers/firmware/qcom/qcom_scm.h
+++ b/drivers/firmware/qcom/qcom_scm.h
@@ -105,6 +105,7 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev);
#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06
#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a
+#define QCOM_SCM_PIL_PAS_GET_RSCTABLE 0x21
#define QCOM_SCM_SVC_IO 0x05
#define QCOM_SCM_IO_READ 0x01
diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h
index bd3417d9c3f9..4fd13661ecdb 100644
--- a/include/linux/firmware/qcom/qcom_scm.h
+++ b/include/linux/firmware/qcom/qcom_scm.h
@@ -91,6 +91,11 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
struct qcom_scm_pas_ctx *ctx);
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_ctx *ctx);
int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size);
+
+int qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_ctx *ctx, void *input_rt,
+ size_t input_rt_size, void **output_rt,
+ size_t *output_rt_size);
+
int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_ctx *ctx);
int qcom_scm_pas_auth_and_reset(u32 peripheral);
int qcom_scm_pas_shutdown(u32 peripheral);
--
2.50.1
Powered by blists - more mailing lists