* [PATCH v2 0/2] remoteproc: elf_loader: Make rproc_elf_load_segments() more generic
@ 2026-10-27 16:25 Uwe Kleine-König
2026-10-27 16:25 ` [PATCH v2 1/2] remoteproc: elf_loader: Create new callback for copying segments to remote cpu Uwe Kleine-König
2026-10-27 16:25 ` [PATCH v2 2/2] remoteproc: imx_dsp_rproc: Implement .memcpy_tova() Uwe Kleine-König
0 siblings, 2 replies; 3+ messages in thread
From: Uwe Kleine-König @ 2026-10-27 16:25 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier
Cc: Wolfram Sang, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, linux-remoteproc, imx, linux-arm-kernel,
linux-kernel
Hello,
changes since (implicit) v1 (available at
https://lore.kernel.org/linux-remoteproc/cover.1793008847.git.u.kleine-koenig@baylibre.com):
- Add Reviewed-by: tags for Peng Fan
- Fix checkpatch warnings pointed out by Mathieu
Uwe Kleine-König (2):
remoteproc: elf_loader: Create new callback for copying segments to
remote cpu
remoteproc: imx_dsp_rproc: Implement .memcpy_tova()
drivers/remoteproc/imx_dsp_rproc.c | 120 ++++++---------------
drivers/remoteproc/remoteproc_elf_loader.c | 64 ++++++-----
include/linux/remoteproc.h | 4 +
3 files changed, 71 insertions(+), 117 deletions(-)
base-commit: bd1ecbb61afefc6a8b876ccbc31e9228b44e9eab
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v2 1/2] remoteproc: elf_loader: Create new callback for copying segments to remote cpu
2026-10-27 16:25 [PATCH v2 0/2] remoteproc: elf_loader: Make rproc_elf_load_segments() more generic Uwe Kleine-König
@ 2026-10-27 16:25 ` Uwe Kleine-König
2026-10-27 16:25 ` [PATCH v2 2/2] remoteproc: imx_dsp_rproc: Implement .memcpy_tova() Uwe Kleine-König
1 sibling, 0 replies; 3+ messages in thread
From: Uwe Kleine-König @ 2026-10-27 16:25 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier
Cc: Wolfram Sang, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, linux-remoteproc, imx, linux-arm-kernel,
linux-kernel, Peng Fan
Some devices have special needs about how an Elf segment is copied to
the remote cpu's memory space where the default implementation using
memcpy_toio/memcpy and memset_io/memset isn't suitable. An affected
mainline driver is imx-dsp-rproc which includes a near-copy of
rproc_elf_load_segments() just to handle the IRAM only allowing 32 bit
accesses. On (not-yet-mainline) ADI SC846 the respective memory isn't
directly accessible at all and DMA must be used to copy the data.
The new callback can be used to implement just the driver specific
memcpy + memset to increase code reuse.
The patch only appears big because of indentation changes.
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
---
drivers/remoteproc/remoteproc_elf_loader.c | 64 +++++++++++++---------
include/linux/remoteproc.h | 4 ++
2 files changed, 41 insertions(+), 27 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index da3cddbe7d4c..3c749a39e5da 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -227,35 +227,45 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
break;
}
- /* grab the kernel address for this device address */
- 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);
- ret = -EINVAL;
- break;
- }
+ if (rproc->ops->memcpy_tova) {
+ ret = rproc->ops->memcpy_tova(rproc, da, elf_data + offset, filesz, memsz);
+ if (ret) {
+ dev_err(dev, "Failed to copy segment %d to device address 0x%llx: %pe\n",
+ i, da, ERR_PTR(ret));
+ break;
+ }
+ } else {
+ /* grab the kernel address for this device address */
+ 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);
+ ret = -EINVAL;
+ break;
+ }
- /* put the segment where the remote processor expects it */
- if (filesz) {
- if (is_iomem)
- memcpy_toio((void __iomem *)ptr, elf_data + offset, filesz);
- else
- memcpy(ptr, elf_data + offset, filesz);
- }
+ /* put the segment where the remote processor expects it */
+ if (filesz) {
+ if (is_iomem)
+ memcpy_toio((void __iomem *)ptr, elf_data + offset, filesz);
+ else
+ memcpy(ptr, elf_data + offset, filesz);
+ }
- /*
- * Zero out remaining memory for this segment.
- *
- * This isn't strictly required since dma_alloc_coherent already
- * did this for us. albeit harmless, we may consider removing
- * this.
- */
- if (memsz > filesz) {
- if (is_iomem)
- memset_io((void __iomem *)(ptr + filesz), 0, memsz - filesz);
- else
- memset(ptr + filesz, 0, memsz - filesz);
+ /*
+ * Zero out remaining memory for this segment.
+ *
+ * This isn't strictly required since dma_alloc_coherent already
+ * did this for us. albeit harmless, we may consider removing
+ * this.
+ */
+ if (memsz > filesz) {
+ if (is_iomem)
+ memset_io((void __iomem *)(ptr + filesz),
+ 0, memsz - filesz);
+ else
+ memset(ptr + filesz, 0, memsz - filesz);
+ }
}
}
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 00019b1895e6..e750a127cbc4 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -75,6 +75,7 @@ enum rsc_handling_status {
* @detach: detach from a device, leaving it powered up
* @kick: kick a virtqueue (virtqueue id given as a parameter)
* @da_to_va: optional platform hook to perform address translations
+ * @memcpy_tova:optional platform hook to copy data into remote memory range
* @parse_fw: parse firmware to extract information (e.g. resource table)
* @handle_rsc: optional platform hook to handle vendor resources. Should return
* RSC_HANDLED if resource was handled, RSC_IGNORED if not handled
@@ -99,6 +100,9 @@ struct rproc_ops {
int (*detach)(struct rproc *rproc);
void (*kick)(struct rproc *rproc, int vqid);
void * (*da_to_va)(struct rproc *rproc, u64 da, size_t len, bool *is_iomem);
+ int (*memcpy_tova)(struct rproc *rproc, u64 da, const void *src,
+ size_t filesz, size_t memsz);
+
int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
int offset, int avail);
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v2 2/2] remoteproc: imx_dsp_rproc: Implement .memcpy_tova()
2026-10-27 16:25 [PATCH v2 0/2] remoteproc: elf_loader: Make rproc_elf_load_segments() more generic Uwe Kleine-König
2026-10-27 16:25 ` [PATCH v2 1/2] remoteproc: elf_loader: Create new callback for copying segments to remote cpu Uwe Kleine-König
@ 2026-10-27 16:25 ` Uwe Kleine-König
1 sibling, 0 replies; 3+ messages in thread
From: Uwe Kleine-König @ 2026-10-27 16:25 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier
Cc: Wolfram Sang, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, linux-remoteproc, imx, linux-arm-kernel,
linux-kernel, Peng Fan
This callback allows to use the core's rproc_elf_load_segments()
function instead of reimplementing it for very minor changes.
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
---
drivers/remoteproc/imx_dsp_rproc.c | 120 ++++++++---------------------
1 file changed, 30 insertions(+), 90 deletions(-)
diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index 96d619daf3f5..324c10f18507 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -864,97 +864,41 @@ static int imx_dsp_rproc_memset(void *addr, u8 value, size_t size)
return 0;
}
-/*
- * imx_dsp_rproc_elf_load_segments() - load firmware segments to memory
- * @rproc: remote processor which will be booted using these fw segments
- * @fw: the ELF firmware image
- *
- * This function loads the firmware segments to memory, where the remote
- * processor expects them.
- *
- * Return: 0 on success and an appropriate error code otherwise
- */
-static int imx_dsp_rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
+static int imx_dsp_rproc_memcpy_tova(struct rproc *rproc, u64 da, const void *src,
+ size_t filesz, size_t memsz)
{
struct device *dev = &rproc->dev;
- const void *ehdr, *phdr;
- int i, ret = 0;
- u16 phnum;
- const u8 *elf_data = fw->data;
- u8 class = fw_elf_get_class(fw);
- u32 elf_phdr_get_size = elf_size_of_phdr(class);
+ void *ptr;
+ int ret;
- ehdr = elf_data;
- phnum = elf_hdr_get_e_phnum(class, ehdr);
- phdr = elf_data + elf_hdr_get_e_phoff(class, ehdr);
+ /* grab the kernel address for this device address */
+ ptr = rproc_da_to_va(rproc, da, memsz, NULL);
+ if (!ptr) {
+ dev_err(dev, "bad phdr da 0x%llx mem 0x%zx\n", da, memsz);
+ return -EINVAL;
+ }
- /* go through the available ELF segments */
- for (i = 0; i < phnum; i++, phdr += elf_phdr_get_size) {
- u64 da = elf_phdr_get_p_paddr(class, phdr);
- u64 memsz = elf_phdr_get_p_memsz(class, phdr);
- u64 filesz = elf_phdr_get_p_filesz(class, phdr);
- u64 offset = elf_phdr_get_p_offset(class, phdr);
- u32 type = elf_phdr_get_p_type(class, phdr);
- void *ptr;
-
- if (type != PT_LOAD || !memsz)
- continue;
-
- dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
- type, da, memsz, filesz);
-
- if (filesz > memsz) {
- dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
- filesz, memsz);
- ret = -EINVAL;
- break;
- }
-
- if (offset + filesz > fw->size) {
- dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
- offset + filesz, fw->size);
- ret = -EINVAL;
- break;
- }
-
- if (!rproc_u64_fit_in_size_t(memsz)) {
- dev_err(dev, "size (%llx) does not fit in size_t type\n",
- memsz);
- ret = -EOVERFLOW;
- break;
- }
-
- /* grab the kernel address for this device address */
- ptr = rproc_da_to_va(rproc, da, memsz, NULL);
- if (!ptr) {
- dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
- memsz);
- ret = -EINVAL;
- break;
- }
-
- /* put the segment where the remote processor expects it */
- if (filesz) {
- ret = imx_dsp_rproc_memcpy(ptr, elf_data + offset, filesz);
- if (ret) {
- dev_err(dev, "memory copy failed for da 0x%llx memsz 0x%llx\n",
- da, memsz);
- break;
- }
- }
-
- /* zero out remaining memory for this segment */
- if (memsz > filesz) {
- ret = imx_dsp_rproc_memset(ptr + filesz, 0, memsz - filesz);
- if (ret) {
- dev_err(dev, "memset failed for da 0x%llx memsz 0x%llx\n",
- da, memsz);
- break;
- }
+ /* put the segment where the remote processor expects it */
+ if (filesz) {
+ ret = imx_dsp_rproc_memcpy(ptr, src, filesz);
+ if (ret) {
+ dev_err(dev, "memory copy failed for da 0x%llx memsz 0x%zx\n",
+ da, memsz);
+ return ret;
}
}
- return ret;
+ /* zero out remaining memory for this segment */
+ if (memsz > filesz) {
+ ret = imx_dsp_rproc_memset(ptr + filesz, 0, memsz - filesz);
+ if (ret) {
+ dev_err(dev, "memset failed for da 0x%llx memsz 0x%zx\n",
+ da, memsz);
+ return ret;
+ }
+ }
+
+ return 0;
}
static int imx_dsp_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
@@ -969,7 +913,6 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw)
struct imx_dsp_rproc *priv = rproc->priv;
const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg;
struct rproc_mem_entry *carveout;
- int ret;
/* Reset DSP if needed */
if (dsp_dcfg->reset)
@@ -985,11 +928,7 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw)
}
}
- ret = imx_dsp_rproc_elf_load_segments(rproc, fw);
- if (ret)
- return ret;
-
- return 0;
+ return rproc_elf_load_segments(rproc, fw);
}
static const struct rproc_ops imx_dsp_rproc_ops = {
@@ -998,6 +937,7 @@ static const struct rproc_ops imx_dsp_rproc_ops = {
.start = imx_dsp_rproc_start,
.stop = imx_dsp_rproc_stop,
.kick = imx_dsp_rproc_kick,
+ .memcpy_tova = imx_dsp_rproc_memcpy_tova,
.load = imx_dsp_rproc_load,
.parse_fw = imx_dsp_rproc_parse_fw,
.handle_rsc = imx_dsp_rproc_handle_rsc,
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-27 16:25 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-27 16:25 [PATCH v2 0/2] remoteproc: elf_loader: Make rproc_elf_load_segments() more generic Uwe Kleine-König
2026-10-27 16:25 ` [PATCH v2 1/2] remoteproc: elf_loader: Create new callback for copying segments to remote cpu Uwe Kleine-König
2026-10-27 16:25 ` [PATCH v2 2/2] remoteproc: imx_dsp_rproc: Implement .memcpy_tova() Uwe Kleine-König
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®