[4/5] remoteproc: imx_rproc: set Cortex-M stack/pc to TCML

Message ID 20230106034305.2868740-5-peng.fan@oss.nxp.com
State New
Headers
Series remoteproc: imx_rproc: support firmware in DDR |

Commit Message

Peng Fan (OSS) Jan. 6, 2023, 3:43 a.m. UTC
  From: Peng Fan <peng.fan@nxp.com>

The i.MX8M Cortex-M core not has ROM. It has a requirement is
the stack, pc value should be set in address 0 and 4 from the view of
itself. From Cortex-A core view, the region is at TCML start address.

The stack and pc value are the first two words stored in section
".interrupts" of the firmware, and the section is the first section in
the firmware.

When the firmware is built to run in TCML, there is no issue, because
when copying elf segments, the first two words are copied to TCML also.

However when the firmware is built ro run in DDR, the first two words
are not copied to TCML start address.

This patch is to find the ".interrupts" section, read out the first
two words and write to TCML start address at offset 0 and 4.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/remoteproc/imx_rproc.c | 37 +++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)
  

Comments

kernel test robot Jan. 6, 2023, 3:23 p.m. UTC | #1
Hi Peng,

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.2-rc2 next-20230106]
[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/Peng-Fan-OSS/remoteproc-elf_loader-introduce-rproc_elf_find_shdr/20230106-114403
base:   git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git rproc-next
patch link:    https://lore.kernel.org/r/20230106034305.2868740-5-peng.fan%40oss.nxp.com
patch subject: [PATCH 4/5] remoteproc: imx_rproc: set Cortex-M stack/pc to TCML
config: arm64-randconfig-r022-20230106
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 8d9828ef5aa9688500657d36cd2aefbe12bbd162)
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/40239477bcfaaea196729da9c6e4b68b862eeff7
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Peng-Fan-OSS/remoteproc-elf_loader-introduce-rproc_elf_find_shdr/20230106-114403
        git checkout 40239477bcfaaea196729da9c6e4b68b862eeff7
        # 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 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/remoteproc/

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/imx_rproc.c:647:6: warning: variable 'sh_addr' set but not used [-Wunused-but-set-variable]
           u64 sh_addr, offset;
               ^
   1 warning generated.


vim +/sh_addr +647 drivers/remoteproc/imx_rproc.c

   638	
   639	static u64 imx_rproc_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
   640	{
   641		struct imx_rproc *priv = rproc->priv;
   642		const u8 *elf_data = (void *)fw->data;
   643		u8 class = fw_elf_get_class(fw);
   644		u64 bootaddr = rproc_elf_get_boot_addr(rproc, fw);
   645		const void *shdr;
   646		void *va;
 > 647		u64 sh_addr, offset;
   648	
   649		if (priv->dcfg->devtype == IMX_RPROC_IMX8M) {
   650			/*
   651			 * i.MX8M Cortex-M requires [stack, pc] be put in address
   652			 * [0, 4], so the da address is 0, size is 8 words.
   653			 */
   654			va = rproc_da_to_va(rproc, 0, 8, NULL);
   655			shdr = rproc_elf_find_shdr(rproc, fw, ".interrupts");
   656			if (!shdr || !va)
   657				return bootaddr;
   658			sh_addr = elf_shdr_get_sh_addr(class, shdr);
   659			offset = elf_shdr_get_sh_offset(class, shdr);
   660	
   661			/*
   662			 * Write stack, pc to TCML start address. The TCML region
   663			 * is marked with ATT_IOMEM, so use writel.
   664			 */
   665			writel(*(u32 *)(elf_data + offset), va);
   666			writel(*(u32 *)(elf_data + offset + 4), va + 4);
   667		}
   668	
   669		return bootaddr;
   670	}
   671
  
