diff mbox series

[v5,6/7] remoteproc: qcom: Add support for memory sandbox

Message ID 1660649034-4303-7-git-send-email-quic_srivasam@quicinc.com
State New
Headers show
Series None | expand

Commit Message

Srinivasa Rao Mandadapu Aug. 16, 2022, 11:23 a.m. UTC
Update pil driver with SMMU mapping for allowing authorised
memory access to ADSP firmware, by reading required memory
regions either from device tree file or from resource table
embedded in ADSP binary header.

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
---
Changes since V4:
	-- Split the code and add appropriate APIs for resource allocation and free.
	-- Update adsp_unmap_smmu with missing free ops call.
	-- Update normalizing length value in adsp_of_unmap_smmu.
Changes since V3:
	-- Rename is_adsp_sb_needed to adsp_sandbox_needed.
	-- Add smmu unmapping in error case and in adsp stop.
Changes since V2:
	-- Replace platform_bus_type with adsp->dev->bus.
	-- Use API of_parse_phandle_with_args() instead of of_parse_phandle_with_fixed_args().
	-- Replace adsp->is_wpss with adsp->is_adsp.
	-- Update error handling in adsp_start().

 drivers/remoteproc/qcom_q6v5_adsp.c | 200 +++++++++++++++++++++++++++++++++++-
 1 file changed, 198 insertions(+), 2 deletions(-)

Comments

