aboutsummaryrefslogtreecommitdiff
path: root/remoteproc
diff options
context:
space:
mode:
authorMikael Olsson <mikael.olsson@arm.com>2023-06-05 16:16:36 +0200
committerMikael Olsson <mikael.olsson@arm.com>2023-09-25 15:01:34 +0200
commit9d0ea8bc126833da28508a0836d02fa437489bab (patch)
tree06146e7e3093c0a35fdb8c7973225ed678bd15f3 /remoteproc
parenta45260efce33ecb55a37545212ff9e5da244c4e9 (diff)
downloadethos-u-linux-driver-stack-9d0ea8bc126833da28508a0836d02fa437489bab.tar.gz
Add resource table entry for address translation
To avoid having to use a hardcoded memory map to translate between the Linux physical addresses to device addresses in the firmware, a new entry type has been added to the resource table that allows the NPU remoteproc driver to provide the memory map to the firmware. With this change, the device tree layout has been changed to wrap the ethosu-rproc node with an ethosu parent node that represents the NPU subsystem. This makes it possible to use the APIs provided by the Linux kernel to perform address translation etc. The "ethosu,dma-ranges" property has been removed from ethosu-proc because the ethosu parent node provides information for how to translate between the Linux Kernel physical addresses and device addresses with a "dma-ranges" property. Change-Id: I48719ee808a5e9391c5a3e967042d26dd92d5026 Signed-off-by: Mikael Olsson <mikael.olsson@arm.com>
Diffstat (limited to 'remoteproc')
-rw-r--r--remoteproc/ethosu_remoteproc.c145
1 files changed, 91 insertions, 54 deletions
diff --git a/remoteproc/ethosu_remoteproc.c b/remoteproc/ethosu_remoteproc.c
index b1f8793..0369156 100644
--- a/remoteproc/ethosu_remoteproc.c
+++ b/remoteproc/ethosu_remoteproc.c
@@ -1,5 +1,6 @@
/*
- * Copyright 2021-2023 Arm Limited and/or its affiliates
+ * SPDX-FileCopyrightText: Copyright 2021-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * SPDX-License-Identifier: GPL-2.0-only
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@@ -14,10 +15,10 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
- *
- * SPDX-License-Identifier: GPL-2.0-only
*/
+
#include <linux/dma-mapping.h>
+#include <linux/dma-direct.h>
#include <linux/firmware.h>
#include <linux/io.h>
#include <linux/irqreturn.h>
@@ -58,6 +59,35 @@ static bool auto_boot = DEFAULT_AUTO_BOOT;
module_param(auto_boot, bool, 0);
MODULE_PARM_DESC(auto_boot, "Set to one to auto boot at load.");
+#define RSC_MAPPING RSC_VENDOR_START + 1
+
+/**
+ * struct fw_rsc_map_range - memory map range
+ * @da: Start device address of the memory address range
+ * @pa: Start physical address of the memory address range
+ * @len: length of memory address range
+ *
+ * Memory range to translate between physical and device addresses.
+ */
+struct fw_rsc_map_range {
+ uint32_t da;
+ uint32_t pa;
+ uint32_t len;
+} __packed;
+
+/**
+ * struct fw_rsc_mapping - memory map for address translation
+ * @num_ranges: Number of ranges in the memory map
+ * @range: Array of the ranges in the memory map
+ *
+ * This resource entry requests the host to provide information for how to
+ * translate between physical and device addresses.
+ */
+struct fw_rsc_mapping {
+ uint8_t num_ranges;
+ struct fw_rsc_map_range range[0];
+} __packed;
+
struct ethosu_rproc {
struct device *dev;
struct reset_control *rstc;
@@ -92,47 +122,6 @@ static void ethosu_mbox_top(struct mbox_client *client,
queue_work(erproc->wq, &erproc->work);
}
-static dma_addr_t ethosu_of_pa_to_da(struct rproc *rproc,
- const phys_addr_t pa,
- const size_t size)
-{
- static const char of_rproc_ranges[] = "ethosu,dma-ranges";
-
- struct device *dev = rproc->dev.parent;
- struct device_node *np = dev->of_node;
- const __be32 *rproc_ranges = of_get_property(np, of_rproc_ranges, NULL);
- const int addr_cells = of_n_addr_cells(np);
- const int size_cells = of_n_size_cells(np);
- const int ranges_cells = addr_cells + addr_cells + size_cells;
- int ranges_cnt;
- int i;
-
- ranges_cnt = of_property_count_elems_of_size(
- np, of_rproc_ranges, ranges_cells * sizeof(u32));
-
- for (i = 0; i < ranges_cnt; i++) {
- const int offset = i * ranges_cells;
-
- const uint64_t of_da = of_read_number(
- &rproc_ranges[offset], addr_cells);
- const uint64_t of_pa = of_read_number(
- &rproc_ranges[offset + addr_cells], addr_cells);
- const uint64_t of_size = of_read_number(
- &rproc_ranges[offset + addr_cells + addr_cells],
- size_cells);
-
- if (pa >= of_pa && (pa + size) <= (of_pa + of_size)) {
- const dma_addr_t da = of_da + pa - of_pa;
-
- dev_dbg(dev, "PA to DA. pa=0x%llx, da=0x%llx", pa, da);
-
- return da;
- }
- }
-
- return (dma_addr_t)(-1);
-}
-
static int ethosu_add_carveout(struct rproc *rproc,
const phys_addr_t pa,
const size_t size,
@@ -143,9 +132,10 @@ static int ethosu_add_carveout(struct rproc *rproc,
void __iomem *va;
struct rproc_mem_entry *mem;
- da = ethosu_of_pa_to_da(rproc, pa, size);
- if (da == (dma_addr_t)(-1)) {
- dev_err(dev, "No mapping found for PA. pa=%llx, size=%zu", pa,
+ da = translate_phys_to_dma(dev, pa);
+ dev_dbg(dev, "PA to DA. pa=0x%pa, da=0x%pad", &pa, &da);
+ if (da == DMA_MAPPING_ERROR) {
+ dev_err(dev, "No mapping found for PA. pa=%pa, size=%zu", &pa,
size);
return -ENOMEM;
@@ -153,7 +143,7 @@ static int ethosu_add_carveout(struct rproc *rproc,
va = devm_ioremap_wc(dev, pa, size);
if (!va) {
- dev_err(dev, "Failed to remap address. pa=%llx, len=%zu", pa,
+ dev_err(dev, "Failed to remap address. pa=%pa, len=%zu", &pa,
size);
return -ENOMEM;
@@ -163,8 +153,8 @@ static int ethosu_add_carveout(struct rproc *rproc,
if (!mem)
return -ENOMEM;
- dev_info(dev, "Add carveout mapping. dma=%llx, da=%x, va=%p, len=%zu",
- mem->dma, mem->da, mem->va, mem->len);
+ dev_info(dev, "Add carveout mapping. dma=%pad, da=%x, va=%p, len=%zu",
+ &mem->dma, mem->da, mem->va, mem->len);
rproc_add_carveout(rproc, mem);
@@ -247,11 +237,58 @@ static void ethosu_rproc_kick(struct rproc *rproc,
mbox_send_message(erproc->ch_tx, (void *)&vqid);
}
+static int ethosu_rproc_handle_rsc(struct rproc *rproc,
+ u32 rsc_type,
+ void *rsc,
+ int offset,
+ int avail)
+{
+ struct ethosu_rproc *erproc = (struct ethosu_rproc *)rproc->priv;
+ struct device *dev = erproc->dev;
+ struct fw_rsc_mapping *mapping = rsc;
+ const struct bus_dma_region *map;
+ size_t num_ranges = 0U;
+ size_t i;
+
+ if (rsc_type != RSC_MAPPING)
+ return RSC_IGNORED;
+
+ if (struct_size(mapping, range, mapping->num_ranges) > avail) {
+ dev_err(dev, "mapping rsc is truncated\n");
+
+ return -EINVAL;
+ }
+
+ for (map = dev->dma_range_map; map->size; ++map)
+ num_ranges++;
+
+ if (num_ranges > mapping->num_ranges) {
+ dev_err(dev,
+ "Mapping rsc doesn't have enough room for DMA ranges\n");
+
+ return -EINVAL;
+ }
+
+ for (i = 0U; i < num_ranges; ++i) {
+ map = &dev->dma_range_map[i];
+ struct fw_rsc_map_range *range = &mapping->range[i];
+
+ range->da = map->dma_start;
+ range->pa = map->cpu_start;
+ range->len = map->size;
+ }
+
+ dev_dbg(dev, "handle_rsc: Mapping rsc setup");
+
+ return RSC_HANDLED;
+}
+
static const struct rproc_ops ethosu_rproc_ops = {
- .prepare = &ethosu_rproc_prepare,
- .start = &ethosu_rproc_start,
- .stop = &ethosu_rproc_stop,
- .kick = &ethosu_rproc_kick,
+ .prepare = &ethosu_rproc_prepare,
+ .start = &ethosu_rproc_start,
+ .stop = &ethosu_rproc_stop,
+ .kick = &ethosu_rproc_kick,
+ .handle_rsc = &ethosu_rproc_handle_rsc,
};
static int ethosu_mailbox_init(struct ethosu_rproc *erproc)