kernel test robot Jan. 11, 2023, 3:20 p.m. UTC | #2
Hi Peng,

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.2-rc3 next-20230111]
[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/Peng-Fan-OSS/remoteproc-elf_loader-introduce-rproc_elf_find_shdr/20230106-114403
base:   git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git rproc-next
patch link:    https://lore.kernel.org/r/20230106034305.2868740-5-peng.fan%40oss.nxp.com
patch subject: [PATCH 4/5] remoteproc: imx_rproc: set Cortex-M stack/pc to TCML
config: arm-randconfig-s031-20230110
compiler: arm-linux-gnueabi-gcc (GCC) 12.1.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # apt-get install sparse
        # sparse version: v0.6.4-39-gce1a6720-dirty
        # https://github.com/intel-lab-lkp/linux/commit/40239477bcfaaea196729da9c6e4b68b862eeff7
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Peng-Fan-OSS/remoteproc-elf_loader-introduce-rproc_elf_find_shdr/20230106-114403
        git checkout 40239477bcfaaea196729da9c6e4b68b862eeff7
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=arm olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=arm SHELL=/bin/bash drivers/remoteproc/

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

sparse warnings: (new ones prefixed by >>)
   drivers/remoteproc/imx_rproc.c:503:12: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void *va @@     got void [noderef] __iomem * @@
   drivers/remoteproc/imx_rproc.c:503:12: sparse:     expected void *va
   drivers/remoteproc/imx_rproc.c:503:12: sparse:     got void [noderef] __iomem *
   drivers/remoteproc/imx_rproc.c:520:20: sparse: sparse: incorrect type in argument 1 (different address spaces) @@     expected void volatile [noderef] __iomem *io_addr @@     got void *va @@
   drivers/remoteproc/imx_rproc.c:520:20: sparse:     expected void volatile [noderef] __iomem *io_addr
   drivers/remoteproc/imx_rproc.c:520:20: sparse:     got void *va
   drivers/remoteproc/imx_rproc.c:636:17: sparse: sparse: cast removes address space '__iomem' of expression
>> drivers/remoteproc/imx_rproc.c:665:17: sparse: sparse: incorrect type in argument 2 (different address spaces) @@     expected void volatile [noderef] __iomem *addr @@     got void *[assigned] va @@
   drivers/remoteproc/imx_rproc.c:665:17: sparse:     expected void volatile [noderef] __iomem *addr
   drivers/remoteproc/imx_rproc.c:665:17: sparse:     got void *[assigned] va
>> drivers/remoteproc/imx_rproc.c:666:17: sparse: sparse: incorrect type in argument 2 (different address spaces) @@     expected void volatile [noderef] __iomem *addr @@     got void * @@
   drivers/remoteproc/imx_rproc.c:666:17: sparse:     expected void volatile [noderef] __iomem *addr
   drivers/remoteproc/imx_rproc.c:666:17: sparse:     got void *

vim +665 drivers/remoteproc/imx_rproc.c

   495	
   496	static int imx_rproc_mem_alloc(struct rproc *rproc,
   497				       struct rproc_mem_entry *mem)
   498	{
   499		struct device *dev = rproc->dev.parent;
   500		void *va;
   501	
   502		dev_dbg(dev, "map memory: %p+%zx\n", &mem->dma, mem->len);
 > 503		va = ioremap_wc(mem->dma, mem->len);
   504		if (IS_ERR_OR_NULL(va)) {
   505			dev_err(dev, "Unable to map memory region: %p+%zx\n",
   506				&mem->dma, mem->len);
   507			return -ENOMEM;
   508		}
   509	
   510		/* Update memory entry va */
   511		mem->va = va;
   512	
   513		return 0;
   514	}
   515	
   516	static int imx_rproc_mem_release(struct rproc *rproc,
   517					 struct rproc_mem_entry *mem)
   518	{
   519		dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
   520		iounmap(mem->va);
   521	
   522		return 0;
   523	}
   524	
   525	static int imx_rproc_prepare(struct rproc *rproc)
   526	{
   527		struct imx_rproc *priv = rproc->priv;
   528		struct device_node *np = priv->dev->of_node;
   529		struct of_phandle_iterator it;
   530		struct rproc_mem_entry *mem;
   531		struct reserved_mem *rmem;
   532		u32 da;
   533	
   534		/* Register associated reserved memory regions */
   535		of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);
   536		while (of_phandle_iterator_next(&it) == 0) {
   537			/*
   538			 * Ignore the first memory region which will be used vdev buffer.
   539			 * No need to do extra handlings, rproc_add_virtio_dev will handle it.
   540			 */
   541			if (!strcmp(it.node->name, "vdev0buffer"))
   542				continue;
   543	
   544			if (!strcmp(it.node->name, "rsc-table"))
   545				continue;
   546	
   547			rmem = of_reserved_mem_lookup(it.node);
   548			if (!rmem) {
   549				dev_err(priv->dev, "unable to acquire memory-region\n");
   550				return -EINVAL;
   551			}
   552	
   553			/* No need to translate pa to da, i.MX use same map */
   554			da = rmem->base;
   555	
   556			/* Register memory region */
   557			mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)rmem->base, rmem->size, da,
   558						   imx_rproc_mem_alloc, imx_rproc_mem_release,
   559						   it.node->name);
   560	
   561			if (mem)
   562				rproc_coredump_add_segment(rproc, da, rmem->size);
   563			else
   564				return -ENOMEM;
   565	
   566			rproc_add_carveout(rproc, mem);
   567		}
   568	
   569		return  0;
   570	}
   571	
   572	static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
   573	{
   574		int ret;
   575	
   576		ret = rproc_elf_load_rsc_table(rproc, fw);
   577		if (ret)
   578			dev_info(&rproc->dev, "No resource table in elf\n");
   579	
   580		return 0;
   581	}
   582	
   583	static void imx_rproc_kick(struct rproc *rproc, int vqid)
   584	{
   585		struct imx_rproc *priv = rproc->priv;
   586		int err;
   587		__u32 mmsg;
   588	
   589		if (!priv->tx_ch) {
   590			dev_err(priv->dev, "No initialized mbox tx channel\n");
   591			return;
   592		}
   593	
   594		/*
   595		 * Send the index of the triggered virtqueue as the mu payload.
   596		 * Let remote processor know which virtqueue is used.
   597		 */
   598		mmsg = vqid << 16;
   599	
   600		err = mbox_send_message(priv->tx_ch, (void *)&mmsg);
   601		if (err < 0)
   602			dev_err(priv->dev, "%s: failed (%d, err:%d)\n",
   603				__func__, vqid, err);
   604	}
   605	
   606	static int imx_rproc_attach(struct rproc *rproc)
   607	{
   608		return imx_rproc_xtr_mbox_init(rproc);
   609	}
   610	
   611	static int imx_rproc_detach(struct rproc *rproc)
   612	{
   613		struct imx_rproc *priv = rproc->priv;
   614		const struct imx_rproc_dcfg *dcfg = priv->dcfg;
   615	
   616		if (dcfg->method != IMX_RPROC_SCU_API)
   617			return -EOPNOTSUPP;
   618	
   619		if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id))
   620			return -EOPNOTSUPP;
   621	
   622		imx_rproc_free_mbox(rproc);
   623	
   624		return 0;
   625	}
   626	
   627	static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
   628	{
   629		struct imx_rproc *priv = rproc->priv;
   630	
   631		/* The resource table has already been mapped in imx_rproc_addr_init */
   632		if (!priv->rsc_table)
   633			return NULL;
   634	
   635		*table_sz = SZ_1K;
   636		return (struct resource_table *)priv->rsc_table;
   637	}
   638	
   639	static u64 imx_rproc_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
   640	{
   641		struct imx_rproc *priv = rproc->priv;
   642		const u8 *elf_data = (void *)fw->data;
   643		u8 class = fw_elf_get_class(fw);
   644		u64 bootaddr = rproc_elf_get_boot_addr(rproc, fw);
   645		const void *shdr;
   646		void *va;
   647		u64 sh_addr, offset;
   648	
   649		if (priv->dcfg->devtype == IMX_RPROC_IMX8M) {
   650			/*
   651			 * i.MX8M Cortex-M requires [stack, pc] be put in address
   652			 * [0, 4], so the da address is 0, size is 8 words.
   653			 */
   654			va = rproc_da_to_va(rproc, 0, 8, NULL);
   655			shdr = rproc_elf_find_shdr(rproc, fw, ".interrupts");
   656			if (!shdr || !va)
   657				return bootaddr;
   658			sh_addr = elf_shdr_get_sh_addr(class, shdr);
   659			offset = elf_shdr_get_sh_offset(class, shdr);
   660	
   661			/*
   662			 * Write stack, pc to TCML start address. The TCML region
   663			 * is marked with ATT_IOMEM, so use writel.
   664			 */
 > 665			writel(*(u32 *)(elf_data + offset), va);
 > 666			writel(*(u32 *)(elf_data + offset + 4), va + 4);
   667		}
   668	
   669		return bootaddr;
   670	}
   671
  

