From 145e1da374bcba14c9ca069646f68b76c422612a Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Wed, 3 Mar 2021 13:47:02 -0800 Subject: remoteproc: sysfs: Use sysfs_emit instead of sprintf For security reasons sysfs_emit() is preferred over sprintf(). Hence, convert the remoteproc's sysfs show functions accordingly. Signed-off-by: Raghavendra Rao Ananta Signed-off-by: Siddharth Gupta Link: https://lore.kernel.org/r/1614808022-26062-1-git-send-email-sidgup@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index 1dbef895e65e..6840dad931d5 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -15,7 +15,7 @@ static ssize_t recovery_show(struct device *dev, { struct rproc *rproc = to_rproc(dev); - return sprintf(buf, "%s", rproc->recovery_disabled ? "disabled\n" : "enabled\n"); + return sysfs_emit(buf, "%s", rproc->recovery_disabled ? "disabled\n" : "enabled\n"); } /* @@ -82,7 +82,7 @@ static ssize_t coredump_show(struct device *dev, { struct rproc *rproc = to_rproc(dev); - return sprintf(buf, "%s\n", rproc_coredump_str[rproc->dump_conf]); + return sysfs_emit(buf, "%s\n", rproc_coredump_str[rproc->dump_conf]); } /* -- cgit v1.2.3 From 780a980e2b047768130ddb68d39fbde84b049630 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 24 Feb 2021 16:20:29 +0800 Subject: remoteproc: pru: Replace DEFINE_SIMPLE_ATTRIBUTE with DEFINE_DEBUGFS_ATTRIBUTE Fix the following coccicheck warning: ./drivers/remoteproc/pru_rproc.c:247:0-23: WARNING: pru_rproc_debug_ss_fops should be defined with DEFINE_DEBUGFS_ATTRIBUTE Reviewed-by: Mathieu Poirier Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/1614154829-42461-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/pru_rproc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 2667919d76b3..16b204ed657b 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -244,8 +244,8 @@ static int pru_rproc_debug_ss_get(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(pru_rproc_debug_ss_fops, pru_rproc_debug_ss_get, - pru_rproc_debug_ss_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(pru_rproc_debug_ss_fops, pru_rproc_debug_ss_get, + pru_rproc_debug_ss_set, "%llu\n"); /* * Create PRU-specific debugfs entries -- cgit v1.2.3 From 2bf2346159bc99cf0679e25be20f4daca60f3f5c Mon Sep 17 00:00:00 2001 From: Jindong Yue Date: Wed, 24 Feb 2021 13:58:25 +0800 Subject: remoteproc: core: Remove casting to rproc_handle_resource_t There are four different callback functions that are used for the rproc_handle_resource_t callback that all have different second parameter types. rproc_handle_vdev -> struct fw_rsc_vdev rproc_handle_trace -> struct fw_rsc_trace rproc_handle_devmem -> struct fw_rsc_devmem rproc_handle_carveout -> struct fw_rsc_carveout These callbacks are cast to rproc_handle_resource_t so that there is no error about incompatible pointer types. Unfortunately, this is a Clang's Control-Flow Integrity checking violation, which verifies that the callback function's types match the prototypes exactly before jumping. [ 7.275750] Kernel panic - not syncing: CFI failure (target: rproc_handle_vdev+0x0/0x4) [ 7.283763] CPU: 2 PID: 1 Comm: init Tainted: G C O 5.4.70-03301-g527af2c96672 #17 [ 7.292463] Hardware name: NXP i.MX8MPlus EVK board (DT) [ 7.297779] Call trace: [ 7.300232] dump_backtrace.cfi_jt+0x0/0x4 [ 7.304337] show_stack+0x18/0x24 [ 7.307660] dump_stack+0xb8/0x114 [ 7.311069] panic+0x164/0x3d4 [ 7.314130] __ubsan_handle_cfi_check_fail_abort+0x0/0x14 [ 7.319533] perf_proc_update_handler+0x0/0xcc [ 7.323983] __cfi_check+0x63278/0x6a290 [ 7.327913] rproc_boot+0x3f8/0x738 [ 7.331404] rproc_add+0x68/0x110 [ 7.334738] imx_rproc_probe+0x5e4/0x708 [imx_rproc] [ 7.339711] platform_drv_probe+0xac/0xf0 [ 7.343726] really_probe+0x260/0x65c [ 7.347393] driver_probe_device+0x64/0x100 [ 7.351580] device_driver_attach+0x6c/0xac [ 7.355766] __driver_attach+0xdc/0x184 [ 7.359609] bus_for_each_dev+0x98/0x104 [ 7.363537] driver_attach+0x24/0x30 [ 7.367117] bus_add_driver+0x100/0x1e0 [ 7.370958] driver_register+0x78/0x114 [ 7.374800] __platform_driver_register+0x44/0x50 [ 7.379514] init_module+0x20/0xfe8 [imx_rproc] [ 7.384049] do_one_initcall+0x190/0x348 [ 7.387979] do_init_module+0x5c/0x210 [ 7.391731] load_module+0x2fbc/0x3590 [ 7.395485] __arm64_sys_finit_module+0xb8/0xec [ 7.400025] el0_svc_common+0xb4/0x19c [ 7.403777] el0_svc_handler+0x74/0x98 [ 7.407531] el0_svc+0x8/0xc [ 7.410419] SMP: stopping secondary CPUs [ 7.414648] Kernel Offset: disabled [ 7.418142] CPU features: 0x00010002,2000200c [ 7.422501] Memory Limit: none To fix this, change the second parameter of all functions to void * and use a local variable with the correct type so that everything works properly. With this, we can remove casting to rproc_handle_resource_t for these functions. Signed-off-by: Jindong Yue Reviewed-by: Peng Fan Reviewed-by: Sami Tolvanen Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210224055825.7417-1-jindong.yue@nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index ab150765d124..553e42a4d2a0 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -482,7 +482,7 @@ static int copy_dma_range_map(struct device *to, struct device *from) /** * rproc_handle_vdev() - handle a vdev fw resource * @rproc: the remote processor - * @rsc: the vring resource descriptor + * @ptr: the vring resource descriptor * @offset: offset of the resource entry * @avail: size of available data (for sanity checking the image) * @@ -507,9 +507,10 @@ static int copy_dma_range_map(struct device *to, struct device *from) * * Returns 0 on success, or an appropriate error code otherwise */ -static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, +static int rproc_handle_vdev(struct rproc *rproc, void *ptr, int offset, int avail) { + struct fw_rsc_vdev *rsc = ptr; struct device *dev = &rproc->dev; struct rproc_vdev *rvdev; int i, ret; @@ -627,7 +628,7 @@ void rproc_vdev_release(struct kref *ref) /** * rproc_handle_trace() - handle a shared trace buffer resource * @rproc: the remote processor - * @rsc: the trace resource descriptor + * @ptr: the trace resource descriptor * @offset: offset of the resource entry * @avail: size of available data (for sanity checking the image) * @@ -641,9 +642,10 @@ void rproc_vdev_release(struct kref *ref) * * Returns 0 on success, or an appropriate error code otherwise */ -static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, +static int rproc_handle_trace(struct rproc *rproc, void *ptr, int offset, int avail) { + struct fw_rsc_trace *rsc = ptr; struct rproc_debug_trace *trace; struct device *dev = &rproc->dev; char name[15]; @@ -693,7 +695,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, /** * rproc_handle_devmem() - handle devmem resource entry * @rproc: remote processor handle - * @rsc: the devmem resource entry + * @ptr: the devmem resource entry * @offset: offset of the resource entry * @avail: size of available data (for sanity checking the image) * @@ -716,9 +718,10 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, * and not allow firmwares to request access to physical addresses that * are outside those ranges. */ -static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, +static int rproc_handle_devmem(struct rproc *rproc, void *ptr, int offset, int avail) { + struct fw_rsc_devmem *rsc = ptr; struct rproc_mem_entry *mapping; struct device *dev = &rproc->dev; int ret; @@ -896,7 +899,7 @@ static int rproc_release_carveout(struct rproc *rproc, /** * rproc_handle_carveout() - handle phys contig memory allocation requests * @rproc: rproc handle - * @rsc: the resource entry + * @ptr: the resource entry * @offset: offset of the resource entry * @avail: size of available data (for image validation) * @@ -913,9 +916,9 @@ static int rproc_release_carveout(struct rproc *rproc, * pressure is important; it may have a substantial impact on performance. */ static int rproc_handle_carveout(struct rproc *rproc, - struct fw_rsc_carveout *rsc, - int offset, int avail) + void *ptr, int offset, int avail) { + struct fw_rsc_carveout *rsc = ptr; struct rproc_mem_entry *carveout; struct device *dev = &rproc->dev; @@ -1097,10 +1100,10 @@ EXPORT_SYMBOL(rproc_of_parse_firmware); * enum fw_resource_type. */ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { - [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, - [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, - [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, - [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev, + [RSC_CARVEOUT] = rproc_handle_carveout, + [RSC_DEVMEM] = rproc_handle_devmem, + [RSC_TRACE] = rproc_handle_trace, + [RSC_VDEV] = rproc_handle_vdev, }; /* handle firmware resource entries before booting the remote processor */ -- cgit v1.2.3 From 40df0a91b2a5228ded8e5f75b80d28c96c6831cd Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 6 Mar 2021 19:24:19 +0800 Subject: remoteproc: add is_iomem to da_to_va Introduce an extra parameter is_iomem to da_to_va, then the caller could take the memory as normal memory or io mapped memory. Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier Reported-by: kernel test robot Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/1615029865-23312-5-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 2 +- drivers/remoteproc/ingenic_rproc.c | 2 +- drivers/remoteproc/keystone_remoteproc.c | 2 +- drivers/remoteproc/mtk_scp.c | 6 +++--- drivers/remoteproc/omap_remoteproc.c | 2 +- drivers/remoteproc/pru_rproc.c | 2 +- drivers/remoteproc/qcom_q6v5_adsp.c | 2 +- drivers/remoteproc/qcom_q6v5_pas.c | 2 +- drivers/remoteproc/qcom_q6v5_wcss.c | 2 +- drivers/remoteproc/qcom_wcnss.c | 2 +- drivers/remoteproc/remoteproc_core.c | 7 +++++-- drivers/remoteproc/remoteproc_coredump.c | 8 ++++++-- drivers/remoteproc/remoteproc_debugfs.c | 2 +- drivers/remoteproc/remoteproc_elf_loader.c | 21 +++++++++++++++------ drivers/remoteproc/remoteproc_internal.h | 2 +- drivers/remoteproc/st_slim_rproc.c | 2 +- drivers/remoteproc/ti_k3_dsp_remoteproc.c | 2 +- drivers/remoteproc/ti_k3_r5_remoteproc.c | 2 +- drivers/remoteproc/wkup_m3_rproc.c | 2 +- 19 files changed, 44 insertions(+), 28 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 8957ed271d20..6603e00bb6f4 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -208,7 +208,7 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da, return -ENOENT; } -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct imx_rproc *priv = rproc->priv; void *va = NULL; diff --git a/drivers/remoteproc/ingenic_rproc.c b/drivers/remoteproc/ingenic_rproc.c index e2618c36eaab..a356738160a4 100644 --- a/drivers/remoteproc/ingenic_rproc.c +++ b/drivers/remoteproc/ingenic_rproc.c @@ -121,7 +121,7 @@ static void ingenic_rproc_kick(struct rproc *rproc, int vqid) writel(vqid, vpu->aux_base + REG_CORE_MSG); } -static void *ingenic_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *ingenic_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct vpu *vpu = rproc->priv; void __iomem *va = NULL; diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index cd266163a65f..54781f553f4e 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid) * can be used either by the remoteproc core for loading (when using kernel * remoteproc loader), or by any rpmsg bus drivers. */ -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct keystone_rproc *ksproc = rproc->priv; void __iomem *va = NULL; diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index ce727598c41c..9679cc26895e 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -272,7 +272,7 @@ static int scp_elf_load_segments(struct rproc *rproc, const struct firmware *fw) } /* grab the kernel address for this device address */ - ptr = (void __iomem *)rproc_da_to_va(rproc, da, memsz); + ptr = (void __iomem *)rproc_da_to_va(rproc, da, memsz, NULL); if (!ptr) { dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); ret = -EINVAL; @@ -509,7 +509,7 @@ static void *mt8192_scp_da_to_va(struct mtk_scp *scp, u64 da, size_t len) return NULL; } -static void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; @@ -627,7 +627,7 @@ void *scp_mapping_dm_addr(struct mtk_scp *scp, u32 mem_addr) { void *ptr; - ptr = scp_da_to_va(scp->rproc, mem_addr, 0); + ptr = scp_da_to_va(scp->rproc, mem_addr, 0, NULL); if (!ptr) return ERR_PTR(-EINVAL); diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index d94b7391bf9d..43531caa1959 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -728,7 +728,7 @@ out: * Return: translated virtual address in kernel memory space on success, * or NULL on failure. */ -static void *omap_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *omap_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct omap_rproc *oproc = rproc->priv; int i; diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 16b204ed657b..d6086f90e809 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -465,7 +465,7 @@ static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, size_t len) * core for any PRU client drivers. The PRU Instruction RAM access is restricted * only to the PRU loader code. */ -static void *pru_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *pru_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct pru_rproc *pru = rproc->priv; diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index e02450225e4a..8b0d8bbacd2e 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -281,7 +281,7 @@ static int adsp_stop(struct rproc *rproc) return ret; } -static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; int offset; diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index e635454d6170..ef85b5511dc9 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -242,7 +242,7 @@ static int adsp_stop(struct rproc *rproc) return ret; } -static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; int offset; diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index 78ebe1168b33..704cd63c9af4 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -410,7 +410,7 @@ static int q6v5_wcss_stop(struct rproc *rproc) return 0; } -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct q6v5_wcss *wcss = rproc->priv; int offset; diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 2a6a23cb14ca..3a131163064c 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -320,7 +320,7 @@ static int wcnss_stop(struct rproc *rproc) return ret; } -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; int offset; diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 553e42a4d2a0..5071cdbfc926 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -189,13 +189,13 @@ EXPORT_SYMBOL(rproc_va_to_pa); * here the output of the DMA API for the carveouts, which should be more * correct. */ -void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct rproc_mem_entry *carveout; void *ptr = NULL; if (rproc->ops->da_to_va) { - ptr = rproc->ops->da_to_va(rproc, da, len); + ptr = rproc->ops->da_to_va(rproc, da, len, is_iomem); if (ptr) goto out; } @@ -217,6 +217,9 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) ptr = carveout->va + offset; + if (is_iomem) + *is_iomem = carveout->is_iomem; + break; } diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index 81ec154a6a5e..aee657cc08c6 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -153,18 +153,22 @@ static void rproc_copy_segment(struct rproc *rproc, void *dest, size_t offset, size_t size) { void *ptr; + bool is_iomem; if (segment->dump) { segment->dump(rproc, segment, dest, offset, size); } else { - ptr = rproc_da_to_va(rproc, segment->da + offset, size); + ptr = rproc_da_to_va(rproc, segment->da + offset, size, &is_iomem); if (!ptr) { dev_err(&rproc->dev, "invalid copy request for segment %pad with offset %zu and size %zu)\n", &segment->da, offset, size); memset(dest, 0xff, size); } else { - memcpy(dest, ptr, size); + if (is_iomem) + memcpy_fromio(dest, ptr, size); + else + memcpy(dest, ptr, size); } } } diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 7e5845376e9f..b5a1e3b697d9 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -132,7 +132,7 @@ static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf, char buf[100]; int len; - va = rproc_da_to_va(data->rproc, trace->da, trace->len); + va = rproc_da_to_va(data->rproc, trace->da, trace->len, NULL); if (!va) { len = scnprintf(buf, sizeof(buf), "Trace %s not available\n", diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index df68d87752e4..11423588965a 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -175,6 +175,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) u64 offset = elf_phdr_get_p_offset(class, phdr); u32 type = elf_phdr_get_p_type(class, phdr); void *ptr; + bool is_iomem; if (type != PT_LOAD) continue; @@ -204,7 +205,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) } /* grab the kernel address for this device address */ - ptr = rproc_da_to_va(rproc, da, memsz); + ptr = rproc_da_to_va(rproc, da, memsz, &is_iomem); if (!ptr) { dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da, memsz); @@ -213,8 +214,12 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) } /* put the segment where the remote processor expects it */ - if (filesz) - memcpy(ptr, elf_data + offset, filesz); + if (filesz) { + if (is_iomem) + memcpy_fromio(ptr, (void __iomem *)(elf_data + offset), filesz); + else + memcpy(ptr, elf_data + offset, filesz); + } /* * Zero out remaining memory for this segment. @@ -223,8 +228,12 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) * did this for us. albeit harmless, we may consider removing * this. */ - if (memsz > filesz) - memset(ptr + filesz, 0, memsz - filesz); + if (memsz > filesz) { + if (is_iomem) + memset_io((void __iomem *)(ptr + filesz), 0, memsz - filesz); + else + memset(ptr + filesz, 0, memsz - filesz); + } } return ret; @@ -377,6 +386,6 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc, return NULL; } - return rproc_da_to_va(rproc, sh_addr, sh_size); + return rproc_da_to_va(rproc, sh_addr, sh_size, NULL); } EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table); diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index c34002888d2c..9ea37aa687d2 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -84,7 +84,7 @@ static inline void rproc_char_device_remove(struct rproc *rproc) void rproc_free_vring(struct rproc_vring *rvring); int rproc_alloc_vring(struct rproc_vdev *rvdev, int i); -void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len); +void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem); phys_addr_t rproc_va_to_pa(void *cpu_addr); int rproc_trigger_recovery(struct rproc *rproc); diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c index 09bcb4d8b9e0..22096adc1ad3 100644 --- a/drivers/remoteproc/st_slim_rproc.c +++ b/drivers/remoteproc/st_slim_rproc.c @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc) return 0; } -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct st_slim_rproc *slim_rproc = rproc->priv; void *va = NULL; diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c index 863c0214e0a8..fd4eb67a6681 100644 --- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c +++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c @@ -354,7 +354,7 @@ static int k3_dsp_rproc_stop(struct rproc *rproc) * can be used either by the remoteproc core for loading (when using kernel * remoteproc loader), or by any rpmsg bus drivers. */ -static void *k3_dsp_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *k3_dsp_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct k3_dsp_rproc *kproc = rproc->priv; void __iomem *va = NULL; diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index 62b5a4c29456..5cf8d030a1f0 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -590,7 +590,7 @@ out: * present in a DSP or IPU device). The translated addresses can be used * either by the remoteproc core for loading, or by any rpmsg bus drivers. */ -static void *k3_r5_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *k3_r5_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct k3_r5_rproc *kproc = rproc->priv; struct k3_r5_core *core = kproc->core; diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 92d387dfc03b..484f7605823e 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -89,7 +89,7 @@ static int wkup_m3_rproc_stop(struct rproc *rproc) return error; } -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { struct wkup_m3_rproc *wkupm3 = rproc->priv; void *va = NULL; -- cgit v1.2.3 From 1896b3d82c555eaec6f6bde0c8d12377060bb22d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 6 Mar 2021 19:24:20 +0800 Subject: remoteproc: imx_rproc: correct err message It is using devm_ioremap, so not devm_ioremap_resource. Correct the error message and print out sa/size. Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/1615029865-23312-6-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 6603e00bb6f4..2a093cea4997 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -268,7 +268,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev, att->sa, att->size); if (!priv->mem[b].cpu_addr) { - dev_err(dev, "devm_ioremap_resource failed\n"); + dev_err(dev, "failed to remap %#x bytes from %#x\n", att->size, att->sa); return -ENOMEM; } priv->mem[b].sys_addr = att->sa; @@ -298,7 +298,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, priv->mem[b].cpu_addr = devm_ioremap_resource(&pdev->dev, &res); if (IS_ERR(priv->mem[b].cpu_addr)) { - dev_err(dev, "devm_ioremap_resource failed\n"); + dev_err(dev, "failed to remap %pr\n", &res); err = PTR_ERR(priv->mem[b].cpu_addr); return err; } -- cgit v1.2.3 From ecadcc47492cc73a9bb92fbf16098192df514b87 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 6 Mar 2021 19:24:21 +0800 Subject: remoteproc: imx_rproc: use devm_ioremap We might need to map an region multiple times, becaue the region might be shared between remote processors, such i.MX8QM with dual M4 cores. So use devm_ioremap, not devm_ioremap_resource. Reviewed-by: Oleksij Rempel Reviewed-by: Richard Zhu Signed-off-by: Peng Fan Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/1615029865-23312-7-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 2a093cea4997..47fc1d06be6a 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -296,7 +296,8 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, if (b >= IMX7D_RPROC_MEM_MAX) break; - priv->mem[b].cpu_addr = devm_ioremap_resource(&pdev->dev, &res); + /* Not use resource version, because we might share region */ + priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev, res.start, resource_size(&res)); if (IS_ERR(priv->mem[b].cpu_addr)) { dev_err(dev, "failed to remap %pr\n", &res); err = PTR_ERR(priv->mem[b].cpu_addr); -- cgit v1.2.3 From b29b4249f8f0cad1a1787cbe59e638ff23d489ed Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 6 Mar 2021 19:24:22 +0800 Subject: remoteproc: imx_rproc: add i.MX specific parse fw hook The hook is used to parse memory-regions and load resource table from the address the remote processor published. Reviewed-by: Richard Zhu Reviewed-by: Mathieu Poirier Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/1615029865-23312-8-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 47fc1d06be6a..5ae1f5209548 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -241,10 +242,102 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *i return va; } +static int imx_rproc_mem_alloc(struct rproc *rproc, + struct rproc_mem_entry *mem) +{ + struct device *dev = rproc->dev.parent; + void *va; + + dev_dbg(dev, "map memory: %p+%zx\n", &mem->dma, mem->len); + va = ioremap_wc(mem->dma, mem->len); + if (IS_ERR_OR_NULL(va)) { + dev_err(dev, "Unable to map memory region: %p+%zx\n", + &mem->dma, mem->len); + return -ENOMEM; + } + + /* Update memory entry va */ + mem->va = va; + + return 0; +} + +static int imx_rproc_mem_release(struct rproc *rproc, + struct rproc_mem_entry *mem) +{ + dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma); + iounmap(mem->va); + + return 0; +} + +static int imx_rproc_parse_memory_regions(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct device_node *np = priv->dev->of_node; + struct of_phandle_iterator it; + struct rproc_mem_entry *mem; + struct reserved_mem *rmem; + u32 da; + + /* Register associated reserved memory regions */ + of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); + while (of_phandle_iterator_next(&it) == 0) { + /* + * Ignore the first memory region which will be used vdev buffer. + * No need to do extra handlings, rproc_add_virtio_dev will handle it. + */ + if (!strcmp(it.node->name, "vdev0buffer")) + continue; + + rmem = of_reserved_mem_lookup(it.node); + if (!rmem) { + dev_err(priv->dev, "unable to acquire memory-region\n"); + return -EINVAL; + } + + /* No need to translate pa to da, i.MX use same map */ + da = rmem->base; + + /* Register memory region */ + mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)rmem->base, rmem->size, da, + imx_rproc_mem_alloc, imx_rproc_mem_release, + it.node->name); + + if (mem) + rproc_coredump_add_segment(rproc, da, rmem->size); + else + return -ENOMEM; + + rproc_add_carveout(rproc, mem); + } + + return 0; +} + +static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) +{ + int ret = imx_rproc_parse_memory_regions(rproc); + + if (ret) + return ret; + + ret = rproc_elf_load_rsc_table(rproc, fw); + if (ret) + dev_info(&rproc->dev, "No resource table in elf\n"); + + return 0; +} + static const struct rproc_ops imx_rproc_ops = { .start = imx_rproc_start, .stop = imx_rproc_stop, .da_to_va = imx_rproc_da_to_va, + .load = rproc_elf_load_segments, + .parse_fw = imx_rproc_parse_fw, + .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, + .sanity_check = rproc_elf_sanity_check, + .get_boot_addr = rproc_elf_get_boot_addr, }; static int imx_rproc_addr_init(struct imx_rproc *priv, -- cgit v1.2.3 From 4ab8f9607aad6323826c9b945dee52e565975fcc Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 6 Mar 2021 19:24:23 +0800 Subject: remoteproc: imx_rproc: support i.MX8MQ/M Add i.MX8MQ dev/sys addr map and configuration data structure i.MX8MM share i.MX8MQ settings. Reviewed-by: Richard Zhu Reviewed-by: Mathieu Poirier Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/1615029865-23312-9-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 6 +++--- drivers/remoteproc/imx_rproc.c | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 15d1574d129b..7cf3d1b40c55 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -24,11 +24,11 @@ config REMOTEPROC_CDEV It's safe to say N if you don't want to use this interface. config IMX_REMOTEPROC - tristate "IMX6/7 remoteproc support" + tristate "i.MX remoteproc support" depends on ARCH_MXC help - Say y here to support iMX's remote processors (Cortex M4 - on iMX7D) via the remote processor framework. + Say y here to support iMX's remote processors via the remote + processor framework. It's safe to say N here. diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 5ae1f5209548..0124ebf69838 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -88,6 +88,34 @@ struct imx_rproc { struct clk *clk; }; +static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { + /* dev addr , sys addr , size , flags */ + /* TCML - alias */ + { 0x00000000, 0x007e0000, 0x00020000, 0 }, + /* OCRAM_S */ + { 0x00180000, 0x00180000, 0x00008000, 0 }, + /* OCRAM */ + { 0x00900000, 0x00900000, 0x00020000, 0 }, + /* OCRAM */ + { 0x00920000, 0x00920000, 0x00020000, 0 }, + /* QSPI Code - alias */ + { 0x08000000, 0x08000000, 0x08000000, 0 }, + /* DDR (Code) - alias */ + { 0x10000000, 0x80000000, 0x0FFE0000, 0 }, + /* TCML */ + { 0x1FFE0000, 0x007E0000, 0x00020000, ATT_OWN }, + /* TCMU */ + { 0x20000000, 0x00800000, 0x00020000, ATT_OWN }, + /* OCRAM_S */ + { 0x20180000, 0x00180000, 0x00008000, ATT_OWN }, + /* OCRAM */ + { 0x20200000, 0x00900000, 0x00020000, ATT_OWN }, + /* OCRAM */ + { 0x20220000, 0x00920000, 0x00020000, ATT_OWN }, + /* DDR (Data) */ + { 0x40000000, 0x40000000, 0x80000000, 0 }, +}; + static const struct imx_rproc_att imx_rproc_att_imx7d[] = { /* dev addr , sys addr , size , flags */ /* OCRAM_S (M4 Boot code) - alias */ @@ -138,6 +166,15 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX7D_M4_STOP, + .att = imx_rproc_att_imx8mq, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { .src_reg = IMX7D_SRC_SCR, .src_mask = IMX7D_M4_RST_MASK, @@ -496,6 +533,8 @@ static int imx_rproc_remove(struct platform_device *pdev) static const struct of_device_id imx_rproc_of_match[] = { { .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d }, { .compatible = "fsl,imx6sx-cm4", .data = &imx_rproc_cfg_imx6sx }, + { .compatible = "fsl,imx8mq-cm4", .data = &imx_rproc_cfg_imx8mq }, + { .compatible = "fsl,imx8mm-cm4", .data = &imx_rproc_cfg_imx8mq }, {}, }; MODULE_DEVICE_TABLE(of, imx_rproc_of_match); @@ -512,5 +551,5 @@ static struct platform_driver imx_rproc_driver = { module_platform_driver(imx_rproc_driver); MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("IMX6SX/7D remote processor control driver"); +MODULE_DESCRIPTION("i.MX remote processor control driver"); MODULE_AUTHOR("Oleksij Rempel "); -- cgit v1.2.3 From 8f2d8961640f0346cbe892273c3260a0d30c1931 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 6 Mar 2021 19:24:24 +0800 Subject: remoteproc: imx_rproc: ignore mapping vdev regions vdev regions are vdev0vring0, vdev0vring1, vdevbuffer and similar. They are handled by remoteproc common code, no need to map in imx rproc driver. Signed-off-by: Peng Fan Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/1615029865-23312-10-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 0124ebf69838..3685bbd135b0 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -417,6 +417,9 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, struct resource res; node = of_parse_phandle(np, "memory-region", a); + /* Not map vdev region */ + if (!strcmp(node->name, "vdev")) + continue; err = of_address_to_resource(node, 0, &res); if (err) { dev_err(dev, "unable to resolve memory region\n"); -- cgit v1.2.3 From 2df7062002d0263bde70b453f671bb4f8493e169 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 6 Mar 2021 19:24:25 +0800 Subject: remoteproc: imx_proc: enable virtio/mailbox Use virtio/mailbox to build connection between Remote Proccessors and Linux. Add work queue to handle incoming messages. Reviewed-by: Richard Zhu Reviewed-by: Mathieu Poirier Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/1615029865-23312-11-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 116 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 3 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 3685bbd135b0..5ebb9f57d3e0 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,9 @@ #include #include #include +#include + +#include "remoteproc_internal.h" #define IMX7D_SRC_SCR 0x0C #define IMX7D_ENABLE_M4 BIT(3) @@ -86,6 +90,11 @@ struct imx_rproc { const struct imx_rproc_dcfg *dcfg; struct imx_rproc_mem mem[IMX7D_RPROC_MEM_MAX]; struct clk *clk; + struct mbox_client cl; + struct mbox_chan *tx_ch; + struct mbox_chan *rx_ch; + struct work_struct rproc_work; + struct workqueue_struct *workqueue; }; static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { @@ -366,9 +375,33 @@ static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) return 0; } +static void imx_rproc_kick(struct rproc *rproc, int vqid) +{ + struct imx_rproc *priv = rproc->priv; + int err; + __u32 mmsg; + + if (!priv->tx_ch) { + dev_err(priv->dev, "No initialized mbox tx channel\n"); + return; + } + + /* + * Send the index of the triggered virtqueue as the mu payload. + * Let remote processor know which virtqueue is used. + */ + mmsg = vqid << 16; + + err = mbox_send_message(priv->tx_ch, (void *)&mmsg); + if (err < 0) + dev_err(priv->dev, "%s: failed (%d, err:%d)\n", + __func__, vqid, err); +} + static const struct rproc_ops imx_rproc_ops = { .start = imx_rproc_start, .stop = imx_rproc_stop, + .kick = imx_rproc_kick, .da_to_va = imx_rproc_da_to_va, .load = rproc_elf_load_segments, .parse_fw = imx_rproc_parse_fw, @@ -444,6 +477,66 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, return 0; } +static void imx_rproc_vq_work(struct work_struct *work) +{ + struct imx_rproc *priv = container_of(work, struct imx_rproc, + rproc_work); + + rproc_vq_interrupt(priv->rproc, 0); + rproc_vq_interrupt(priv->rproc, 1); +} + +static void imx_rproc_rx_callback(struct mbox_client *cl, void *msg) +{ + struct rproc *rproc = dev_get_drvdata(cl->dev); + struct imx_rproc *priv = rproc->priv; + + queue_work(priv->workqueue, &priv->rproc_work); +} + +static int imx_rproc_xtr_mbox_init(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct device *dev = priv->dev; + struct mbox_client *cl; + int ret; + + if (!of_get_property(dev->of_node, "mbox-names", NULL)) + return 0; + + cl = &priv->cl; + cl->dev = dev; + cl->tx_block = true; + cl->tx_tout = 100; + cl->knows_txdone = false; + cl->rx_callback = imx_rproc_rx_callback; + + priv->tx_ch = mbox_request_channel_byname(cl, "tx"); + if (IS_ERR(priv->tx_ch)) { + ret = PTR_ERR(priv->tx_ch); + return dev_err_probe(cl->dev, ret, + "failed to request tx mailbox channel: %d\n", ret); + } + + priv->rx_ch = mbox_request_channel_byname(cl, "rx"); + if (IS_ERR(priv->rx_ch)) { + mbox_free_channel(priv->tx_ch); + ret = PTR_ERR(priv->rx_ch); + return dev_err_probe(cl->dev, ret, + "failed to request rx mailbox channel: %d\n", ret); + } + + return 0; +} + +static void imx_rproc_free_mbox(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + + mbox_free_channel(priv->tx_ch); + mbox_free_channel(priv->rx_ch); +} + static int imx_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -481,18 +574,28 @@ static int imx_rproc_probe(struct platform_device *pdev) priv->dev = dev; dev_set_drvdata(dev, rproc); + priv->workqueue = create_workqueue(dev_name(dev)); + if (!priv->workqueue) { + dev_err(dev, "cannot create workqueue\n"); + ret = -ENOMEM; + goto err_put_rproc; + } + + ret = imx_rproc_xtr_mbox_init(rproc); + if (ret) + goto err_put_wkq; ret = imx_rproc_addr_init(priv, pdev); if (ret) { dev_err(dev, "failed on imx_rproc_addr_init\n"); - goto err_put_rproc; + goto err_put_mbox; } priv->clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->clk)) { dev_err(dev, "Failed to get clock\n"); ret = PTR_ERR(priv->clk); - goto err_put_rproc; + goto err_put_mbox; } /* @@ -502,9 +605,11 @@ static int imx_rproc_probe(struct platform_device *pdev) ret = clk_prepare_enable(priv->clk); if (ret) { dev_err(&rproc->dev, "Failed to enable clock\n"); - goto err_put_rproc; + goto err_put_mbox; } + INIT_WORK(&priv->rproc_work, imx_rproc_vq_work); + ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed\n"); @@ -515,6 +620,10 @@ static int imx_rproc_probe(struct platform_device *pdev) err_put_clk: clk_disable_unprepare(priv->clk); +err_put_mbox: + imx_rproc_free_mbox(rproc); +err_put_wkq: + destroy_workqueue(priv->workqueue); err_put_rproc: rproc_free(rproc); @@ -528,6 +637,7 @@ static int imx_rproc_remove(struct platform_device *pdev) clk_disable_unprepare(priv->clk); rproc_del(rproc); + imx_rproc_free_mbox(rproc); rproc_free(rproc); return 0; -- cgit v1.2.3 From 18cda8018a4b5f4819e02ad2cabf40c3666c6366 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 12 Mar 2021 08:04:20 +0000 Subject: remoteproc: imx_rproc: fix return value check in imx_rproc_addr_init() In case of error, the function devm_ioremap() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Fixes: ecadcc47492c ("remoteproc: imx_rproc: use devm_ioremap") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20210312080420.277151-1-weiyongjun1@huawei.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 5ebb9f57d3e0..6d3207ccbaef 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -464,10 +464,9 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, /* Not use resource version, because we might share region */ priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev, res.start, resource_size(&res)); - if (IS_ERR(priv->mem[b].cpu_addr)) { + if (!priv->mem[b].cpu_addr) { dev_err(dev, "failed to remap %pr\n", &res); - err = PTR_ERR(priv->mem[b].cpu_addr); - return err; + return -ENOMEM; } priv->mem[b].sys_addr = res.start; priv->mem[b].size = resource_size(&res); -- cgit v1.2.3 From 9af2a2a9c64ee68a5dc8271d54235609191f1cd1 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 11 Mar 2021 16:26:05 -0800 Subject: remoteproc: qcom_q6v5_mss: Provide errors for firmware-name parsing Failing to read the "firmware-name" DT property without informing the developer is annoying, add some helpful debug prints. Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210312002605.3273255-1-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 66106ba25ba3..15abfbba78d2 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1661,8 +1661,10 @@ static int q6v5_probe(struct platform_device *pdev) mba_image = desc->hexagon_mba_image; ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name", 0, &mba_image); - if (ret < 0 && ret != -EINVAL) + if (ret < 0 && ret != -EINVAL) { + dev_err(&pdev->dev, "unable to read mba firmware-name\n"); return ret; + } rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops, mba_image, sizeof(*qproc)); @@ -1680,8 +1682,10 @@ static int q6v5_probe(struct platform_device *pdev) qproc->hexagon_mdt_image = "modem.mdt"; ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name", 1, &qproc->hexagon_mdt_image); - if (ret < 0 && ret != -EINVAL) + if (ret < 0 && ret != -EINVAL) { + dev_err(&pdev->dev, "unable to read mpss firmware-name\n"); goto free_rproc; + } platform_set_drvdata(pdev, qproc); -- cgit v1.2.3 From 3d2ee78906af5f08d499d6aa3aa504406fa38106 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 12 Mar 2021 15:20:02 -0800 Subject: remoteproc: qcom_q6v5_mss: Validate p_filesz in ELF loader Analog to the issue in the common mdt_loader code the MSS ELF loader does not validate that p_filesz bytes will fit in the memory region and that the loaded segments are not truncated. Fix this in the same way as proposed for the mdt_loader. Reviewed-by: Mathieu Poirier Fixes: 135b9e8d1cd8 ("remoteproc: qcom_q6v5_mss: Validate modem blob firmware size before load") Link: https://lore.kernel.org/r/20210312232002.3466791-1-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 15abfbba78d2..423b31dfa574 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1210,6 +1210,14 @@ static int q6v5_mpss_load(struct q6v5 *qproc) goto release_firmware; } + if (phdr->p_filesz > phdr->p_memsz) { + dev_err(qproc->dev, + "refusing to load segment %d with p_filesz > p_memsz\n", + i); + ret = -EINVAL; + goto release_firmware; + } + ptr = memremap(qproc->mpss_phys + offset, phdr->p_memsz, MEMREMAP_WC); if (!ptr) { dev_err(qproc->dev, @@ -1241,6 +1249,16 @@ static int q6v5_mpss_load(struct q6v5 *qproc) goto release_firmware; } + if (seg_fw->size != phdr->p_filesz) { + dev_err(qproc->dev, + "failed to load segment %d from truncated file %s\n", + i, fw_name); + ret = -EINVAL; + release_firmware(seg_fw); + memunmap(ptr); + goto release_firmware; + } + release_firmware(seg_fw); } -- cgit v1.2.3 From 16324fc8def1c08a92261089aaf503aca3381aa6 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:37 -0700 Subject: remoteproc: Remove useless check in rproc_del() Whether started at probe() time or thereafter from the command line, a remote processor needs to be shut down before the final cleanup phases can happen. Otherwise the system may be left in an unpredictable state where the remote processor is expecting the remoteproc core to be providing services when in fact it no longer exist. Invariably calling rproc_shutdown() is fine since it will return immediately if the remote processor has already been switched off. Signed-off-by: Mathieu Poirier Reviewed-by: Peng Fan Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-2-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 5071cdbfc926..4c2e678732f5 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2353,10 +2353,8 @@ int rproc_del(struct rproc *rproc) if (!rproc) return -EINVAL; - /* if rproc is marked always-on, rproc_add() booted it */ /* TODO: make sure this works with rproc->power > 1 */ - if (rproc->auto_boot) - rproc_shutdown(rproc); + rproc_shutdown(rproc); mutex_lock(&rproc->lock); rproc->state = RPROC_DELETED; -- cgit v1.2.3 From 6a6c4dc0e5de5dc4fec0ccda417c26f5814be380 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:38 -0700 Subject: remoteproc: Rename function rproc_actuate() Rename function rproc_actuate() to rproc_attach(). That way it is easy to understand that it does the opposite of rproc_detach(). Signed-off-by: Mathieu Poirier Reviewed-by: Peng Fan Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-3-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 4c2e678732f5..9127b2aa5424 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1422,7 +1422,7 @@ reset_table_ptr: return ret; } -static int rproc_attach(struct rproc *rproc) +static int __rproc_attach(struct rproc *rproc) { struct device *dev = &rproc->dev; int ret; @@ -1547,7 +1547,7 @@ disable_iommu: * Attach to remote processor - similar to rproc_fw_boot() but without * the steps that deal with the firmware image. */ -static int rproc_actuate(struct rproc *rproc) +static int rproc_attach(struct rproc *rproc) { struct device *dev = &rproc->dev; int ret; @@ -1587,7 +1587,7 @@ static int rproc_actuate(struct rproc *rproc) goto clean_up_resources; } - ret = rproc_attach(rproc); + ret = __rproc_attach(rproc); if (ret) goto clean_up_resources; @@ -1808,7 +1808,7 @@ int rproc_boot(struct rproc *rproc) if (rproc->state == RPROC_DETACHED) { dev_info(dev, "attaching to %s\n", rproc->name); - ret = rproc_actuate(rproc); + ret = rproc_attach(rproc); } else { dev_info(dev, "powering up %s\n", rproc->name); -- cgit v1.2.3 From 4196d18903f94090f0a223d65de25e3bf50a3d13 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:39 -0700 Subject: remoteproc: Add new RPROC_ATTACHED state Add a new RPROC_ATTACHED state to take into account scenarios where the remoteproc core needs to attach to a remote processor that is booted by another entity. Signed-off-by: Mathieu Poirier Reviewed-by: Peng Fan Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-4-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_sysfs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index 6840dad931d5..26fd9ceecdb5 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -172,6 +172,7 @@ static const char * const rproc_state_string[] = { [RPROC_RUNNING] = "running", [RPROC_CRASHED] = "crashed", [RPROC_DELETED] = "deleted", + [RPROC_ATTACHED] = "attached", [RPROC_DETACHED] = "detached", [RPROC_LAST] = "invalid", }; -- cgit v1.2.3 From 76f4c87587e2ff41e9b9867ffde2137f27ba39b9 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:40 -0700 Subject: remoteproc: Properly represent the attached state There is a need to know when a remote processor has been attached to rather than booted by the remoteproc core. In order to avoid manipulating two variables, i.e rproc::autonomous and rproc::state, get rid of the former and simply use the newly introduced RPROC_ATTACHED state. Signed-off-by: Mathieu Poirier Reviewed-by: Peng Fan Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-5-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 20 +------------------- drivers/remoteproc/remoteproc_sysfs.c | 5 +---- 2 files changed, 2 insertions(+), 23 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9127b2aa5424..d828c01f4f8a 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1450,7 +1450,7 @@ static int __rproc_attach(struct rproc *rproc) goto stop_rproc; } - rproc->state = RPROC_RUNNING; + rproc->state = RPROC_ATTACHED; dev_info(dev, "remote processor %s is now attached\n", rproc->name); @@ -1665,14 +1665,6 @@ static int rproc_stop(struct rproc *rproc, bool crashed) rproc->state = RPROC_OFFLINE; - /* - * The remote processor has been stopped and is now offline, which means - * that the next time it is brought back online the remoteproc core will - * be responsible to load its firmware. As such it is no longer - * autonomous. - */ - rproc->autonomous = false; - dev_info(dev, "stopped remote processor %s\n", rproc->name); return 0; @@ -2083,16 +2075,6 @@ int rproc_add(struct rproc *rproc) if (ret < 0) return ret; - /* - * Remind ourselves the remote processor has been attached to rather - * than booted by the remoteproc core. This is important because the - * RPROC_DETACHED state will be lost as soon as the remote processor - * has been attached to. Used in firmware_show() and reset in - * rproc_stop(). - */ - if (rproc->state == RPROC_DETACHED) - rproc->autonomous = true; - /* if rproc is marked always-on, request it to boot */ if (rproc->auto_boot) { ret = rproc_trigger_auto_boot(rproc); diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index 26fd9ceecdb5..4f58be1e13c1 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -138,11 +138,8 @@ static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, * If the remote processor has been started by an external * entity we have no idea of what image it is running. As such * simply display a generic string rather then rproc->firmware. - * - * Here we rely on the autonomous flag because a remote processor - * may have been attached to and currently in a running state. */ - if (rproc->autonomous) + if (rproc->state == RPROC_ATTACHED) firmware = "unknown"; return sprintf(buf, "%s\n", firmware); -- cgit v1.2.3 From 1a631382be1d22ddab0582dae3498b3d28e2e44a Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:41 -0700 Subject: remoteproc: Add new get_loaded_rsc_table() to rproc_ops Add a new get_loaded_rsc_table() operation in order to support scenarios where the remoteproc core has booted a remote processor and detaches from it. When re-attaching to the remote processor, the core needs to know where the resource table has been placed in memory. Signed-off-by: Mathieu Poirier Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-6-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 32 ++++++++++++++++++++++++++++++++ drivers/remoteproc/remoteproc_internal.h | 10 ++++++++++ 2 files changed, 42 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index d828c01f4f8a..c7e1cf1b6f66 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1543,6 +1543,32 @@ disable_iommu: return ret; } +static int rproc_set_rsc_table(struct rproc *rproc) +{ + struct resource_table *table_ptr; + struct device *dev = &rproc->dev; + size_t table_sz; + int ret; + + table_ptr = rproc_get_loaded_rsc_table(rproc, &table_sz); + if (!table_ptr) { + /* Not having a resource table is acceptable */ + return 0; + } + + if (IS_ERR(table_ptr)) { + ret = PTR_ERR(table_ptr); + dev_err(dev, "can't load resource table: %d\n", ret); + return ret; + } + + rproc->cached_table = NULL; + rproc->table_ptr = table_ptr; + rproc->table_sz = table_sz; + + return 0; +} + /* * Attach to remote processor - similar to rproc_fw_boot() but without * the steps that deal with the firmware image. @@ -1562,6 +1588,12 @@ static int rproc_attach(struct rproc *rproc) return ret; } + ret = rproc_set_rsc_table(rproc); + if (ret) { + dev_err(dev, "can't load resource table: %d\n", ret); + goto disable_iommu; + } + /* reset max_notifyid */ rproc->max_notifyid = -1; diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index 9ea37aa687d2..a328e634b1de 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -177,6 +177,16 @@ struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc, return NULL; } +static inline +struct resource_table *rproc_get_loaded_rsc_table(struct rproc *rproc, + size_t *size) +{ + if (rproc->ops->get_loaded_rsc_table) + return rproc->ops->get_loaded_rsc_table(rproc, size); + + return NULL; +} + static inline bool rproc_u64_fit_in_size_t(u64 val) { -- cgit v1.2.3 From 8a471396d21ca499d89d4071b2b670258f009ffa Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:42 -0700 Subject: remoteproc: stm32: Move resource table setup to rproc_ops Move the setting of the resource table installed by an external entity to rproc_ops::get_loaded_rsc_table(). This is to support scenarios where a remote processor has been attached to but is detached at a later stage. To re-attach the remote processor, the address of the resource table needs to be available at a later time than the platform driver's probe() function. Signed-off-by: Mathieu Poirier Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-7-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/stm32_rproc.c | 141 +++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 73 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index ccb3c14a0023..f647e565014b 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -546,6 +546,73 @@ static void stm32_rproc_kick(struct rproc *rproc, int vqid) } } +static int stm32_rproc_da_to_pa(struct rproc *rproc, + u64 da, phys_addr_t *pa) +{ + struct stm32_rproc *ddata = rproc->priv; + struct device *dev = rproc->dev.parent; + struct stm32_rproc_mem *p_mem; + unsigned int i; + + for (i = 0; i < ddata->nb_rmems; i++) { + p_mem = &ddata->rmems[i]; + + if (da < p_mem->dev_addr || + da >= p_mem->dev_addr + p_mem->size) + continue; + + *pa = da - p_mem->dev_addr + p_mem->bus_addr; + dev_dbg(dev, "da %llx to pa %#x\n", da, *pa); + + return 0; + } + + dev_err(dev, "can't translate da %llx\n", da); + + return -EINVAL; +} + +static struct resource_table * +stm32_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz) +{ + struct stm32_rproc *ddata = rproc->priv; + struct device *dev = rproc->dev.parent; + phys_addr_t rsc_pa; + u32 rsc_da; + int err; + + /* The resource table has already been mapped, nothing to do */ + if (ddata->rsc_va) + goto done; + + err = regmap_read(ddata->rsctbl.map, ddata->rsctbl.reg, &rsc_da); + if (err) { + dev_err(dev, "failed to read rsc tbl addr\n"); + return ERR_PTR(-EINVAL); + } + + if (!rsc_da) + /* no rsc table */ + return ERR_PTR(-ENOENT); + + err = stm32_rproc_da_to_pa(rproc, rsc_da, &rsc_pa); + if (err) + return ERR_PTR(err); + + ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, RSC_TBL_SIZE); + if (IS_ERR_OR_NULL(ddata->rsc_va)) { + dev_err(dev, "Unable to map memory region: %pa+%zx\n", + &rsc_pa, RSC_TBL_SIZE); + ddata->rsc_va = NULL; + return ERR_PTR(-ENOMEM); + } + +done: + /* Assuming the resource table fits in 1kB is fair */ + *table_sz = RSC_TBL_SIZE; + return (struct resource_table *)ddata->rsc_va; +} + static const struct rproc_ops st_rproc_ops = { .start = stm32_rproc_start, .stop = stm32_rproc_stop, @@ -554,6 +621,7 @@ static const struct rproc_ops st_rproc_ops = { .load = rproc_elf_load_segments, .parse_fw = stm32_rproc_parse_fw, .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, + .get_loaded_rsc_table = stm32_rproc_get_loaded_rsc_table, .sanity_check = rproc_elf_sanity_check, .get_boot_addr = rproc_elf_get_boot_addr, }; @@ -695,75 +763,6 @@ static int stm32_rproc_get_m4_status(struct stm32_rproc *ddata, return regmap_read(ddata->m4_state.map, ddata->m4_state.reg, state); } -static int stm32_rproc_da_to_pa(struct platform_device *pdev, - struct stm32_rproc *ddata, - u64 da, phys_addr_t *pa) -{ - struct device *dev = &pdev->dev; - struct stm32_rproc_mem *p_mem; - unsigned int i; - - for (i = 0; i < ddata->nb_rmems; i++) { - p_mem = &ddata->rmems[i]; - - if (da < p_mem->dev_addr || - da >= p_mem->dev_addr + p_mem->size) - continue; - - *pa = da - p_mem->dev_addr + p_mem->bus_addr; - dev_dbg(dev, "da %llx to pa %#x\n", da, *pa); - - return 0; - } - - dev_err(dev, "can't translate da %llx\n", da); - - return -EINVAL; -} - -static int stm32_rproc_get_loaded_rsc_table(struct platform_device *pdev, - struct rproc *rproc, - struct stm32_rproc *ddata) -{ - struct device *dev = &pdev->dev; - phys_addr_t rsc_pa; - u32 rsc_da; - int err; - - err = regmap_read(ddata->rsctbl.map, ddata->rsctbl.reg, &rsc_da); - if (err) { - dev_err(dev, "failed to read rsc tbl addr\n"); - return err; - } - - if (!rsc_da) - /* no rsc table */ - return 0; - - err = stm32_rproc_da_to_pa(pdev, ddata, rsc_da, &rsc_pa); - if (err) - return err; - - ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, RSC_TBL_SIZE); - if (IS_ERR_OR_NULL(ddata->rsc_va)) { - dev_err(dev, "Unable to map memory region: %pa+%zx\n", - &rsc_pa, RSC_TBL_SIZE); - ddata->rsc_va = NULL; - return -ENOMEM; - } - - /* - * The resource table is already loaded in device memory, no need - * to work with a cached table. - */ - rproc->cached_table = NULL; - /* Assuming the resource table fits in 1kB is fair */ - rproc->table_sz = RSC_TBL_SIZE; - rproc->table_ptr = (struct resource_table *)ddata->rsc_va; - - return 0; -} - static int stm32_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -803,10 +802,6 @@ static int stm32_rproc_probe(struct platform_device *pdev) ret = stm32_rproc_parse_memory_regions(rproc); if (ret) goto free_resources; - - ret = stm32_rproc_get_loaded_rsc_table(pdev, rproc, ddata); - if (ret) - goto free_resources; } rproc->has_iommu = false; -- cgit v1.2.3 From 6e20a05104e55dc0e4899db8110013d521d20a6e Mon Sep 17 00:00:00 2001 From: Arnaud POULIQUEN Date: Fri, 12 Mar 2021 09:24:43 -0700 Subject: remoteproc: stm32: Move memory parsing to rproc_ops Some actions such as memory resources reallocation are needed when trying to reattach a co-processor. Use the prepare() operation for these actions. Co-developed-by: Mathieu Poirier Signed-off-by: Mathieu Poirier Signed-off-by: Arnaud POULIQUEN Link: https://lore.kernel.org/r/20210312162453.1234145-8-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 14 ++++++++++++-- drivers/remoteproc/stm32_rproc.c | 27 ++++++--------------------- 2 files changed, 18 insertions(+), 23 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index c7e1cf1b6f66..de670f4f592c 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1588,10 +1588,17 @@ static int rproc_attach(struct rproc *rproc) return ret; } + /* Do anything that is needed to boot the remote processor */ + ret = rproc_prepare_device(rproc); + if (ret) { + dev_err(dev, "can't prepare rproc %s: %d\n", rproc->name, ret); + goto disable_iommu; + } + ret = rproc_set_rsc_table(rproc); if (ret) { dev_err(dev, "can't load resource table: %d\n", ret); - goto disable_iommu; + goto unprepare_device; } /* reset max_notifyid */ @@ -1608,7 +1615,7 @@ static int rproc_attach(struct rproc *rproc) ret = rproc_handle_resources(rproc, rproc_loading_handlers); if (ret) { dev_err(dev, "Failed to process resources: %d\n", ret); - goto disable_iommu; + goto unprepare_device; } /* Allocate carveout resources associated to rproc */ @@ -1627,6 +1634,9 @@ static int rproc_attach(struct rproc *rproc) clean_up_resources: rproc_resource_cleanup(rproc); +unprepare_device: + /* release HW resources if needed */ + rproc_unprepare_device(rproc); disable_iommu: rproc_disable_iommu(rproc); return ret; diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index f647e565014b..3d45f51de4d0 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -207,16 +207,7 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name) return -EINVAL; } -static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc, - const struct firmware *fw) -{ - if (rproc_elf_load_rsc_table(rproc, fw)) - dev_warn(&rproc->dev, "no resource table found for this firmware\n"); - - return 0; -} - -static int stm32_rproc_parse_memory_regions(struct rproc *rproc) +static int stm32_rproc_prepare(struct rproc *rproc) { struct device *dev = rproc->dev.parent; struct device_node *np = dev->of_node; @@ -274,12 +265,10 @@ static int stm32_rproc_parse_memory_regions(struct rproc *rproc) static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) { - int ret = stm32_rproc_parse_memory_regions(rproc); - - if (ret) - return ret; + if (rproc_elf_load_rsc_table(rproc, fw)) + dev_warn(&rproc->dev, "no resource table found for this firmware\n"); - return stm32_rproc_elf_load_rsc_table(rproc, fw); + return 0; } static irqreturn_t stm32_rproc_wdg(int irq, void *data) @@ -614,6 +603,7 @@ done: } static const struct rproc_ops st_rproc_ops = { + .prepare = stm32_rproc_prepare, .start = stm32_rproc_start, .stop = stm32_rproc_stop, .attach = stm32_rproc_attach, @@ -796,14 +786,9 @@ static int stm32_rproc_probe(struct platform_device *pdev) if (ret) goto free_rproc; - if (state == M4_STATE_CRUN) { + if (state == M4_STATE_CRUN) rproc->state = RPROC_DETACHED; - ret = stm32_rproc_parse_memory_regions(rproc); - if (ret) - goto free_resources; - } - rproc->has_iommu = false; ddata->workqueue = create_workqueue(dev_name(dev)); if (!ddata->workqueue) { -- cgit v1.2.3 From 6070203fe43335a02b7fd103bae582095411adc5 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:45 -0700 Subject: remoteproc: Introduce function __rproc_detach() Introduce function __rproc_detach() to perform the same kind of operation as rproc_stop(), but instead of switching off the remote processor using rproc->ops->stop(), it uses rproc->ops->detach(). That way it is possible for the core to release the resources associated with a remote processor while the latter is kept operating. Signed-off-by: Mathieu Poirier Reviewed-by: Peng Fan Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-10-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index de670f4f592c..23e9040386c2 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1712,6 +1712,36 @@ static int rproc_stop(struct rproc *rproc, bool crashed) return 0; } +/* + * __rproc_detach(): Does the opposite of __rproc_attach() + */ +static int __maybe_unused __rproc_detach(struct rproc *rproc) +{ + struct device *dev = &rproc->dev; + int ret; + + /* No need to continue if a detach() operation has not been provided */ + if (!rproc->ops->detach) + return -EINVAL; + + /* Stop any subdevices for the remote processor */ + rproc_stop_subdevices(rproc, false); + + /* Tell the remote processor the core isn't available anymore */ + ret = rproc->ops->detach(rproc); + if (ret) { + dev_err(dev, "can't detach from rproc: %d\n", ret); + return ret; + } + + rproc_unprepare_subdevices(rproc); + + rproc->state = RPROC_DETACHED; + + dev_info(dev, "detached remote processor %s\n", rproc->name); + + return 0; +} /** * rproc_trigger_recovery() - recover a remoteproc -- cgit v1.2.3 From d3962a397885518a85d2dc6b0c51e6594f71c30f Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:46 -0700 Subject: remoteproc: Introduce function rproc_detach() Introduce function rproc_detach() to enable the remoteproc core to release the resources associated with a remote processor without stopping its operation. Signed-off-by: Mathieu Poirier Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-11-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 58 +++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 23e9040386c2..78a36a3723ec 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1715,7 +1715,7 @@ static int rproc_stop(struct rproc *rproc, bool crashed) /* * __rproc_detach(): Does the opposite of __rproc_attach() */ -static int __maybe_unused __rproc_detach(struct rproc *rproc) +static int __rproc_detach(struct rproc *rproc) { struct device *dev = &rproc->dev; int ret; @@ -1954,6 +1954,62 @@ out: } EXPORT_SYMBOL(rproc_shutdown); +/** + * rproc_detach() - Detach the remote processor from the + * remoteproc core + * + * @rproc: the remote processor + * + * Detach a remote processor (previously attached to with rproc_attach()). + * + * In case @rproc is still being used by an additional user(s), then + * this function will just decrement the power refcount and exit, + * without disconnecting the device. + * + * Function rproc_detach() calls __rproc_detach() in order to let a remote + * processor know that services provided by the application processor are + * no longer available. From there it should be possible to remove the + * platform driver and even power cycle the application processor (if the HW + * supports it) without needing to switch off the remote processor. + */ +int rproc_detach(struct rproc *rproc) +{ + struct device *dev = &rproc->dev; + int ret; + + ret = mutex_lock_interruptible(&rproc->lock); + if (ret) { + dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret); + return ret; + } + + /* if the remote proc is still needed, bail out */ + if (!atomic_dec_and_test(&rproc->power)) { + ret = 0; + goto out; + } + + ret = __rproc_detach(rproc); + if (ret) { + atomic_inc(&rproc->power); + goto out; + } + + /* clean up all acquired resources */ + rproc_resource_cleanup(rproc); + + /* release HW resources if needed */ + rproc_unprepare_device(rproc); + + rproc_disable_iommu(rproc); + + rproc->table_ptr = NULL; +out: + mutex_unlock(&rproc->lock); + return ret; +} +EXPORT_SYMBOL(rproc_detach); + /** * rproc_get_by_phandle() - find a remote processor by phandle * @phandle: phandle to the rproc -- cgit v1.2.3 From 9dc9507f1880fb6225e3e058cb5219b152cbf198 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:47 -0700 Subject: remoteproc: Properly deal with the resource table when detaching If it is possible to detach the remote processor, keep an untouched copy of the resource table. That way we can start from the same resource table without having to worry about original values or what elements the startup code has changed when re-attaching to the remote processor. Signed-off-by: Mathieu Poirier Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-12-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 78a36a3723ec..57c851d22ba6 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1562,6 +1562,24 @@ static int rproc_set_rsc_table(struct rproc *rproc) return ret; } + /* + * If it is possible to detach the remote processor, keep an untouched + * copy of the resource table. That way we can start fresh again when + * the remote processor is re-attached, that is: + * + * DETACHED -> ATTACHED -> DETACHED -> ATTACHED + * + * Free'd in rproc_reset_rsc_table_on_detach() and + * rproc_reset_rsc_table_on_stop(). + */ + if (rproc->ops->detach) { + rproc->clean_table = kmemdup(table_ptr, table_sz, GFP_KERNEL); + if (!rproc->clean_table) + return -ENOMEM; + } else { + rproc->clean_table = NULL; + } + rproc->cached_table = NULL; rproc->table_ptr = table_ptr; rproc->table_sz = table_sz; @@ -1569,6 +1587,59 @@ static int rproc_set_rsc_table(struct rproc *rproc) return 0; } +static int rproc_reset_rsc_table_on_detach(struct rproc *rproc) +{ + struct resource_table *table_ptr; + + /* A resource table was never retrieved, nothing to do here */ + if (!rproc->table_ptr) + return 0; + + /* + * If we made it to this point a clean_table _must_ have been + * allocated in rproc_set_rsc_table(). If one isn't present + * something went really wrong and we must complain. + */ + if (WARN_ON(!rproc->clean_table)) + return -EINVAL; + + /* Remember where the external entity installed the resource table */ + table_ptr = rproc->table_ptr; + + /* + * If we made it here the remote processor was started by another + * entity and a cache table doesn't exist. As such make a copy of + * the resource table currently used by the remote processor and + * use that for the rest of the shutdown process. The memory + * allocated here is free'd in rproc_detach(). + */ + rproc->cached_table = kmemdup(rproc->table_ptr, + rproc->table_sz, GFP_KERNEL); + if (!rproc->cached_table) + return -ENOMEM; + + /* + * Use a copy of the resource table for the remainder of the + * shutdown process. + */ + rproc->table_ptr = rproc->cached_table; + + /* + * Reset the memory area where the firmware loaded the resource table + * to its original value. That way when we re-attach the remote + * processor the resource table is clean and ready to be used again. + */ + memcpy(table_ptr, rproc->clean_table, rproc->table_sz); + + /* + * The clean resource table is no longer needed. Allocated in + * rproc_set_rsc_table(). + */ + kfree(rproc->clean_table); + + return 0; +} + /* * Attach to remote processor - similar to rproc_fw_boot() but without * the steps that deal with the firmware image. @@ -1727,6 +1798,13 @@ static int __rproc_detach(struct rproc *rproc) /* Stop any subdevices for the remote processor */ rproc_stop_subdevices(rproc, false); + /* the installed resource table is no longer accessible */ + ret = rproc_reset_rsc_table_on_detach(rproc); + if (ret) { + dev_err(dev, "can't reset resource table: %d\n", ret); + return ret; + } + /* Tell the remote processor the core isn't available anymore */ ret = rproc->ops->detach(rproc); if (ret) { @@ -2003,6 +2081,9 @@ int rproc_detach(struct rproc *rproc) rproc_disable_iommu(rproc); + /* Free the copy of the resource table */ + kfree(rproc->cached_table); + rproc->cached_table = NULL; rproc->table_ptr = NULL; out: mutex_unlock(&rproc->lock); -- cgit v1.2.3 From 8088dd4d9316964901b13df09a20ee0f917f414d Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:48 -0700 Subject: remoteproc: Properly deal with the resource table when stopping When a remote processor that was attached to is stopped, special care must be taken to make sure the shutdown process is similar to what it would be had it been started by the remoteproc core. This patch takes care of that by making a copy of the resource table currently used by the remote processor. From that point on the copy is used, as if the remote processor had been started by the remoteproc core. Signed-off-by: Mathieu Poirier Reviewed-by: Arnaud Pouliquen Reported-by: kernel test robot Link: https://lore.kernel.org/r/20210312162453.1234145-13-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 48 +++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 57c851d22ba6..163fad5b95a1 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1640,6 +1640,47 @@ static int rproc_reset_rsc_table_on_detach(struct rproc *rproc) return 0; } +static int rproc_reset_rsc_table_on_stop(struct rproc *rproc) +{ + /* A resource table was never retrieved, nothing to do here */ + if (!rproc->table_ptr) + return 0; + + /* + * If a cache table exists the remote processor was started by + * the remoteproc core. That cache table should be used for + * the rest of the shutdown process. + */ + if (rproc->cached_table) + goto out; + + /* + * If we made it here the remote processor was started by another + * entity and a cache table doesn't exist. As such make a copy of + * the resource table currently used by the remote processor and + * use that for the rest of the shutdown process. The memory + * allocated here is free'd in rproc_shutdown(). + */ + rproc->cached_table = kmemdup(rproc->table_ptr, + rproc->table_sz, GFP_KERNEL); + if (!rproc->cached_table) + return -ENOMEM; + + /* + * Since the remote processor is being switched off the clean table + * won't be needed. Allocated in rproc_set_rsc_table(). + */ + kfree(rproc->clean_table); + +out: + /* + * Use a copy of the resource table for the remainder of the + * shutdown process. + */ + rproc->table_ptr = rproc->cached_table; + return 0; +} + /* * Attach to remote processor - similar to rproc_fw_boot() but without * the steps that deal with the firmware image. @@ -1765,7 +1806,12 @@ static int rproc_stop(struct rproc *rproc, bool crashed) rproc_stop_subdevices(rproc, crashed); /* the installed resource table is no longer accessible */ - rproc->table_ptr = rproc->cached_table; + ret = rproc_reset_rsc_table_on_stop(rproc); + if (ret) { + dev_err(dev, "can't reset resource table: %d\n", ret); + return ret; + } + /* power off the remote processor */ ret = rproc->ops->stop(rproc); -- cgit v1.2.3 From 800dad0025ecb9ca8c885414cab070f8cc40e81e Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:49 -0700 Subject: remoteproc: Properly deal with a kernel panic when attached The panic handler operation of registered remote processors should also be called when remote processors have been attached to. Signed-off-by: Mathieu Poirier Reviewed-by: Peng Fan Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-14-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 163fad5b95a1..4cf6ef7e15b5 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2733,7 +2733,11 @@ static int rproc_panic_handler(struct notifier_block *nb, unsigned long event, rcu_read_lock(); list_for_each_entry_rcu(rproc, &rproc_list, node) { - if (!rproc->ops->panic || rproc->state != RPROC_RUNNING) + if (!rproc->ops->panic) + continue; + + if (rproc->state != RPROC_RUNNING && + rproc->state != RPROC_ATTACHED) continue; d = rproc->ops->panic(rproc); -- cgit v1.2.3 From 83d4e6712c3b1a7dd5b43251737ea3d7d0a460f4 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:50 -0700 Subject: remoteproc: Properly deal with a start request when attached This patch takes into account scenarios where a remote processor has been attached to when receiving a "start" command from sysfs. As with the case with the running state, the command can't be carried out if the remote processor is already in operation. Signed-off-by: Mathieu Poirier Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-15-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_cdev.c | 3 ++- drivers/remoteproc/remoteproc_sysfs.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c index b19ea3057bde..b2cee9afb41b 100644 --- a/drivers/remoteproc/remoteproc_cdev.c +++ b/drivers/remoteproc/remoteproc_cdev.c @@ -32,7 +32,8 @@ static ssize_t rproc_cdev_write(struct file *filp, const char __user *buf, size_ return -EFAULT; if (!strncmp(cmd, "start", len)) { - if (rproc->state == RPROC_RUNNING) + if (rproc->state == RPROC_RUNNING || + rproc->state == RPROC_ATTACHED) return -EBUSY; ret = rproc_boot(rproc); diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index 4f58be1e13c1..bbfa238e4707 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -194,7 +194,8 @@ static ssize_t state_store(struct device *dev, int ret = 0; if (sysfs_streq(buf, "start")) { - if (rproc->state == RPROC_RUNNING) + if (rproc->state == RPROC_RUNNING || + rproc->state == RPROC_ATTACHED) return -EBUSY; ret = rproc_boot(rproc); -- cgit v1.2.3 From d2008a96833082713094ba8a545141be1b01b266 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:51 -0700 Subject: remoteproc: Properly deal with a stop request when attached Allow a remote processor that was started by another entity to be switched off by the remoteproc core. For that to happen a rproc::ops::stop() operation needs to be available. Signed-off-by: Mathieu Poirier Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-16-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_cdev.c | 3 ++- drivers/remoteproc/remoteproc_core.c | 4 ++++ drivers/remoteproc/remoteproc_sysfs.c | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c index b2cee9afb41b..0249d8f6c3f8 100644 --- a/drivers/remoteproc/remoteproc_cdev.c +++ b/drivers/remoteproc/remoteproc_cdev.c @@ -38,7 +38,8 @@ static ssize_t rproc_cdev_write(struct file *filp, const char __user *buf, size_ ret = rproc_boot(rproc); } else if (!strncmp(cmd, "stop", len)) { - if (rproc->state != RPROC_RUNNING) + if (rproc->state != RPROC_RUNNING && + rproc->state != RPROC_ATTACHED) return -EINVAL; rproc_shutdown(rproc); diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 4cf6ef7e15b5..626a6b90fba2 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1802,6 +1802,10 @@ static int rproc_stop(struct rproc *rproc, bool crashed) struct device *dev = &rproc->dev; int ret; + /* No need to continue if a stop() operation has not been provided */ + if (!rproc->ops->stop) + return -EINVAL; + /* Stop any subdevices for the remote processor */ rproc_stop_subdevices(rproc, crashed); diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index bbfa238e4707..23c0dc1ddc34 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -202,7 +202,8 @@ static ssize_t state_store(struct device *dev, if (ret) dev_err(&rproc->dev, "Boot failed: %d\n", ret); } else if (sysfs_streq(buf, "stop")) { - if (rproc->state != RPROC_RUNNING) + if (rproc->state != RPROC_RUNNING && + rproc->state != RPROC_ATTACHED) return -EINVAL; rproc_shutdown(rproc); -- cgit v1.2.3 From 5daaeb5f07ed0681b734864dde58dcadab115963 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:52 -0700 Subject: remoteproc: Properly deal with a detach request when attached This patch introduces the capability to detach a remote processor that has been attached to by the remoteproc core. For that to happen a rproc::ops::detach() operation needs to be available. Signed-off-by: Mathieu Poirier Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210312162453.1234145-17-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_cdev.c | 5 +++++ drivers/remoteproc/remoteproc_sysfs.c | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c index 0249d8f6c3f8..2db494816d5f 100644 --- a/drivers/remoteproc/remoteproc_cdev.c +++ b/drivers/remoteproc/remoteproc_cdev.c @@ -43,6 +43,11 @@ static ssize_t rproc_cdev_write(struct file *filp, const char __user *buf, size_ return -EINVAL; rproc_shutdown(rproc); + } else if (!strncmp(cmd, "detach", len)) { + if (rproc->state != RPROC_ATTACHED) + return -EINVAL; + + ret = rproc_detach(rproc); } else { dev_err(&rproc->dev, "Unrecognized option\n"); ret = -EINVAL; diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index 23c0dc1ddc34..ea8b89f97d7b 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -207,6 +207,11 @@ static ssize_t state_store(struct device *dev, return -EINVAL; rproc_shutdown(rproc); + } else if (sysfs_streq(buf, "detach")) { + if (rproc->state != RPROC_ATTACHED) + return -EINVAL; + + ret = rproc_detach(rproc); } else { dev_err(&rproc->dev, "Unrecognised option: %s\n", buf); ret = -EINVAL; -- cgit v1.2.3 From 6e71d2b2a2b717c3bddbe72cdf48dd07d53f8364 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 12 Mar 2021 09:24:53 -0700 Subject: remoteproc: Refactor function rproc_cdev_release() Refactor function rproc_cdev_release() to take into account the current state of the remote processor when choosing the state to transition to. Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210312162453.1234145-18-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_cdev.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c index 2db494816d5f..0b8a84c04f76 100644 --- a/drivers/remoteproc/remoteproc_cdev.c +++ b/drivers/remoteproc/remoteproc_cdev.c @@ -86,11 +86,17 @@ static long rproc_device_ioctl(struct file *filp, unsigned int ioctl, unsigned l static int rproc_cdev_release(struct inode *inode, struct file *filp) { struct rproc *rproc = container_of(inode->i_cdev, struct rproc, cdev); + int ret = 0; + + if (!rproc->cdev_put_on_release) + return 0; - if (rproc->cdev_put_on_release && rproc->state == RPROC_RUNNING) + if (rproc->state == RPROC_RUNNING) rproc_shutdown(rproc); + else if (rproc->state == RPROC_ATTACHED) + ret = rproc_detach(rproc); - return 0; + return ret; } static const struct file_operations rproc_fops = { -- cgit v1.2.3 From 6549f42c3d179575cd1466c4fd65d76680e49fed Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 29 Jan 2021 00:18:12 +0530 Subject: remoteproc: qcom: wcss: populate hardcoded param using driver data Q6 based WiFi fw loading is supported across different targets, ex: IPQ8074/QCS404. In order to support different fw names/pas id etc, populate hardcoded param using driver data. Signed-off-by: Govind Singh Signed-off-by: Gokul Sriram Palanisamy Link: https://lore.kernel.org/r/1611859695-11824-2-git-send-email-gokulsri@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_wcss.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index 704cd63c9af4..0a37c6e665df 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -71,6 +71,11 @@ #define TCSR_WCSS_CLK_MASK 0x1F #define TCSR_WCSS_CLK_ENABLE 0x14 +struct wcss_data { + const char *firmware_name; + unsigned int crash_reason_smem; +}; + struct q6v5_wcss { struct device *dev; @@ -93,6 +98,8 @@ struct q6v5_wcss { void *mem_region; size_t mem_size; + unsigned int crash_reason_smem; + struct qcom_rproc_glink glink_subdev; struct qcom_rproc_ssr ssr_subdev; }; @@ -438,7 +445,7 @@ static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw) return ret; } -static const struct rproc_ops q6v5_wcss_ops = { +static const struct rproc_ops q6v5_wcss_ipq8074_ops = { .start = q6v5_wcss_start, .stop = q6v5_wcss_stop, .da_to_va = q6v5_wcss_da_to_va, @@ -538,12 +545,17 @@ static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss) static int q6v5_wcss_probe(struct platform_device *pdev) { + const struct wcss_data *desc; struct q6v5_wcss *wcss; struct rproc *rproc; int ret; - rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_wcss_ops, - "IPQ8074/q6_fw.mdt", sizeof(*wcss)); + desc = device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_wcss_ipq8074_ops, + desc->firmware_name, sizeof(*wcss)); if (!rproc) { dev_err(&pdev->dev, "failed to allocate rproc\n"); return -ENOMEM; @@ -551,6 +563,7 @@ static int q6v5_wcss_probe(struct platform_device *pdev) wcss = rproc->priv; wcss->dev = &pdev->dev; + wcss->crash_reason_smem = desc->crash_reason_smem; ret = q6v5_wcss_init_mmio(wcss, pdev); if (ret) @@ -564,7 +577,8 @@ static int q6v5_wcss_probe(struct platform_device *pdev) if (ret) goto free_rproc; - ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, WCSS_CRASH_REASON, NULL); + ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, desc->crash_reason_smem, + NULL); if (ret) goto free_rproc; @@ -595,8 +609,13 @@ static int q6v5_wcss_remove(struct platform_device *pdev) return 0; } +static const struct wcss_data wcss_ipq8074_res_init = { + .firmware_name = "IPQ8074/q6_fw.mdt", + .crash_reason_smem = WCSS_CRASH_REASON, +}; + static const struct of_device_id q6v5_wcss_of_match[] = { - { .compatible = "qcom,ipq8074-wcss-pil" }, + { .compatible = "qcom,ipq8074-wcss-pil", .data = &wcss_ipq8074_res_init }, { }, }; MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match); -- cgit v1.2.3 From 0af65b9b915e52019aee91db3e1f8b39a7ec8d08 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 29 Jan 2021 00:18:14 +0530 Subject: remoteproc: qcom: wcss: Add non pas wcss Q6 support for QCS404 Add non PAS WCSS remoteproc driver support for QCS404 SOC. Add WCSS q6 bootup and shutdown sequence handled from Application Processor SubSystem(APSS). Signed-off-by: Govind Singh Signed-off-by: Gokul Sriram Palanisamy Link: https://lore.kernel.org/r/1611859695-11824-4-git-send-email-gokulsri@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_wcss.c | 566 +++++++++++++++++++++++++++++++++--- 1 file changed, 528 insertions(+), 38 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index 0a37c6e665df..d67264c93996 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -4,13 +4,18 @@ * Copyright (C) 2014 Sony Mobile Communications AB * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. */ +#include +#include +#include #include #include #include #include +#include #include #include #include +#include #include #include #include "qcom_common.h" @@ -24,6 +29,9 @@ #define Q6SS_GFMUX_CTL_REG 0x020 #define Q6SS_PWR_CTL_REG 0x030 #define Q6SS_MEM_PWR_CTL 0x0B0 +#define Q6SS_STRAP_ACC 0x110 +#define Q6SS_CGC_OVERRIDE 0x034 +#define Q6SS_BCR_REG 0x6000 /* AXI Halt Register Offsets */ #define AXI_HALTREQ_REG 0x0 @@ -37,14 +45,19 @@ #define Q6SS_CORE_ARES BIT(1) #define Q6SS_BUS_ARES_ENABLE BIT(2) +/* Q6SS_BRC_RESET */ +#define Q6SS_BRC_BLK_ARES BIT(0) + /* Q6SS_GFMUX_CTL */ #define Q6SS_CLK_ENABLE BIT(1) +#define Q6SS_SWITCH_CLK_SRC BIT(8) /* Q6SS_PWR_CTL */ #define Q6SS_L2DATA_STBY_N BIT(18) #define Q6SS_SLP_RET_N BIT(19) #define Q6SS_CLAMP_IO BIT(20) #define QDSS_BHS_ON BIT(21) +#define QDSS_Q6_MEMORIES GENMASK(15, 0) /* Q6SS parameters */ #define Q6SS_LDO_BYP BIT(25) @@ -53,6 +66,7 @@ #define Q6SS_CLAMP_QMC_MEM BIT(22) #define HALT_CHECK_MAX_LOOPS 200 #define Q6SS_XO_CBCR GENMASK(5, 3) +#define Q6SS_SLEEP_CBCR GENMASK(5, 2) /* Q6SS config/status registers */ #define TCSR_GLOBAL_CFG0 0x0 @@ -71,9 +85,23 @@ #define TCSR_WCSS_CLK_MASK 0x1F #define TCSR_WCSS_CLK_ENABLE 0x14 +#define MAX_HALT_REG 3 +enum { + WCSS_IPQ8074, + WCSS_QCS404, +}; + struct wcss_data { const char *firmware_name; unsigned int crash_reason_smem; + u32 version; + bool aon_reset_required; + bool wcss_q6_reset_required; + const char *ssr_name; + const char *sysmon_name; + int ssctl_id; + const struct rproc_ops *ops; + bool requires_force_stop; }; struct q6v5_wcss { @@ -87,9 +115,26 @@ struct q6v5_wcss { u32 halt_wcss; u32 halt_nc; + struct clk *xo; + struct clk *ahbfabric_cbcr_clk; + struct clk *gcc_abhs_cbcr; + struct clk *gcc_axim_cbcr; + struct clk *lcc_csr_cbcr; + struct clk *ahbs_cbcr; + struct clk *tcm_slave_cbcr; + struct clk *qdsp6ss_abhm_cbcr; + struct clk *qdsp6ss_sleep_cbcr; + struct clk *qdsp6ss_axim_cbcr; + struct clk *qdsp6ss_xo_cbcr; + struct clk *qdsp6ss_core_gfmux; + struct clk *lcc_bcr_sleep; + struct regulator *cx_supply; + struct qcom_sysmon *sysmon; + struct reset_control *wcss_aon_reset; struct reset_control *wcss_reset; struct reset_control *wcss_q6_reset; + struct reset_control *wcss_q6_bcr_reset; struct qcom_q6v5 q6v5; @@ -99,6 +144,8 @@ struct q6v5_wcss { size_t mem_size; unsigned int crash_reason_smem; + u32 version; + bool requires_force_stop; struct qcom_rproc_glink glink_subdev; struct qcom_rproc_ssr ssr_subdev; @@ -244,6 +291,207 @@ wcss_reset: return ret; } +static int q6v5_wcss_qcs404_power_on(struct q6v5_wcss *wcss) +{ + unsigned long val; + int ret, idx; + + /* Toggle the restart */ + reset_control_assert(wcss->wcss_reset); + usleep_range(200, 300); + reset_control_deassert(wcss->wcss_reset); + usleep_range(200, 300); + + /* Enable GCC_WDSP_Q6SS_AHBS_CBCR clock */ + ret = clk_prepare_enable(wcss->gcc_abhs_cbcr); + if (ret) + return ret; + + /* Remove reset to the WCNSS QDSP6SS */ + reset_control_deassert(wcss->wcss_q6_bcr_reset); + + /* Enable Q6SSTOP_AHBFABRIC_CBCR clock */ + ret = clk_prepare_enable(wcss->ahbfabric_cbcr_clk); + if (ret) + goto disable_gcc_abhs_cbcr_clk; + + /* Enable the LCCCSR CBC clock, Q6SSTOP_Q6SSTOP_LCC_CSR_CBCR clock */ + ret = clk_prepare_enable(wcss->lcc_csr_cbcr); + if (ret) + goto disable_ahbfabric_cbcr_clk; + + /* Enable the Q6AHBS CBC, Q6SSTOP_Q6SS_AHBS_CBCR clock */ + ret = clk_prepare_enable(wcss->ahbs_cbcr); + if (ret) + goto disable_csr_cbcr_clk; + + /* Enable the TCM slave CBC, Q6SSTOP_Q6SS_TCM_SLAVE_CBCR clock */ + ret = clk_prepare_enable(wcss->tcm_slave_cbcr); + if (ret) + goto disable_ahbs_cbcr_clk; + + /* Enable the Q6SS AHB master CBC, Q6SSTOP_Q6SS_AHBM_CBCR clock */ + ret = clk_prepare_enable(wcss->qdsp6ss_abhm_cbcr); + if (ret) + goto disable_tcm_slave_cbcr_clk; + + /* Enable the Q6SS AXI master CBC, Q6SSTOP_Q6SS_AXIM_CBCR clock */ + ret = clk_prepare_enable(wcss->qdsp6ss_axim_cbcr); + if (ret) + goto disable_abhm_cbcr_clk; + + /* Enable the Q6SS XO CBC */ + val = readl(wcss->reg_base + Q6SS_XO_CBCR); + val |= BIT(0); + writel(val, wcss->reg_base + Q6SS_XO_CBCR); + /* Read CLKOFF bit to go low indicating CLK is enabled */ + ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR, + val, !(val & BIT(31)), 1, + HALT_CHECK_MAX_LOOPS); + if (ret) { + dev_err(wcss->dev, + "xo cbcr enabling timed out (rc:%d)\n", ret); + return ret; + } + + writel(0, wcss->reg_base + Q6SS_CGC_OVERRIDE); + + /* Enable QDSP6 sleep clock clock */ + val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR); + val |= BIT(0); + writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR); + + /* Enable the Enable the Q6 AXI clock, GCC_WDSP_Q6SS_AXIM_CBCR*/ + ret = clk_prepare_enable(wcss->gcc_axim_cbcr); + if (ret) + goto disable_sleep_cbcr_clk; + + /* Assert resets, stop core */ + val = readl(wcss->reg_base + Q6SS_RESET_REG); + val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE; + writel(val, wcss->reg_base + Q6SS_RESET_REG); + + /* Program the QDSP6SS PWR_CTL register */ + writel(0x01700000, wcss->reg_base + Q6SS_PWR_CTL_REG); + + writel(0x03700000, wcss->reg_base + Q6SS_PWR_CTL_REG); + + writel(0x03300000, wcss->reg_base + Q6SS_PWR_CTL_REG); + + writel(0x033C0000, wcss->reg_base + Q6SS_PWR_CTL_REG); + + /* + * Enable memories by turning on the QDSP6 memory foot/head switch, one + * bank at a time to avoid in-rush current + */ + for (idx = 28; idx >= 0; idx--) { + writel((readl(wcss->reg_base + Q6SS_MEM_PWR_CTL) | + (1 << idx)), wcss->reg_base + Q6SS_MEM_PWR_CTL); + } + + writel(0x031C0000, wcss->reg_base + Q6SS_PWR_CTL_REG); + writel(0x030C0000, wcss->reg_base + Q6SS_PWR_CTL_REG); + + val = readl(wcss->reg_base + Q6SS_RESET_REG); + val &= ~Q6SS_CORE_ARES; + writel(val, wcss->reg_base + Q6SS_RESET_REG); + + /* Enable the Q6 core clock at the GFM, Q6SSTOP_QDSP6SS_GFMUX_CTL */ + val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG); + val |= Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC; + writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG); + + /* Enable sleep clock branch needed for BCR circuit */ + ret = clk_prepare_enable(wcss->lcc_bcr_sleep); + if (ret) + goto disable_core_gfmux_clk; + + return 0; + +disable_core_gfmux_clk: + val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG); + val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC); + writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG); + clk_disable_unprepare(wcss->gcc_axim_cbcr); +disable_sleep_cbcr_clk: + val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR); + val &= ~Q6SS_CLK_ENABLE; + writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR); + val = readl(wcss->reg_base + Q6SS_XO_CBCR); + val &= ~Q6SS_CLK_ENABLE; + writel(val, wcss->reg_base + Q6SS_XO_CBCR); + clk_disable_unprepare(wcss->qdsp6ss_axim_cbcr); +disable_abhm_cbcr_clk: + clk_disable_unprepare(wcss->qdsp6ss_abhm_cbcr); +disable_tcm_slave_cbcr_clk: + clk_disable_unprepare(wcss->tcm_slave_cbcr); +disable_ahbs_cbcr_clk: + clk_disable_unprepare(wcss->ahbs_cbcr); +disable_csr_cbcr_clk: + clk_disable_unprepare(wcss->lcc_csr_cbcr); +disable_ahbfabric_cbcr_clk: + clk_disable_unprepare(wcss->ahbfabric_cbcr_clk); +disable_gcc_abhs_cbcr_clk: + clk_disable_unprepare(wcss->gcc_abhs_cbcr); + + return ret; +} + +static inline int q6v5_wcss_qcs404_reset(struct q6v5_wcss *wcss) +{ + unsigned long val; + + writel(0x80800000, wcss->reg_base + Q6SS_STRAP_ACC); + + /* Start core execution */ + val = readl(wcss->reg_base + Q6SS_RESET_REG); + val &= ~Q6SS_STOP_CORE; + writel(val, wcss->reg_base + Q6SS_RESET_REG); + + return 0; +} + +static int q6v5_qcs404_wcss_start(struct rproc *rproc) +{ + struct q6v5_wcss *wcss = rproc->priv; + int ret; + + ret = clk_prepare_enable(wcss->xo); + if (ret) + return ret; + + ret = regulator_enable(wcss->cx_supply); + if (ret) + goto disable_xo_clk; + + qcom_q6v5_prepare(&wcss->q6v5); + + ret = q6v5_wcss_qcs404_power_on(wcss); + if (ret) { + dev_err(wcss->dev, "wcss clk_enable failed\n"); + goto disable_cx_supply; + } + + writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB); + + q6v5_wcss_qcs404_reset(wcss); + + ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ); + if (ret == -ETIMEDOUT) { + dev_err(wcss->dev, "start timed out\n"); + goto disable_cx_supply; + } + + return 0; + +disable_cx_supply: + regulator_disable(wcss->cx_supply); +disable_xo_clk: + clk_disable_unprepare(wcss->xo); + + return ret; +} + static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss, struct regmap *halt_map, u32 offset) @@ -278,6 +526,70 @@ static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss, regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0); } +static int q6v5_qcs404_wcss_shutdown(struct q6v5_wcss *wcss) +{ + unsigned long val; + int ret; + + q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss); + + /* assert clamps to avoid MX current inrush */ + val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG); + val |= (Q6SS_CLAMP_IO | Q6SS_CLAMP_WL | Q6SS_CLAMP_QMC_MEM); + writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG); + + /* Disable memories by turning off memory foot/headswitch */ + writel((readl(wcss->reg_base + Q6SS_MEM_PWR_CTL) & + ~QDSS_Q6_MEMORIES), + wcss->reg_base + Q6SS_MEM_PWR_CTL); + + /* Clear the BHS_ON bit */ + val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG); + val &= ~Q6SS_BHS_ON; + writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG); + + clk_disable_unprepare(wcss->ahbfabric_cbcr_clk); + clk_disable_unprepare(wcss->lcc_csr_cbcr); + clk_disable_unprepare(wcss->tcm_slave_cbcr); + clk_disable_unprepare(wcss->qdsp6ss_abhm_cbcr); + clk_disable_unprepare(wcss->qdsp6ss_axim_cbcr); + + val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR); + val &= ~BIT(0); + writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR); + + val = readl(wcss->reg_base + Q6SS_XO_CBCR); + val &= ~BIT(0); + writel(val, wcss->reg_base + Q6SS_XO_CBCR); + + clk_disable_unprepare(wcss->ahbs_cbcr); + clk_disable_unprepare(wcss->lcc_bcr_sleep); + + val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG); + val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC); + writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG); + + clk_disable_unprepare(wcss->gcc_abhs_cbcr); + + ret = reset_control_assert(wcss->wcss_reset); + if (ret) { + dev_err(wcss->dev, "wcss_reset failed\n"); + return ret; + } + usleep_range(200, 300); + + ret = reset_control_deassert(wcss->wcss_reset); + if (ret) { + dev_err(wcss->dev, "wcss_reset failed\n"); + return ret; + } + usleep_range(200, 300); + + clk_disable_unprepare(wcss->gcc_axim_cbcr); + + return 0; +} + static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss) { int ret; @@ -397,20 +709,28 @@ static int q6v5_wcss_stop(struct rproc *rproc) int ret; /* WCSS powerdown */ - ret = qcom_q6v5_request_stop(&wcss->q6v5, NULL); - if (ret == -ETIMEDOUT) { - dev_err(wcss->dev, "timed out on wait\n"); - return ret; + if (wcss->requires_force_stop) { + ret = qcom_q6v5_request_stop(&wcss->q6v5, NULL); + if (ret == -ETIMEDOUT) { + dev_err(wcss->dev, "timed out on wait\n"); + return ret; + } } - ret = q6v5_wcss_powerdown(wcss); - if (ret) - return ret; - - /* Q6 Power down */ - ret = q6v5_q6_powerdown(wcss); - if (ret) - return ret; + if (wcss->version == WCSS_QCS404) { + ret = q6v5_qcs404_wcss_shutdown(wcss); + if (ret) + return ret; + } else { + ret = q6v5_wcss_powerdown(wcss); + if (ret) + return ret; + + /* Q6 Power down */ + ret = q6v5_q6_powerdown(wcss); + if (ret) + return ret; + } qcom_q6v5_unprepare(&wcss->q6v5); @@ -453,14 +773,26 @@ static const struct rproc_ops q6v5_wcss_ipq8074_ops = { .get_boot_addr = rproc_elf_get_boot_addr, }; -static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss) +static const struct rproc_ops q6v5_wcss_qcs404_ops = { + .start = q6v5_qcs404_wcss_start, + .stop = q6v5_wcss_stop, + .da_to_va = q6v5_wcss_da_to_va, + .load = q6v5_wcss_load, + .get_boot_addr = rproc_elf_get_boot_addr, + .parse_fw = qcom_register_dump_segments, +}; + +static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss, + const struct wcss_data *desc) { struct device *dev = wcss->dev; - wcss->wcss_aon_reset = devm_reset_control_get(dev, "wcss_aon_reset"); - if (IS_ERR(wcss->wcss_aon_reset)) { - dev_err(wcss->dev, "unable to acquire wcss_aon_reset\n"); - return PTR_ERR(wcss->wcss_aon_reset); + if (desc->aon_reset_required) { + wcss->wcss_aon_reset = devm_reset_control_get(dev, "wcss_aon_reset"); + if (IS_ERR(wcss->wcss_aon_reset)) { + dev_err(wcss->dev, "fail to acquire wcss_aon_reset\n"); + return PTR_ERR(wcss->wcss_aon_reset); + } } wcss->wcss_reset = devm_reset_control_get(dev, "wcss_reset"); @@ -469,10 +801,18 @@ static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss) return PTR_ERR(wcss->wcss_reset); } - wcss->wcss_q6_reset = devm_reset_control_get(dev, "wcss_q6_reset"); - if (IS_ERR(wcss->wcss_q6_reset)) { - dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n"); - return PTR_ERR(wcss->wcss_q6_reset); + if (desc->wcss_q6_reset_required) { + wcss->wcss_q6_reset = devm_reset_control_get(dev, "wcss_q6_reset"); + if (IS_ERR(wcss->wcss_q6_reset)) { + dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n"); + return PTR_ERR(wcss->wcss_q6_reset); + } + } + + wcss->wcss_q6_bcr_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_bcr_reset"); + if (IS_ERR(wcss->wcss_q6_bcr_reset)) { + dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n"); + return PTR_ERR(wcss->wcss_q6_bcr_reset); } return 0; @@ -481,35 +821,48 @@ static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss) static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss, struct platform_device *pdev) { - struct of_phandle_args args; + unsigned int halt_reg[MAX_HALT_REG] = {0}; + struct device_node *syscon; struct resource *res; int ret; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6"); - wcss->reg_base = devm_ioremap_resource(&pdev->dev, res); + wcss->reg_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); if (IS_ERR(wcss->reg_base)) return PTR_ERR(wcss->reg_base); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb"); - wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(wcss->rmb_base)) - return PTR_ERR(wcss->rmb_base); + if (wcss->version == WCSS_IPQ8074) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb"); + wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(wcss->rmb_base)) + return PTR_ERR(wcss->rmb_base); + } - ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, - "qcom,halt-regs", 3, 0, &args); - if (ret < 0) { + syscon = of_parse_phandle(pdev->dev.of_node, + "qcom,halt-regs", 0); + if (!syscon) { dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n"); return -EINVAL; } - wcss->halt_map = syscon_node_to_regmap(args.np); - of_node_put(args.np); + wcss->halt_map = syscon_node_to_regmap(syscon); + of_node_put(syscon); if (IS_ERR(wcss->halt_map)) return PTR_ERR(wcss->halt_map); - wcss->halt_q6 = args.args[0]; - wcss->halt_wcss = args.args[1]; - wcss->halt_nc = args.args[2]; + ret = of_property_read_variable_u32_array(pdev->dev.of_node, + "qcom,halt-regs", + halt_reg, 0, + MAX_HALT_REG); + if (ret < 0) { + dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n"); + return -EINVAL; + } + + wcss->halt_q6 = halt_reg[0]; + wcss->halt_wcss = halt_reg[1]; + wcss->halt_nc = halt_reg[2]; return 0; } @@ -543,6 +896,107 @@ static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss) return 0; } +static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) +{ + int ret; + + wcss->xo = devm_clk_get(wcss->dev, "xo"); + if (IS_ERR(wcss->xo)) { + ret = PTR_ERR(wcss->xo); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get xo clock"); + return ret; + } + + wcss->gcc_abhs_cbcr = devm_clk_get(wcss->dev, "gcc_abhs_cbcr"); + if (IS_ERR(wcss->gcc_abhs_cbcr)) { + ret = PTR_ERR(wcss->gcc_abhs_cbcr); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get gcc abhs clock"); + return PTR_ERR(wcss->gcc_abhs_cbcr); + } + + wcss->gcc_axim_cbcr = devm_clk_get(wcss->dev, "gcc_axim_cbcr"); + if (IS_ERR(wcss->gcc_axim_cbcr)) { + ret = PTR_ERR(wcss->gcc_axim_cbcr); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get gcc axim clock\n"); + return PTR_ERR(wcss->gcc_axim_cbcr); + } + + wcss->ahbfabric_cbcr_clk = devm_clk_get(wcss->dev, + "lcc_ahbfabric_cbc"); + if (IS_ERR(wcss->ahbfabric_cbcr_clk)) { + ret = PTR_ERR(wcss->ahbfabric_cbcr_clk); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get ahbfabric clock\n"); + return PTR_ERR(wcss->ahbfabric_cbcr_clk); + } + + wcss->lcc_csr_cbcr = devm_clk_get(wcss->dev, "tcsr_lcc_cbc"); + if (IS_ERR(wcss->lcc_csr_cbcr)) { + ret = PTR_ERR(wcss->lcc_csr_cbcr); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get csr cbcr clk\n"); + return PTR_ERR(wcss->lcc_csr_cbcr); + } + + wcss->ahbs_cbcr = devm_clk_get(wcss->dev, + "lcc_abhs_cbc"); + if (IS_ERR(wcss->ahbs_cbcr)) { + ret = PTR_ERR(wcss->ahbs_cbcr); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get ahbs_cbcr clk\n"); + return PTR_ERR(wcss->ahbs_cbcr); + } + + wcss->tcm_slave_cbcr = devm_clk_get(wcss->dev, + "lcc_tcm_slave_cbc"); + if (IS_ERR(wcss->tcm_slave_cbcr)) { + ret = PTR_ERR(wcss->tcm_slave_cbcr); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get tcm cbcr clk\n"); + return PTR_ERR(wcss->tcm_slave_cbcr); + } + + wcss->qdsp6ss_abhm_cbcr = devm_clk_get(wcss->dev, "lcc_abhm_cbc"); + if (IS_ERR(wcss->qdsp6ss_abhm_cbcr)) { + ret = PTR_ERR(wcss->qdsp6ss_abhm_cbcr); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get abhm cbcr clk\n"); + return PTR_ERR(wcss->qdsp6ss_abhm_cbcr); + } + + wcss->qdsp6ss_axim_cbcr = devm_clk_get(wcss->dev, "lcc_axim_cbc"); + if (IS_ERR(wcss->qdsp6ss_axim_cbcr)) { + ret = PTR_ERR(wcss->qdsp6ss_axim_cbcr); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get axim cbcr clk\n"); + return PTR_ERR(wcss->qdsp6ss_abhm_cbcr); + } + + wcss->lcc_bcr_sleep = devm_clk_get(wcss->dev, "lcc_bcr_sleep"); + if (IS_ERR(wcss->lcc_bcr_sleep)) { + ret = PTR_ERR(wcss->lcc_bcr_sleep); + if (ret != -EPROBE_DEFER) + dev_err(wcss->dev, "failed to get bcr cbcr clk\n"); + return PTR_ERR(wcss->lcc_bcr_sleep); + } + + return 0; +} + +static int q6v5_wcss_init_regulator(struct q6v5_wcss *wcss) +{ + wcss->cx_supply = devm_regulator_get(wcss->dev, "cx"); + if (IS_ERR(wcss->cx_supply)) + return PTR_ERR(wcss->cx_supply); + + regulator_set_load(wcss->cx_supply, 100000); + + return 0; +} + static int q6v5_wcss_probe(struct platform_device *pdev) { const struct wcss_data *desc; @@ -554,7 +1008,7 @@ static int q6v5_wcss_probe(struct platform_device *pdev) if (!desc) return -EINVAL; - rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_wcss_ipq8074_ops, + rproc = rproc_alloc(&pdev->dev, pdev->name, desc->ops, desc->firmware_name, sizeof(*wcss)); if (!rproc) { dev_err(&pdev->dev, "failed to allocate rproc\n"); @@ -563,7 +1017,10 @@ static int q6v5_wcss_probe(struct platform_device *pdev) wcss = rproc->priv; wcss->dev = &pdev->dev; - wcss->crash_reason_smem = desc->crash_reason_smem; + wcss->version = desc->version; + + wcss->version = desc->version; + wcss->requires_force_stop = desc->requires_force_stop; ret = q6v5_wcss_init_mmio(wcss, pdev); if (ret) @@ -573,7 +1030,17 @@ static int q6v5_wcss_probe(struct platform_device *pdev) if (ret) goto free_rproc; - ret = q6v5_wcss_init_reset(wcss); + if (wcss->version == WCSS_QCS404) { + ret = q6v5_wcss_init_clock(wcss); + if (ret) + goto free_rproc; + + ret = q6v5_wcss_init_regulator(wcss); + if (ret) + goto free_rproc; + } + + ret = q6v5_wcss_init_reset(wcss, desc); if (ret) goto free_rproc; @@ -585,6 +1052,11 @@ static int q6v5_wcss_probe(struct platform_device *pdev) qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss"); qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss"); + if (desc->ssctl_id) + wcss->sysmon = qcom_add_sysmon_subdev(rproc, + desc->sysmon_name, + desc->ssctl_id); + ret = rproc_add(rproc); if (ret) goto free_rproc; @@ -612,10 +1084,28 @@ static int q6v5_wcss_remove(struct platform_device *pdev) static const struct wcss_data wcss_ipq8074_res_init = { .firmware_name = "IPQ8074/q6_fw.mdt", .crash_reason_smem = WCSS_CRASH_REASON, + .aon_reset_required = true, + .wcss_q6_reset_required = true, + .ops = &q6v5_wcss_ipq8074_ops, + .requires_force_stop = true, +}; + +static const struct wcss_data wcss_qcs404_res_init = { + .crash_reason_smem = WCSS_CRASH_REASON, + .firmware_name = "wcnss.mdt", + .version = WCSS_QCS404, + .aon_reset_required = false, + .wcss_q6_reset_required = false, + .ssr_name = "mpss", + .sysmon_name = "wcnss", + .ssctl_id = 0x12, + .ops = &q6v5_wcss_qcs404_ops, + .requires_force_stop = false, }; static const struct of_device_id q6v5_wcss_of_match[] = { { .compatible = "qcom,ipq8074-wcss-pil", .data = &wcss_ipq8074_res_init }, + { .compatible = "qcom,qcs404-wcss-pil", .data = &wcss_qcs404_res_init }, { }, }; MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match); -- cgit v1.2.3 From bb91c9ee518cd7353f2301f4bd6b65ea42a750d4 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 29 Jan 2021 00:18:15 +0530 Subject: remoteproc: qcom: wcss: explicitly request exclusive reset control Use request exclusive reset control for wcss reset controls. Signed-off-by: Govind Singh Signed-off-by: Gokul Sriram Palanisamy Link: https://lore.kernel.org/r/1611859695-11824-5-git-send-email-gokulsri@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_wcss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index d67264c93996..71ec1a451e35 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -788,21 +788,21 @@ static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss, struct device *dev = wcss->dev; if (desc->aon_reset_required) { - wcss->wcss_aon_reset = devm_reset_control_get(dev, "wcss_aon_reset"); + wcss->wcss_aon_reset = devm_reset_control_get_exclusive(dev, "wcss_aon_reset"); if (IS_ERR(wcss->wcss_aon_reset)) { dev_err(wcss->dev, "fail to acquire wcss_aon_reset\n"); return PTR_ERR(wcss->wcss_aon_reset); } } - wcss->wcss_reset = devm_reset_control_get(dev, "wcss_reset"); + wcss->wcss_reset = devm_reset_control_get_exclusive(dev, "wcss_reset"); if (IS_ERR(wcss->wcss_reset)) { dev_err(wcss->dev, "unable to acquire wcss_reset\n"); return PTR_ERR(wcss->wcss_reset); } if (desc->wcss_q6_reset_required) { - wcss->wcss_q6_reset = devm_reset_control_get(dev, "wcss_q6_reset"); + wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset"); if (IS_ERR(wcss->wcss_q6_reset)) { dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n"); return PTR_ERR(wcss->wcss_q6_reset); -- cgit v1.2.3 From 48073935b9a4f820733937bd40a74c1c389caee6 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 11 Mar 2021 16:24:41 -0800 Subject: remoteproc: qcom: wcnss: Allow specifying firmware-name Introduce a firmware-name property, in order to be able to support device/platform specific firmware for the wireless connectivity subsystem; in line with other Qualcomm remoteproc drivers. Acked-by: Mathieu Poirier Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210312002441.3273183-1-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_wcnss.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 3a131163064c..5f3455aa7e0e 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -530,6 +530,7 @@ static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss) static int wcnss_probe(struct platform_device *pdev) { + const char *fw_name = WCNSS_FIRMWARE_NAME; const struct wcnss_data *data; struct qcom_wcnss *wcnss; struct resource *res; @@ -547,8 +548,13 @@ static int wcnss_probe(struct platform_device *pdev) return -ENXIO; } + ret = of_property_read_string(pdev->dev.of_node, "firmware-name", + &fw_name); + if (ret < 0 && ret != -EINVAL) + return ret; + rproc = rproc_alloc(&pdev->dev, pdev->name, &wcnss_ops, - WCNSS_FIRMWARE_NAME, sizeof(*wcnss)); + fw_name, sizeof(*wcnss)); if (!rproc) { dev_err(&pdev->dev, "unable to allocate remoteproc\n"); return -ENOMEM; -- cgit v1.2.3 From 6d1f2803cb6b414c2e45fa64d1fdad6b581e1e88 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 7 Apr 2021 10:56:39 -0500 Subject: remoteproc: pru: Fixup interrupt-parent logic for fw events The PRU firmware interrupt mapping logic in pru_handle_intrmap() uses of_irq_find_parent() with PRU device node to get a handle to the PRUSS Interrupt Controller at present. This logic however requires that the PRU nodes always define a interrupt-parent property. This property is neither a required/defined property as per the PRU remoteproc binding, nor is relevant from a DT node point of view without any associated interrupts. The current logic finds a wrong interrupt controller and fails to perform proper mapping without any interrupt-parent property in the PRU nodes. Fix this logic to always find and use the sibling interrupt controller. Also, while at this, fix the acquired interrupt controller device node reference properly. Fixes: c75c9fdac66e ("remoteproc: pru: Add support for PRU specific interrupt configuration") Signed-off-by: Suman Anna Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210407155641.5501-2-s-anna@ti.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/pru_rproc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index d6086f90e809..b8b3c1921fe6 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -284,7 +284,7 @@ static int pru_handle_intrmap(struct rproc *rproc) struct pru_rproc *pru = rproc->priv; struct pru_irq_rsc *rsc = pru->pru_interrupt_map; struct irq_fwspec fwspec; - struct device_node *irq_parent; + struct device_node *parent, *irq_parent; int i, ret = 0; /* not having pru_interrupt_map is not an error */ @@ -312,9 +312,16 @@ static int pru_handle_intrmap(struct rproc *rproc) /* * parse and fill in system event to interrupt channel and - * channel-to-host mapping + * channel-to-host mapping. The interrupt controller to be used + * for these mappings for a given PRU remoteproc is always its + * corresponding sibling PRUSS INTC node. */ - irq_parent = of_irq_find_parent(pru->dev->of_node); + parent = of_get_parent(dev_of_node(pru->dev)); + if (!parent) + return -ENODEV; + + irq_parent = of_get_child_by_name(parent, "interrupt-controller"); + of_node_put(parent); if (!irq_parent) { kfree(pru->mapped_irq); return -ENODEV; @@ -337,11 +344,13 @@ static int pru_handle_intrmap(struct rproc *rproc) goto map_fail; } } + of_node_put(irq_parent); return ret; map_fail: pru_dispose_irq_mapping(pru); + of_node_put(irq_parent); return ret; } -- cgit v1.2.3 From 1fe72bcfac087dba5ab52778e0646ed9e145cd32 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 7 Apr 2021 10:56:40 -0500 Subject: remoteproc: pru: Fix wrong success return value for fw events The irq_create_fwspec_mapping() returns a proper virq value on success and 0 upon any failure. The pru_handle_intrmap() treats this as an error and disposes all firmware event mappings correctly, but is returning this incorrect value as is, letting the pru_rproc_start() interpret it as a success and boot the PRU. Fix this by returning an error value back upon any such failure. While at this, revise the error trace to print some meaningful info about the failed event. Fixes: c75c9fdac66e ("remoteproc: pru: Add support for PRU specific interrupt configuration") Signed-off-by: Suman Anna Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210407155641.5501-3-s-anna@ti.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/pru_rproc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index b8b3c1921fe6..ac6348cc094f 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -339,8 +339,10 @@ static int pru_handle_intrmap(struct rproc *rproc) pru->mapped_irq[i] = irq_create_fwspec_mapping(&fwspec); if (!pru->mapped_irq[i]) { - dev_err(dev, "failed to get virq\n"); - ret = pru->mapped_irq[i]; + dev_err(dev, "failed to get virq for fw mapping %d: event %d chnl %d host %d\n", + i, fwspec.param[0], fwspec.param[1], + fwspec.param[2]); + ret = -EINVAL; goto map_fail; } } -- cgit v1.2.3 From 880a66e026fbe6a17cd59fe0ee942bbad62a6c26 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 7 Apr 2021 10:56:41 -0500 Subject: remoteproc: pru: Fix and cleanup firmware interrupt mapping logic The PRU firmware interrupt mappings are configured and unconfigured in .start() and .stop() callbacks respectively using the variables 'evt_count' and a 'mapped_irq' pointer. These variables are modified only during these callbacks but are not re-initialized/reset properly during unwind or failure paths. These stale values caused a kernel crash while stopping a PRU remoteproc running a different firmware with no events on a subsequent run after a previous run that was running a firmware with events. Fix this crash by ensuring that the evt_count is 0 and the mapped_irq pointer is set to NULL in pru_dispose_irq_mapping(). Also, reset these variables properly during any failures in the .start() callback. While at this, the pru_dispose_irq_mapping() callsites are all made to look the same, moving any conditional logic to inside the function. Reviewed-by: Mathieu Poirier Fixes: c75c9fdac66e ("remoteproc: pru: Add support for PRU specific interrupt configuration") Reported-by: Vignesh Raghavendra Signed-off-by: Suman Anna Link: https://lore.kernel.org/r/20210407155641.5501-4-s-anna@ti.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/pru_rproc.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index ac6348cc094f..b13ff4283232 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -266,12 +266,17 @@ static void pru_rproc_create_debug_entries(struct rproc *rproc) static void pru_dispose_irq_mapping(struct pru_rproc *pru) { - while (pru->evt_count--) { + if (!pru->mapped_irq) + return; + + while (pru->evt_count) { + pru->evt_count--; if (pru->mapped_irq[pru->evt_count] > 0) irq_dispose_mapping(pru->mapped_irq[pru->evt_count]); } kfree(pru->mapped_irq); + pru->mapped_irq = NULL; } /* @@ -307,8 +312,10 @@ static int pru_handle_intrmap(struct rproc *rproc) pru->evt_count = rsc->num_evts; pru->mapped_irq = kcalloc(pru->evt_count, sizeof(unsigned int), GFP_KERNEL); - if (!pru->mapped_irq) + if (!pru->mapped_irq) { + pru->evt_count = 0; return -ENOMEM; + } /* * parse and fill in system event to interrupt channel and @@ -317,13 +324,19 @@ static int pru_handle_intrmap(struct rproc *rproc) * corresponding sibling PRUSS INTC node. */ parent = of_get_parent(dev_of_node(pru->dev)); - if (!parent) + if (!parent) { + kfree(pru->mapped_irq); + pru->mapped_irq = NULL; + pru->evt_count = 0; return -ENODEV; + } irq_parent = of_get_child_by_name(parent, "interrupt-controller"); of_node_put(parent); if (!irq_parent) { kfree(pru->mapped_irq); + pru->mapped_irq = NULL; + pru->evt_count = 0; return -ENODEV; } @@ -398,8 +411,7 @@ static int pru_rproc_stop(struct rproc *rproc) pru_control_write_reg(pru, PRU_CTRL_CTRL, val); /* dispose irq mapping - new firmware can provide new mapping */ - if (pru->mapped_irq) - pru_dispose_irq_mapping(pru); + pru_dispose_irq_mapping(pru); return 0; } -- cgit v1.2.3 From 859fd2418b4ba00bba56263b8abc7f54f4a7260f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 19 Mar 2021 09:41:00 +0000 Subject: remoteproc: qcom: wcss: Fix return value check in q6v5_wcss_init_mmio() In case of error, the function devm_ioremap() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Fixes: 0af65b9b915e ("remoteproc: qcom: wcss: Add non pas wcss Q6 support for QCS404") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20210319094100.4185044-1-weiyongjun1@huawei.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_wcss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index 71ec1a451e35..6f7d940d4431 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -829,8 +829,8 @@ static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss, res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6"); wcss->reg_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (IS_ERR(wcss->reg_base)) - return PTR_ERR(wcss->reg_base); + if (!wcss->reg_base) + return -ENOMEM; if (wcss->version == WCSS_IPQ8074) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb"); -- cgit v1.2.3 From 3fdba9d27cc68a4d561da80bfecd4f73239b9a86 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 8 Apr 2021 22:42:11 +0530 Subject: remoteproc: qcom: pas: Add modem support for SDX55 Add remoteproc support for Hexagon modem found on the Qualcomm SDX55 platform. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210408171211.92141-1-manivannan.sadhasivam@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index ef85b5511dc9..b921fc26cd04 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -785,6 +785,22 @@ static const struct adsp_data wcss_resource_init = { .ssctl_id = 0x12, }; +static const struct adsp_data sdx55_mpss_resource = { + .crash_reason_smem = 421, + .firmware_name = "modem.mdt", + .pas_id = 4, + .has_aggre2_clk = false, + .auto_boot = true, + .proxy_pd_names = (char*[]){ + "cx", + "mss", + NULL + }, + .ssr_name = "mpss", + .sysmon_name = "modem", + .ssctl_id = 0x22, +}; + static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init}, { .compatible = "qcom,msm8996-adsp-pil", .data = &adsp_resource_init}, @@ -797,6 +813,7 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init}, { .compatible = "qcom,sdm845-adsp-pas", .data = &adsp_resource_init}, { .compatible = "qcom,sdm845-cdsp-pas", .data = &cdsp_resource_init}, + { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource}, { .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource}, { .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource}, { .compatible = "qcom,sm8150-mpss-pas", .data = &mpss_resource_init}, -- cgit v1.2.3 From ca0e89406ba18e9ba98d28413b50469f631bb583 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 26 Mar 2021 02:47:41 +0000 Subject: remoteproc: qcom: wcss: Fix wrong pointer passed to PTR_ERR() PTR_ERR should access the value just tested by IS_ERR, otherwise the wrong error code will be returned. This commit fix it by return 'ret' directly. Reviewed-by: Dan Carpenter Fixes: 0af65b9b915e ("remoteproc: qcom: wcss: Add non pas wcss Q6 support for QCS404") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20210326024741.841267-1-weiyongjun1@huawei.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_wcss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index 6f7d940d4431..eab911dabb0b 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -972,7 +972,7 @@ static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) ret = PTR_ERR(wcss->qdsp6ss_axim_cbcr); if (ret != -EPROBE_DEFER) dev_err(wcss->dev, "failed to get axim cbcr clk\n"); - return PTR_ERR(wcss->qdsp6ss_abhm_cbcr); + return ret; } wcss->lcc_bcr_sleep = devm_clk_get(wcss->dev, "lcc_bcr_sleep"); -- cgit v1.2.3 From 6353da47ee0082286e4d4a7dc4b38d4ee5ea4cb4 Mon Sep 17 00:00:00 2001 From: Junlin Yang Date: Thu, 8 Apr 2021 22:33:22 +0800 Subject: remoteproc: qcom: wcss: Remove unnecessary PTR_ERR() Remove unnecessary PTR_ERR(), it has been assigned to ret before, so return ret directly. Signed-off-by: Junlin Yang Link: https://lore.kernel.org/r/20210408143322.1647-1-angkery@163.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_wcss.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index eab911dabb0b..20d50ec7eff1 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -913,7 +913,7 @@ static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) ret = PTR_ERR(wcss->gcc_abhs_cbcr); if (ret != -EPROBE_DEFER) dev_err(wcss->dev, "failed to get gcc abhs clock"); - return PTR_ERR(wcss->gcc_abhs_cbcr); + return ret; } wcss->gcc_axim_cbcr = devm_clk_get(wcss->dev, "gcc_axim_cbcr"); @@ -921,7 +921,7 @@ static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) ret = PTR_ERR(wcss->gcc_axim_cbcr); if (ret != -EPROBE_DEFER) dev_err(wcss->dev, "failed to get gcc axim clock\n"); - return PTR_ERR(wcss->gcc_axim_cbcr); + return ret; } wcss->ahbfabric_cbcr_clk = devm_clk_get(wcss->dev, @@ -930,7 +930,7 @@ static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) ret = PTR_ERR(wcss->ahbfabric_cbcr_clk); if (ret != -EPROBE_DEFER) dev_err(wcss->dev, "failed to get ahbfabric clock\n"); - return PTR_ERR(wcss->ahbfabric_cbcr_clk); + return ret; } wcss->lcc_csr_cbcr = devm_clk_get(wcss->dev, "tcsr_lcc_cbc"); @@ -938,7 +938,7 @@ static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) ret = PTR_ERR(wcss->lcc_csr_cbcr); if (ret != -EPROBE_DEFER) dev_err(wcss->dev, "failed to get csr cbcr clk\n"); - return PTR_ERR(wcss->lcc_csr_cbcr); + return ret; } wcss->ahbs_cbcr = devm_clk_get(wcss->dev, @@ -947,7 +947,7 @@ static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) ret = PTR_ERR(wcss->ahbs_cbcr); if (ret != -EPROBE_DEFER) dev_err(wcss->dev, "failed to get ahbs_cbcr clk\n"); - return PTR_ERR(wcss->ahbs_cbcr); + return ret; } wcss->tcm_slave_cbcr = devm_clk_get(wcss->dev, @@ -956,7 +956,7 @@ static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) ret = PTR_ERR(wcss->tcm_slave_cbcr); if (ret != -EPROBE_DEFER) dev_err(wcss->dev, "failed to get tcm cbcr clk\n"); - return PTR_ERR(wcss->tcm_slave_cbcr); + return ret; } wcss->qdsp6ss_abhm_cbcr = devm_clk_get(wcss->dev, "lcc_abhm_cbc"); @@ -964,7 +964,7 @@ static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) ret = PTR_ERR(wcss->qdsp6ss_abhm_cbcr); if (ret != -EPROBE_DEFER) dev_err(wcss->dev, "failed to get abhm cbcr clk\n"); - return PTR_ERR(wcss->qdsp6ss_abhm_cbcr); + return ret; } wcss->qdsp6ss_axim_cbcr = devm_clk_get(wcss->dev, "lcc_axim_cbc"); @@ -980,7 +980,7 @@ static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) ret = PTR_ERR(wcss->lcc_bcr_sleep); if (ret != -EPROBE_DEFER) dev_err(wcss->dev, "failed to get bcr cbcr clk\n"); - return PTR_ERR(wcss->lcc_bcr_sleep); + return ret; } return 0; -- cgit v1.2.3 From 889cb0d43d18ed348971e49378ed6a63e3a4745e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 31 Mar 2021 12:27:09 +0000 Subject: remoteproc: imx_rproc: fix build error without CONFIG_MAILBOX Fix build error when CONFIG_MAILBOX is not set: arm-linux-gnueabi-ld: drivers/remoteproc/imx_rproc.o: in function `imx_rproc_kick': imx_rproc.c:(.text+0x328): undefined reference to `mbox_send_message' arm-linux-gnueabi-ld: drivers/remoteproc/imx_rproc.o: in function `imx_rproc_probe': imx_rproc.c:(.text+0x52c): undefined reference to `mbox_request_channel_byname' arm-linux-gnueabi-ld: imx_rproc.c:(.text+0x548): undefined reference to `mbox_request_channel_byname' arm-linux-gnueabi-ld: imx_rproc.c:(.text+0x76c): undefined reference to `mbox_free_channel' arm-linux-gnueabi-ld: imx_rproc.c:(.text+0x774): undefined reference to `mbox_free_channel' arm-linux-gnueabi-ld: imx_rproc.c:(.text+0x7c4): undefined reference to `mbox_free_channel' arm-linux-gnueabi-ld: drivers/remoteproc/imx_rproc.o: in function `imx_rproc_remove': imx_rproc.c:(.text+0x86c): undefined reference to `mbox_free_channel' arm-linux-gnueabi-ld: imx_rproc.c:(.text+0x874): undefined reference to `mbox_free_channel' make: *** [Makefile:1292: vmlinux] Error 1 Reviewed-by: Mathieu Poirier Fixes: 2df7062002d0 ("remoteproc: imx_proc: enable virtio/mailbox") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20210331122709.3935521-1-weiyongjun1@huawei.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 7cf3d1b40c55..e68fcedc999c 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -26,6 +26,7 @@ config REMOTEPROC_CDEV config IMX_REMOTEPROC tristate "i.MX remoteproc support" depends on ARCH_MXC + select MAILBOX help Say y here to support iMX's remote processors via the remote processor framework. -- cgit v1.2.3 From 6e962bfe56b99843ab716dc8a9438039476c99e2 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 8 Apr 2021 09:44:46 +0800 Subject: remoteproc: imx_rproc: add missing of_node_put After of_parse_phandle, we need of_node_put to decrease the refcount of the device_node. Reported-by: Mathieu Poirier Signed-off-by: Peng Fan Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/1617846289-13496-2-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 6d3207ccbaef..077413319f58 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -459,6 +459,8 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, return err; } + of_node_put(node); + if (b >= IMX7D_RPROC_MEM_MAX) break; -- cgit v1.2.3 From f638a19775ae60ae919ff604fdc04362ff4f817f Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 8 Apr 2021 09:44:47 +0800 Subject: remoteproc: imx_rproc: enlarge IMX7D_RPROC_MEM_MAX 8 is not enough when we need more, such as resource table for remote cores that booted before Linux Kernel, so enlarge IMX7D_RPROC_MEM_MAX to 32. And also rename it to IMX_RPROC_MEM_MAX which make more sense. Signed-off-by: Peng Fan Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/1617846289-13496-3-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 077413319f58..b05aae0ad7a2 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -48,7 +48,7 @@ | IMX6SX_SW_M4C_NON_SCLR_RST \ | IMX6SX_SW_M4C_RST) -#define IMX7D_RPROC_MEM_MAX 8 +#define IMX_RPROC_MEM_MAX 32 /** * struct imx_rproc_mem - slim internal memory structure @@ -88,7 +88,7 @@ struct imx_rproc { struct regmap *regmap; struct rproc *rproc; const struct imx_rproc_dcfg *dcfg; - struct imx_rproc_mem mem[IMX7D_RPROC_MEM_MAX]; + struct imx_rproc_mem mem[IMX_RPROC_MEM_MAX]; struct clk *clk; struct mbox_client cl; struct mbox_chan *tx_ch; @@ -272,7 +272,7 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *i if (imx_rproc_da_to_sys(priv, da, len, &sys)) return NULL; - for (i = 0; i < IMX7D_RPROC_MEM_MAX; i++) { + for (i = 0; i < IMX_RPROC_MEM_MAX; i++) { if (sys >= priv->mem[i].sys_addr && sys + len < priv->mem[i].sys_addr + priv->mem[i].size) { unsigned int offset = sys - priv->mem[i].sys_addr; @@ -425,7 +425,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, if (!(att->flags & ATT_OWN)) continue; - if (b >= IMX7D_RPROC_MEM_MAX) + if (b >= IMX_RPROC_MEM_MAX) break; priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev, @@ -461,7 +461,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, of_node_put(node); - if (b >= IMX7D_RPROC_MEM_MAX) + if (b >= IMX_RPROC_MEM_MAX) break; /* Not use resource version, because we might share region */ -- cgit v1.2.3 From 10a3d4079eaea06472f1981152e2840e7232ffa9 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 8 Apr 2021 09:44:48 +0800 Subject: remoteproc: imx_rproc: move memory parsing to rproc_ops Use the rproc_ops::prepare() hook for doing memory resources reallocation when reattaching a remote procesor. Suggested-by: Mathieu Poirier Reviewed-by: Mathieu Poirier Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/1617846289-13496-4-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index b05aae0ad7a2..7cd09971d1a4 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -317,7 +317,7 @@ static int imx_rproc_mem_release(struct rproc *rproc, return 0; } -static int imx_rproc_parse_memory_regions(struct rproc *rproc) +static int imx_rproc_prepare(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; struct device_node *np = priv->dev->of_node; @@ -363,10 +363,7 @@ static int imx_rproc_parse_memory_regions(struct rproc *rproc) static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) { - int ret = imx_rproc_parse_memory_regions(rproc); - - if (ret) - return ret; + int ret; ret = rproc_elf_load_rsc_table(rproc, fw); if (ret) @@ -399,6 +396,7 @@ static void imx_rproc_kick(struct rproc *rproc, int vqid) } static const struct rproc_ops imx_rproc_ops = { + .prepare = imx_rproc_prepare, .start = imx_rproc_start, .stop = imx_rproc_stop, .kick = imx_rproc_kick, -- cgit v1.2.3 From 5e4c1243071d29ed5511121d044116b942ba6a7b Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 8 Apr 2021 09:44:49 +0800 Subject: remoteproc: imx_rproc: support remote cores booted before Linux Kernel - When remote cores are kicked before Linux Kernel, we are not able to get resource table from the firmware elf file, so we need to add rsc_table to hold the resource table published by remote cores and imx_rproc_get_loaded_rsc_table is to get the resource table. - Per remoteproc framework, add attach hook for processor in a detached state. - Add imx_rproc_detect_mode to detect remote cores' working mode to set the state which is required by remoteproc framework. Reviewed-by: Mathieu Poirier Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/1617846289-13496-5-git-send-email-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 7cd09971d1a4..d6338872c6db 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -95,6 +95,7 @@ struct imx_rproc { struct mbox_chan *rx_ch; struct work_struct rproc_work; struct workqueue_struct *workqueue; + void __iomem *rsc_table; }; static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { @@ -395,8 +396,26 @@ static void imx_rproc_kick(struct rproc *rproc, int vqid) __func__, vqid, err); } +static int imx_rproc_attach(struct rproc *rproc) +{ + return 0; +} + +static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz) +{ + struct imx_rproc *priv = rproc->priv; + + /* The resource table has already been mapped in imx_rproc_addr_init */ + if (!priv->rsc_table) + return NULL; + + *table_sz = SZ_1K; + return (struct resource_table *)priv->rsc_table; +} + static const struct rproc_ops imx_rproc_ops = { .prepare = imx_rproc_prepare, + .attach = imx_rproc_attach, .start = imx_rproc_start, .stop = imx_rproc_stop, .kick = imx_rproc_kick, @@ -404,6 +423,7 @@ static const struct rproc_ops imx_rproc_ops = { .load = rproc_elf_load_segments, .parse_fw = imx_rproc_parse_fw, .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, }; @@ -470,6 +490,8 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, } priv->mem[b].sys_addr = res.start; priv->mem[b].size = resource_size(&res); + if (!strcmp(node->name, "rsc_table")) + priv->rsc_table = priv->mem[b].cpu_addr; b++; } @@ -536,6 +558,25 @@ static void imx_rproc_free_mbox(struct rproc *rproc) mbox_free_channel(priv->rx_ch); } +static int imx_rproc_detect_mode(struct imx_rproc *priv) +{ + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device *dev = priv->dev; + int ret; + u32 val; + + ret = regmap_read(priv->regmap, dcfg->src_reg, &val); + if (ret) { + dev_err(dev, "Failed to read src\n"); + return ret; + } + + if (!(val & dcfg->src_stop)) + priv->rproc->state = RPROC_DETACHED; + + return 0; +} + static int imx_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -590,6 +631,10 @@ static int imx_rproc_probe(struct platform_device *pdev) goto err_put_mbox; } + ret = imx_rproc_detect_mode(priv); + if (ret) + goto err_put_mbox; + priv->clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->clk)) { dev_err(dev, "Failed to get clock\n"); -- cgit v1.2.3 From edf696f26855788cdff832ac83319e1f2aafcc90 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 31 Mar 2021 09:33:47 +0200 Subject: remoteproc: stm32: add capability to detach A mechanism similar to the shutdown mailbox signal is implemented to detach a remote processor. Upon detachment, a signal is sent to the remote firmware, allowing it to perform specific actions such as stopping rpmsg communication. The Cortex-M hold boot is also disabled to allow the remote processor to restart in case of crash. Signed-off-by: Arnaud Pouliquen Reviewed-by: Mathieu Poirier Tested-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210331073347.8293-3-arnaud.pouliquen@foss.st.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/stm32_rproc.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 3d45f51de4d0..7353f9e7e7af 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -28,7 +28,7 @@ #define RELEASE_BOOT 1 #define MBOX_NB_VQ 2 -#define MBOX_NB_MBX 3 +#define MBOX_NB_MBX 4 #define STM32_SMC_RCC 0x82001000 #define STM32_SMC_REG_WRITE 0x1 @@ -38,6 +38,7 @@ #define STM32_MBX_VQ1 "vq1" #define STM32_MBX_VQ1_ID 1 #define STM32_MBX_SHUTDOWN "shutdown" +#define STM32_MBX_DETACH "detach" #define RSC_TBL_SIZE 1024 @@ -336,6 +337,15 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { .tx_done = NULL, .tx_tout = 500, /* 500 ms time out */ }, + }, + { + .name = STM32_MBX_DETACH, + .vq_id = -1, + .client = { + .tx_block = true, + .tx_done = NULL, + .tx_tout = 200, /* 200 ms time out to detach should be fair enough */ + }, } }; @@ -461,6 +471,25 @@ static int stm32_rproc_attach(struct rproc *rproc) return stm32_rproc_set_hold_boot(rproc, true); } +static int stm32_rproc_detach(struct rproc *rproc) +{ + struct stm32_rproc *ddata = rproc->priv; + int err, dummy_data, idx; + + /* Inform the remote processor of the detach */ + idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_DETACH); + if (idx >= 0 && ddata->mb[idx].chan) { + /* A dummy data is sent to allow to block on transmit */ + err = mbox_send_message(ddata->mb[idx].chan, + &dummy_data); + if (err < 0) + dev_warn(&rproc->dev, "warning: remote FW detach without ack\n"); + } + + /* Allow remote processor to auto-reboot */ + return stm32_rproc_set_hold_boot(rproc, false); +} + static int stm32_rproc_stop(struct rproc *rproc) { struct stm32_rproc *ddata = rproc->priv; @@ -597,7 +626,12 @@ stm32_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz) } done: - /* Assuming the resource table fits in 1kB is fair */ + /* + * Assuming the resource table fits in 1kB is fair. + * Notice for the detach, that this 1 kB memory area has to be reserved in the coprocessor + * firmware for the resource table. On detach, the remoteproc core re-initializes this + * entire area by overwriting it with the initial values stored in rproc->clean_table. + */ *table_sz = RSC_TBL_SIZE; return (struct resource_table *)ddata->rsc_va; } @@ -607,6 +641,7 @@ static const struct rproc_ops st_rproc_ops = { .start = stm32_rproc_start, .stop = stm32_rproc_stop, .attach = stm32_rproc_attach, + .detach = stm32_rproc_detach, .kick = stm32_rproc_kick, .load = rproc_elf_load_segments, .parse_fw = stm32_rproc_parse_fw, -- cgit v1.2.3