aboutsummaryrefslogtreecommitdiff
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
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>
-rw-r--r--README.md87
-rw-r--r--remoteproc/ethosu_remoteproc.c145
2 files changed, 138 insertions, 94 deletions
diff --git a/README.md b/README.md
index 4bcd34b..1b9a692 100644
--- a/README.md
+++ b/README.md
@@ -96,6 +96,12 @@ modified to insert an Ethos-U subsystem in one of the M-class slots. Mailbox
communication is based on the Arm MHU v2, and the reset is controlled using a IO
mapped bridge.
+## ethosu
+
+The `ethosu` device represents the Ethos-U subsystem and contains a
+`dma-ranges` entry that specifies how to translate between the Linux kernel
+physical addresses and bus (Cortex-M) addresses.
+
## ethosu-rproc
The [Ethos-U remoteproc driver](remoteproc/ethosu_remoteproc.c) is used to load
@@ -111,20 +117,17 @@ The `memory-region` entry references the shared memory pool. This is the memory
region used to allocate DMA buffers for the virtio rpmsg message queues and
other memory resources.
-The `ethosu,dma-ranges` is specific to the Ethos-U remoteproc driver, and is
-used to translate Linux physical addresses into DMA addresses. The reason for
-not using `dma-range` directly is that `dma-ranges` is not fully supported by
-the
-[virtio_ring.c](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/virtio/virtio_ring.c)
-kernel driver. Buffers sent to the firmware will contain Linux physical
-addresses instead of DMA addresses.
-
The `reset` entry is referencing the driver used to control reset for the
subsystem.
The `mboxes` entry is referencing the MHU v2 driver used for mailbox
communication.
+Note `dma-ranges` is not fully supported by the
+[virtio_ring.c](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/virtio/virtio_ring.c)
+kernel driver. Therefore, buffers sent to the firmware will contain Linux
+physical addresses instead of DMA addresses.
+
## Corstone-1000 DTB
```
@@ -169,38 +172,42 @@ communication.
reg-names = "rstreg", "streg";
};
- /* - compatible : "arm,ethosu-rproc"
- * - reg : Memory regions reserved for firmware binary
- * - ethosu,dma-ranges : Address translation from bus address (Cortex-M)
- * to Linux kernel physical address
- * - bus address (#address-cells)
- * - physical address (#address-cells)
- * - size (#size-cells)
- * - memory-region : Memory region for allocation of DMA buffers
- * - mboxes : Mailbox driver used to raise interrupts on
- * remote CPU
- * - resets : Reset driver used to reset remote CPU
- */
- ethosu-rproc {
- compatible = "arm,ethosu-rproc";
-
- // Address mapping from DMA to physical
- ethosu,dma-ranges = <0x00000000 0x44000000 0x00200000>,
- <0x60000000 0x80000000 0x10000000>;
-
- reg = <0x44000000 0x00200000>,
- <0x84000000 0x01000000>;
- reg-names = "rom", "shared";
-
- // Memory region to allocate buffers from
- memory-region = <&rproc_reserved>;
-
- // Mailbox IRQ communication
- mboxes = <&mbox_es0mhu0 0>, <&mbox_es0mhu0 0>;
- mbox-names = "tx", "rx";
-
- // Reset handler
- resets = <&cs1k_rst_es0 0>;
+
+ ethosu {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges;
+
+ // Address mapping from bus address (Cortex-M) to Linux kernel physical address
+ dma-ranges = <0x00000000 0x44000000 0x00200000>,
+ <0x60000000 0x80000000 0x10000000>;
+
+
+ /* - compatible : "arm,ethosu-rproc"
+ * - reg : Memory regions reserved for firmware binary
+ * - memory-region : Memory region for allocation of DMA buffers
+ * - mboxes : Mailbox driver used to raise interrupts on
+ * remote CPU
+ * - resets : Reset driver used to reset remote CPU
+ */
+ ethosu-rproc {
+ compatible = "arm,ethosu-rproc";
+
+ reg = <0x44000000 0x00200000>,
+ <0x84000000 0x01000000>;
+ reg-names = "rom", "shared";
+
+ // Memory region to allocate buffers from
+ memory-region = <&rproc_reserved>;
+
+ // Mailbox IRQ communication
+ mboxes = <&mbox_es0mhu0 0>, <&mbox_es0mhu0 0>;
+ mbox-names = "tx", "rx";
+
+ // Reset handler
+ resets = <&cs1k_rst_es0 0>;
+ };
};
};
```
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)