diff options
-rw-r--r-- | README.md | 87 | ||||
-rw-r--r-- | remoteproc/ethosu_remoteproc.c | 145 |
2 files changed, 138 insertions, 94 deletions
@@ -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 = ðosu_rproc_prepare, - .start = ðosu_rproc_start, - .stop = ðosu_rproc_stop, - .kick = ðosu_rproc_kick, + .prepare = ðosu_rproc_prepare, + .start = ðosu_rproc_start, + .stop = ðosu_rproc_stop, + .kick = ðosu_rproc_kick, + .handle_rsc = ðosu_rproc_handle_rsc, }; static int ethosu_mailbox_init(struct ethosu_rproc *erproc) |