Patch

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 13199e593b47..2ddf89e15dc6 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -7,6 +7,7 @@ 
 #include <linux/arm-smccc.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/firmware.h>
 #include <linux/firmware/imx/sci.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -23,6 +24,7 @@ 
 #include <linux/workqueue.h>
 
 #include "imx_rproc.h"
+#include "remoteproc_elf_helpers.h"
 #include "remoteproc_internal.h"
 
 #define IMX7D_SRC_SCR			0x0C
@@ -634,6 +636,39 @@  static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc
 	return (struct resource_table *)priv->rsc_table;
 }
 
+static u64 imx_rproc_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const u8 *elf_data = (void *)fw->data;
+	u8 class = fw_elf_get_class(fw);
+	u64 bootaddr = rproc_elf_get_boot_addr(rproc, fw);
+	const void *shdr;
+	void *va;
+	u64 sh_addr, offset;
+
+	if (priv->dcfg->devtype == IMX_RPROC_IMX8M) {
+		/*
+		 * i.MX8M Cortex-M requires [stack, pc] be put in address
+		 * [0, 4], so the da address is 0, size is 8 words.
+		 */
+		va = rproc_da_to_va(rproc, 0, 8, NULL);
+		shdr = rproc_elf_find_shdr(rproc, fw, ".interrupts");
+		if (!shdr || !va)
+			return bootaddr;
+		sh_addr = elf_shdr_get_sh_addr(class, shdr);
+		offset = elf_shdr_get_sh_offset(class, shdr);
+
+		/*
+		 * Write stack, pc to TCML start address. The TCML region
+		 * is marked with ATT_IOMEM, so use writel.
+		 */
+		writel(*(u32 *)(elf_data + offset), va);
+		writel(*(u32 *)(elf_data + offset + 4), va + 4);
+	}
+
+	return bootaddr;
+}
+
 static const struct rproc_ops imx_rproc_ops = {
 	.prepare	= imx_rproc_prepare,
 	.attach		= imx_rproc_attach,
@@ -647,7 +682,7 @@  static const struct rproc_ops imx_rproc_ops = {
 	.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
 	.get_loaded_rsc_table = imx_rproc_get_loaded_rsc_table,
 	.sanity_check	= rproc_elf_sanity_check,
-	.get_boot_addr	= rproc_elf_get_boot_addr,
+	.get_boot_addr	= imx_rproc_get_boot_addr,
 };
 
 static int imx_rproc_addr_init(struct imx_rproc *priv,