kernel test robot Aug. 20, 2022, 1:52 p.m. UTC | #1
Hi Srinivasa,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on remoteproc/rproc-next]
[also build test WARNING on linus/master v6.0-rc1 next-20220819]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Srinivasa-Rao-Mandadapu/Update-ADSP-pil-loader-for-SC7280-platform/20220816-195318
base:   git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git rproc-next
config: arm64-allyesconfig (https://download.01.org/0day-ci/archive/20220820/202208202105.f6q5X3x5-lkp@intel.com/config)
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project c9a41fe60ab62f7a40049c100adcc8087a47669b)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/04dc00863cb7b62aa7e5356f81cad5e7720e17ad
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Srinivasa-Rao-Mandadapu/Update-ADSP-pil-loader-for-SC7280-platform/20220816-195318
        git checkout 04dc00863cb7b62aa7e5356f81cad5e7720e17ad
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/interconnect/imx/ drivers/remoteproc/ drivers/thunderbolt/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/remoteproc/qcom_q6v5_adsp.c:442:54: warning: format specifies type 'void *' but the argument has type 'u32' (aka 'unsigned int') [-Wformat]
                           pr_err("failed to map addr = %p mem_size = %x\n", rsc_fw->pa, rsc_fw->len);
                                                        ~~                   ^~~~~~~~~~
                                                        %u
   include/linux/printk.h:518:33: note: expanded from macro 'pr_err'
           printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
                                  ~~~     ^~~~~~~~~~~
   include/linux/printk.h:475:60: note: expanded from macro 'printk'
   #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
                                                       ~~~    ^~~~~~~~~~~
   include/linux/printk.h:447:19: note: expanded from macro 'printk_index_wrap'
                   _p_func(_fmt, ##__VA_ARGS__);                           \
                           ~~~~    ^~~~~~~~~~~
   1 warning generated.


vim +442 drivers/remoteproc/qcom_q6v5_adsp.c

   422	
   423	static int adsp_rproc_map_smmu(struct rproc *rproc, int len)
   424	{
   425		struct fw_rsc_devmem *rsc_fw;
   426		struct fw_rsc_hdr *hdr;
   427		int offset;
   428		int ret;
   429		int i;
   430	
   431		if (!rproc->table_ptr)
   432			return 0;
   433	
   434		for (i = 0; i < rproc->table_ptr->num; i++) {
   435			offset = rproc->table_ptr->offset[i];
   436			hdr = (void *)rproc->table_ptr + offset;
   437			rsc_fw = (struct fw_rsc_devmem *)hdr + sizeof(*hdr);
   438	
   439			ret = iommu_map(rproc->domain, rsc_fw->da, rsc_fw->pa,
   440						rsc_fw->len, rsc_fw->flags);
   441			if (ret) {
 > 442				pr_err("failed to map addr = %p mem_size = %x\n", rsc_fw->pa, rsc_fw->len);
   443				goto  rproc_smmu_unmap;
   444			}
   445		}
   446	
   447		return 0;
   448	
   449	rproc_smmu_unmap:
   450		adsp_rproc_unmap_smmu(rproc, i);
   451		return ret;
   452	}
   453
diff mbox series

Patch

diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index b0a63a0..b0faa4b 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -9,6 +9,7 @@ 
 #include <linux/firmware.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iommu.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/mfd/syscon.h>
@@ -48,6 +49,8 @@ 
 #define LPASS_PWR_ON_REG		0x10
 #define LPASS_HALTREQ_REG		0x0
 
+#define SID_MASK_DEFAULT        0xF
+
 #define QDSP6SS_XO_CBCR		0x38
 #define QDSP6SS_CORE_CBCR	0x20
 #define QDSP6SS_SLEEP_CBCR	0x3c
@@ -78,7 +81,7 @@  struct adsp_pil_data {
 struct qcom_adsp {
 	struct device *dev;
 	struct rproc *rproc;
-
+	struct iommu_domain *iommu_dom;
 	struct qcom_q6v5 q6v5;
 
 	struct clk *xo;
@@ -333,6 +336,185 @@  static int adsp_load(struct rproc *rproc, const struct firmware *fw)
 	return 0;
 }
 
+static void adsp_of_unmap_smmu(struct iommu_domain *iommu_dom, const __be32 *prop, int len)
+{
+	unsigned long iova;
+	unsigned int mem_size;
+	int i;
+
+	len /= sizeof(__be32);
+	for (i = 0; i < len; i++) {
+		iova = be32_to_cpu(prop[i++]);
+		/* Skip Physical address*/
+		i++;
+		mem_size = be32_to_cpu(prop[i++]);
+		iommu_unmap(iommu_dom, iova, mem_size);
+	}
+}
+
+static void adsp_rproc_unmap_smmu(struct rproc *rproc, int len)
+{
+	struct fw_rsc_devmem *rsc_fw;
+	struct fw_rsc_hdr *hdr;
+	int offset;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		offset = rproc->table_ptr->offset[i];
+		hdr = (void *)rproc->table_ptr + offset;
+		rsc_fw = (struct fw_rsc_devmem *)hdr + sizeof(*hdr);
+
+		iommu_unmap(rproc->domain, rsc_fw->da, rsc_fw->len);
+	}
+}
+
+static void adsp_unmap_smmu(struct rproc *rproc)
+{
+	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+	const __be32 *prop;
+	unsigned int len;
+
+	iommu_unmap(adsp->iommu_dom, adsp->mem_phys, adsp->mem_size);
+
+	prop = of_get_property(adsp->dev->of_node, "qcom,adsp-memory-regions", &len);
+	if (prop) {
+		adsp_of_unmap_smmu(adsp->iommu_dom, prop, len);
+	} else {
+		if (rproc->table_ptr)
+			adsp_rproc_unmap_smmu(rproc, rproc->table_ptr->num);
+	}
+
+	iommu_domain_free(adsp->iommu_dom);
+}
+
+static int adsp_of_map_smmu(struct iommu_domain *iommu_dom, const __be32 *prop, int len)
+{
+	unsigned long mem_phys;
+	unsigned long iova;
+	unsigned int mem_size;
+	unsigned int flag;
+	int access_level;
+	int ret;
+	int i;
+
+	len /= sizeof(__be32);
+	for (i = 0; i < len; i++) {
+		iova = be32_to_cpu(prop[i++]);
+		mem_phys = be32_to_cpu(prop[i++]);
+		mem_size = be32_to_cpu(prop[i++]);
+		access_level = be32_to_cpu(prop[i]);
+
+		if (access_level)
+			flag = IOMMU_READ | IOMMU_WRITE;
+		else
+			flag = IOMMU_READ;
+
+		ret = iommu_map(iommu_dom, iova, mem_phys, mem_size, flag);
+		if (ret) {
+			pr_err("failed to map addr = %p mem_size = %x\n", &(mem_phys), mem_size);
+			goto of_smmu_unmap;
+		}
+	}
+	return 0;
+of_smmu_unmap:
+	adsp_of_unmap_smmu(iommu_dom, prop, i);
+	return ret;
+}
+
+static int adsp_rproc_map_smmu(struct rproc *rproc, int len)
+{
+	struct fw_rsc_devmem *rsc_fw;
+	struct fw_rsc_hdr *hdr;
+	int offset;
+	int ret;
+	int i;
+
+	if (!rproc->table_ptr)
+		return 0;
+
+	for (i = 0; i < rproc->table_ptr->num; i++) {
+		offset = rproc->table_ptr->offset[i];
+		hdr = (void *)rproc->table_ptr + offset;
+		rsc_fw = (struct fw_rsc_devmem *)hdr + sizeof(*hdr);
+
+		ret = iommu_map(rproc->domain, rsc_fw->da, rsc_fw->pa,
+					rsc_fw->len, rsc_fw->flags);
+		if (ret) {
+			pr_err("failed to map addr = %p mem_size = %x\n", rsc_fw->pa, rsc_fw->len);
+			goto  rproc_smmu_unmap;
+		}
+	}
+
+	return 0;
+
+rproc_smmu_unmap:
+	adsp_rproc_unmap_smmu(rproc, i);
+	return ret;
+}
+
+static int adsp_map_smmu(struct qcom_adsp *adsp, struct rproc *rproc)
+{
+	struct of_phandle_args args;
+	const __be32 *prop;
+	long long sid;
+	unsigned int len;
+	int ret;
+
+	ret = of_parse_phandle_with_args(adsp->dev->of_node, "iommus", "#iommu-cells", 0, &args);
+	if (ret < 0)
+		sid = -1;
+	else
+		sid = args.args[0] & SID_MASK_DEFAULT;
+
+	adsp->iommu_dom = iommu_domain_alloc(adsp->dev->bus);
+	if (!adsp->iommu_dom) {
+		dev_err(adsp->dev, "failed to allocate iommu domain\n");
+		ret = -ENOMEM;
+		goto domain_free;
+	}
+
+	ret = iommu_attach_device(adsp->iommu_dom, adsp->dev);
+	if (ret) {
+		dev_err(adsp->dev, "could not attach device ret = %d\n", ret);
+		ret = -EBUSY;
+		goto detach_device;
+	}
+
+	/* Add SID configuration for ADSP Firmware to SMMU */
+	adsp->mem_phys =  adsp->mem_phys | (sid << 32);
+
+	ret = iommu_map(adsp->iommu_dom, adsp->mem_phys, adsp->mem_phys,
+			adsp->mem_size,	IOMMU_READ | IOMMU_WRITE);
+	if (ret) {
+		dev_err(adsp->dev, "Unable to map ADSP Physical Memory\n");
+		goto sid_unmap;
+	}
+
+	prop = of_get_property(adsp->dev->of_node, "qcom,adsp-memory-regions", &len);
+	if (prop) {
+		ret = adsp_of_map_smmu(adsp->iommu_dom, prop, len);
+		if (ret) {
+			dev_err(adsp->dev, "Unable to map memory regions accessed by ADSP\n");
+			goto sid_unmap;
+		}
+	} else {
+		ret = adsp_rproc_map_smmu(rproc, len);
+		if (ret) {
+			dev_err(adsp->dev, "Unable to map memory regions accessed by ADSP\n");
+			goto sid_unmap;
+		}
+	}
+	return 0;
+
+sid_unmap:
+	iommu_unmap(adsp->iommu_dom, adsp->mem_phys, adsp->mem_size);
+detach_device:
+	iommu_domain_free(adsp->iommu_dom);
+domain_free:
+	return ret;
+}
+
+
 static int adsp_start(struct rproc *rproc)
 {
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
@@ -343,9 +525,16 @@  static int adsp_start(struct rproc *rproc)
 	if (ret)
 		return ret;
 
+	if (adsp->adsp_sandbox_needed) {
+		ret = adsp_map_smmu(adsp, rproc);
+		if (ret) {
+			dev_err(adsp->dev, "ADSP smmu mapping failed\n");
+			goto disable_irqs;
+		}
+	}
 	ret = clk_prepare_enable(adsp->xo);
 	if (ret)
-		goto disable_irqs;
+		goto adsp_smmu_unmap;
 
 	ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds,
 				    adsp->proxy_pd_count);
@@ -401,6 +590,9 @@  static int adsp_start(struct rproc *rproc)
 	qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 disable_xo_clk:
 	clk_disable_unprepare(adsp->xo);
+adsp_smmu_unmap:
+	if (adsp->adsp_sandbox_needed)
+		adsp_unmap_smmu(rproc);
 disable_irqs:
 	qcom_q6v5_unprepare(&adsp->q6v5);
 
@@ -429,6 +621,9 @@  static int adsp_stop(struct rproc *rproc)
 	if (ret)
 		dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
 
+	if (adsp->adsp_sandbox_needed)
+		adsp_unmap_smmu(rproc);
+
 	handover = qcom_q6v5_unprepare(&adsp->q6v5);
 	if (handover)
 		qcom_adsp_pil_handover(&adsp->q6v5);
@@ -460,6 +655,7 @@  static const struct rproc_ops adsp_ops = {
 	.stop = adsp_stop,
 	.da_to_va = adsp_da_to_va,
 	.parse_fw = qcom_register_dump_segments,
+	.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
 	.load = adsp_load,
 	.panic = adsp_panic,
 };