From 87fb21a33713079bdedf5102f4f156eddb5770e5 Mon Sep 17 00:00:00 2001 Message-Id: <87fb21a33713079bdedf5102f4f156eddb5770e5.1663777662.git.quic_gokukris@quicinc.com> In-Reply-To: References: From: Gokul krishna Krishnakumar Date: Mon, 12 Sep 2022 11:41:32 -0700 Subject: [PATCH v2 2/2] soc: qcom: mdt_loader: Move the memory allocation into mdt loader By moving the memory allocation to mdt loader we can simplify the scm call, by just packing arguments provided to it from the clients for making secuer world calls. We can also simplify the memory allocation for the qcom metadata, by just doing one memory allocation in the mdt loader. Signed-off-by: Gokul krishna Krishnakumar --- drivers/firmware/qcom_scm.c | 16 ---------- drivers/remoteproc/qcom_q6v5_mss.c | 2 +- drivers/remoteproc/qcom_q6v5_pas.c | 4 +-- drivers/soc/qcom/mdt_loader.c | 60 ++++++++++++++++++++++++++++++++----- include/linux/qcom_scm.h | 1 - include/linux/soc/qcom/mdt_loader.h | 13 ++++++-- 6 files changed, 66 insertions(+), 30 deletions(-) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 05ec03c..ea0eba65 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -483,22 +483,6 @@ int qcom_scm_pas_init_image(u32 peripheral, dma_addr_t mdata_phys) } EXPORT_SYMBOL(qcom_scm_pas_init_image); -/** - * qcom_scm_pas_metadata_release() - release metadata context - * @ctx: metadata context - */ -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) -{ - if (!ctx->ptr) - return; - - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); - - ctx->ptr = NULL; - ctx->phys = 0; - ctx->size = 0; -} -EXPORT_SYMBOL(qcom_scm_pas_metadata_release); /** * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index fddb63c..1919bfc 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -947,7 +947,7 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, int ret; int i; - metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev); + metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev, NULL); if (IS_ERR(metadata)) return PTR_ERR(metadata); diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 6afd094..f112ff4 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -159,7 +159,7 @@ static int adsp_unprepare(struct rproc *rproc) * auth_and_reset() was successful, but in other cases clean it up * here. */ - qcom_scm_pas_metadata_release(&adsp->pas_metadata); + qcom_scm_pas_metadata_release(adsp->dev, &adsp->pas_metadata); return 0; } @@ -232,7 +232,7 @@ static int adsp_start(struct rproc *rproc) goto disable_px_supply; } - qcom_scm_pas_metadata_release(&adsp->pas_metadata); + qcom_scm_pas_metadata_release(adsp->dev, &adsp->pas_metadata); return 0; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 8d06125..ad8725e 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -16,6 +16,7 @@ #include #include #include +#include static bool mdt_phdr_valid(const struct elf32_phdr *phdr) { @@ -110,6 +111,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size); * @data_len: length of the read metadata blob * @fw_name: name of the firmware, for construction of segment file names * @dev: device handle to associate resources with + * @mdata_phys: phys address for the assigned metadata buffer * * The mechanism that performs the authentication of the loading firmware * expects an ELF header directly followed by the segment of hashes, with no @@ -124,7 +126,8 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size); * Return: pointer to data, or ERR_PTR() */ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, - const char *fw_name, struct device *dev) + const char *fw_name, struct device *dev, + dma_addr_t *mdata_phys) { const struct elf32_phdr *phdrs; const struct elf32_hdr *ehdr; @@ -160,10 +163,21 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, ehdr_size = phdrs[0].p_filesz; hash_size = phdrs[hash_segment].p_filesz; - data = kmalloc(ehdr_size + hash_size, GFP_KERNEL); - if (!data) + /* + * During the scm call memory protection will be enabled for the meta + * data blob, so make sure it's physically contiguous, 4K aligned and + * non-cachable to avoid XPU violations. + */ + if (mdata_phys) { + data = dma_alloc_coherent(dev, ehdr_size + hash_size, mdata_phys, + GFP_KERNEL); + } else { + data = kmalloc(ehdr_size + hash_size, GFP_KERNEL); + } + if (!data) { + dev_err(dev, "Allocation of metadata buffer failed.\n"); return ERR_PTR(-ENOMEM); - + } /* Copy ELF header */ memcpy(data, fw->data, ehdr_size); @@ -179,7 +193,11 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, /* Hash is in its own segment, beyond the loaded file */ ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev); if (ret) { - kfree(data); + if (mdata_phys) { + dma_free_coherent(dev, ehdr_size + hash_size, data, *mdata_phys); + } else { + kfree(data); + } return ERR_PTR(ret); } } @@ -191,6 +209,23 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); /** + * qcom_pas_metadata_release() - release metadata context + * @ctx: metadata context + */ +void qcom_scm_pas_metadata_release(struct device *dev, struct qcom_scm_pas_metadata *ctx) +{ + if (!ctx->ptr) + return; + + dma_free_coherent(dev, ctx->size, ctx->ptr, ctx->phys); + + ctx->ptr = NULL; + ctx->phys = 0; + ctx->size = 0; +} +EXPORT_SYMBOL(qcom_scm_pas_metadata_release); + +/** * qcom_mdt_pas_init() - initialize PAS region for firmware loading * @dev: device handle to associate resources with * @fw: firmware object for the mdt file @@ -232,7 +267,7 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K); } - metadata = qcom_mdt_read_metadata(fw, &metadata_len, fw_name, dev); + metadata = qcom_mdt_read_metadata(fw, &metadata_len, fw_name, dev, &mdata_phys); if (IS_ERR(metadata)) { ret = PTR_ERR(metadata); dev_err(dev, "error %d reading firmware %s metadata\n", ret, fw_name); @@ -240,7 +275,18 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, } ret = qcom_scm_pas_init_image(pas_id, mdata_phys); - kfree(metadata); + if (ret || !ctx) { + if (mdata_phys) { + dma_free_coherent(dev, metadata_len, metadata, mdata_phys); + } else { + kfree(metadata); + } + } else if (ctx) { + ctx->ptr = metadata; + ctx->phys = mdata_phys; + ctx->size = metadata_len; + } + if (ret) { /* Invalid firmware metadata */ dev_err(dev, "error %d initializing firmware %s\n", ret, fw_name); diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 751436a..0053936 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -75,7 +75,6 @@ struct qcom_scm_pas_metadata { }; extern int qcom_scm_pas_init_image(u32 peripheral, dma_addr_t metadata); -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size); extern int qcom_scm_pas_auth_and_reset(u32 peripheral); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 9e8e604..856b6f9 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -28,8 +28,11 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base); void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, - const char *fw_name, struct device *dev); + const char *fw_name, struct device *dev, + dma_addr_t *mdata_phys); +void qcom_scm_pas_metadata_release(struct device *dev, + struct qcom_scm_pas_metadata *ctx); #else /* !IS_ENABLED(CONFIG_QCOM_MDT_LOADER) */ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw) @@ -64,11 +67,15 @@ static inline int qcom_mdt_load_no_init(struct device *dev, static inline void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, const char *fw_name, - struct device *dev) + struct device *dev, dma_addr_t *mdata_phys) { return ERR_PTR(-ENODEV); } - +void qcom_scm_pas_metadata_release(struct device *dev, + struct qcom_scm_pas_metadata *ctx) +{ + return NULL; +} #endif /* !IS_ENABLED(CONFIG_QCOM_MDT_LOADER) */ #endif -- 2.7.4