All of lore.kernel.org
 help / color / mirror / Atom feed
From: Amjad Ouled-Ameur <aouledameur@baylibre.com>
To: u-boot@lists.denx.de
Cc: khilman@baylibre.com, Keerthy <j-keerthy@ti.com>,
	Amjad Ouled-Ameur <aouledameur@baylibre.com>,
	Patrick Delaunay <patrick.delaunay@foss.st.com>,
	Simon Glass <sjg@chromium.org>
Subject: [PATCH v3 06/11] remoteproc: uclass: Add remoteproc resource handling helpers
Date: Tue, 18 Jan 2022 11:12:44 +0100	[thread overview]
Message-ID: <20220118101249.87031-7-aouledameur@baylibre.com> (raw)
In-Reply-To: <20220118101249.87031-1-aouledameur@baylibre.com>

From: Keerthy <j-keerthy@ti.com>

Add remoteproc resource handling helpers. These functions
are primarily to parse the resource table and to handle
different types of resources. Carveout, devmem, trace &
vring resources are handled.

Signed-off-by: Keerthy <j-keerthy@ti.com>
[Amjad: fix redefinition of "struct resource_table" and compile warnings ]
Signed-off-by: Amjad Ouled-Ameur <aouledameur@baylibre.com>

---

(no changes since v2)

Changes in v2:
- Add useful checks and remove redundant code.

 drivers/remoteproc/rproc-uclass.c | 534 ++++++++++++++++++++++++++++++
 include/remoteproc.h              | 384 ++++++++++++++++++++-
 2 files changed, 917 insertions(+), 1 deletion(-)

diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c
index 87e1ec7ad7f0..50bcc9030e98 100644
--- a/drivers/remoteproc/rproc-uclass.c
+++ b/drivers/remoteproc/rproc-uclass.c
@@ -8,15 +8,31 @@
 
 #define pr_fmt(fmt) "%s: " fmt, __func__
 #include <common.h>
+#include <elf.h>
 #include <errno.h>
 #include <log.h>
 #include <malloc.h>
+#include <virtio_ring.h>
 #include <remoteproc.h>
 #include <asm/io.h>
 #include <dm/device-internal.h>
 #include <dm.h>
 #include <dm/uclass.h>
 #include <dm/uclass-internal.h>
+#include <linux/compat.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct resource_table {
+	u32 ver;
+	u32 num;
+	u32 reserved[2];
+	u32 offset[0];
+} __packed;
+
+typedef int (*handle_resource_t) (struct udevice *, void *, int offset, int avail);
+
+static struct resource_table *rsc_table;
 
 /**
  * for_each_remoteproc_device() - iterate through the list of rproc devices
@@ -196,6 +212,80 @@ static int rproc_post_probe(struct udevice *dev)
 	return 0;
 }
 
+/**
+ * rproc_add_res() - After parsing the resource table add the mappings
+ * @dev:	device we finished probing
+ * @mapping: rproc_mem_entry for the resource
+ *
+ * Return: if the remote proc driver has a add_res routine, invokes it and
+ * hands over the return value. overall, 0 if all went well, else appropriate
+ * error value.
+ */
+static int rproc_add_res(struct udevice *dev, struct rproc_mem_entry *mapping)
+{
+	const struct dm_rproc_ops *ops = rproc_get_ops(dev);
+
+	if (!ops->add_res)
+		return -ENOSYS;
+
+	return ops->add_res(dev, mapping);
+}
+
+/**
+ * rproc_alloc_mem() - After parsing the resource table allocat mem
+ * @dev:	device we finished probing
+ * @len: rproc_mem_entry for the resource
+ * @align: alignment for the resource
+ *
+ * Return: if the remote proc driver has a add_res routine, invokes it and
+ * hands over the return value. overall, 0 if all went well, else appropriate
+ * error value.
+ */
+static void *rproc_alloc_mem(struct udevice *dev, unsigned long len,
+			     unsigned long align)
+{
+	const struct dm_rproc_ops *ops;
+
+	ops = rproc_get_ops(dev);
+	if (!ops) {
+		debug("%s driver has no ops?\n", dev->name);
+		return NULL;
+	}
+
+	if (ops->alloc_mem)
+		return ops->alloc_mem(dev, len, align);
+
+	return NULL;
+}
+
+/**
+ * rproc_config_pagetable() - Configure page table for remote processor
+ * @dev:	device we finished probing
+ * @virt: Virtual address of the resource
+ * @phys: Physical address the resource
+ * @len: length the resource
+ *
+ * Return: if the remote proc driver has a add_res routine, invokes it and
+ * hands over the return value. overall, 0 if all went well, else appropriate
+ * error value.
+ */
+static int rproc_config_pagetable(struct udevice *dev, unsigned int virt,
+				  unsigned int phys, unsigned int len)
+{
+	const struct dm_rproc_ops *ops;
+
+	ops = rproc_get_ops(dev);
+	if (!ops) {
+		debug("%s driver has no ops?\n", dev->name);
+		return -EINVAL;
+	}
+
+	if (ops->config_pagetable)
+		return ops->config_pagetable(dev, virt, phys, len);
+
+	return 0;
+}
+
 UCLASS_DRIVER(rproc) = {
 	.id = UCLASS_REMOTEPROC,
 	.name = "remoteproc",
@@ -426,3 +516,447 @@ int rproc_is_running(int id)
 {
 	return _rproc_ops_wrapper(id, RPROC_RUNNING);
 };
+
+
+static int handle_trace(struct udevice *dev, struct fw_rsc_trace *rsc,
+			int offset, int avail)
+{
+	if (sizeof(*rsc) > avail) {
+		debug("trace rsc is truncated\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * make sure reserved bytes are zeroes
+	 */
+	if (rsc->reserved) {
+		debug("trace rsc has non zero reserved bytes\n");
+		return -EINVAL;
+	}
+
+	debug("trace rsc: da 0x%x, len 0x%x\n", rsc->da, rsc->len);
+
+	return 0;
+}
+
+static int handle_devmem(struct udevice *dev, struct fw_rsc_devmem *rsc,
+			 int offset, int avail)
+{
+	struct rproc_mem_entry *mapping;
+
+	if (sizeof(*rsc) > avail) {
+		debug("devmem rsc is truncated\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * make sure reserved bytes are zeroes
+	 */
+	if (rsc->reserved) {
+		debug("devmem rsc has non zero reserved bytes\n");
+		return -EINVAL;
+	}
+
+	debug("devmem rsc: pa 0x%x, da 0x%x, len 0x%x\n",
+	      rsc->pa, rsc->da, rsc->len);
+
+	rproc_config_pagetable(dev, rsc->da, rsc->pa, rsc->len);
+
+	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+	if (!mapping)
+		return -ENOMEM;
+
+	/*
+	 * We'll need this info later when we'll want to unmap everything
+	 * (e.g. on shutdown).
+	 *
+	 * We can't trust the remote processor not to change the resource
+	 * table, so we must maintain this info independently.
+	 */
+	mapping->dma = rsc->pa;
+	mapping->da = rsc->da;
+	mapping->len = rsc->len;
+	rproc_add_res(dev, mapping);
+
+	debug("mapped devmem pa 0x%x, da 0x%x, len 0x%x\n",
+	      rsc->pa, rsc->da, rsc->len);
+
+	return 0;
+}
+
+static int handle_carveout(struct udevice *dev, struct fw_rsc_carveout *rsc,
+			   int offset, int avail)
+{
+	struct rproc_mem_entry *mapping;
+
+	if (sizeof(*rsc) > avail) {
+		debug("carveout rsc is truncated\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * make sure reserved bytes are zeroes
+	 */
+	if (rsc->reserved) {
+		debug("carveout rsc has non zero reserved bytes\n");
+		return -EINVAL;
+	}
+
+	debug("carveout rsc: da %x, pa %x, len %x, flags %x\n",
+	      rsc->da, rsc->pa, rsc->len, rsc->flags);
+
+	rsc->pa = (uintptr_t)rproc_alloc_mem(dev, rsc->len, 8);
+	if (!rsc->pa) {
+		debug
+		    ("failed to allocate carveout rsc: da %x, pa %x, len %x, flags %x\n",
+		     rsc->da, rsc->pa, rsc->len, rsc->flags);
+		return -ENOMEM;
+	}
+	rproc_config_pagetable(dev, rsc->da, rsc->pa, rsc->len);
+
+	/*
+	 * Ok, this is non-standard.
+	 *
+	 * Sometimes we can't rely on the generic iommu-based DMA API
+	 * to dynamically allocate the device address and then set the IOMMU
+	 * tables accordingly, because some remote processors might
+	 * _require_ us to use hard coded device addresses that their
+	 * firmware was compiled with.
+	 *
+	 * In this case, we must use the IOMMU API directly and map
+	 * the memory to the device address as expected by the remote
+	 * processor.
+	 *
+	 * Obviously such remote processor devices should not be configured
+	 * to use the iommu-based DMA API: we expect 'dma' to contain the
+	 * physical address in this case.
+	 */
+	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+	if (!mapping)
+		return -ENOMEM;
+
+	/*
+	 * We'll need this info later when we'll want to unmap
+	 * everything (e.g. on shutdown).
+	 *
+	 * We can't trust the remote processor not to change the
+	 * resource table, so we must maintain this info independently.
+	 */
+	mapping->dma = rsc->pa;
+	mapping->da = rsc->da;
+	mapping->len = rsc->len;
+	rproc_add_res(dev, mapping);
+
+	debug("carveout mapped 0x%x to 0x%x\n", rsc->da, rsc->pa);
+
+	return 0;
+}
+
+#define RPROC_PAGE_SHIFT 12
+#define RPROC_PAGE_SIZE  BIT(RPROC_PAGE_SHIFT)
+#define RPROC_PAGE_ALIGN(x) (((x) + (RPROC_PAGE_SIZE - 1)) & ~(RPROC_PAGE_SIZE - 1))
+
+static int alloc_vring(struct udevice *dev, struct fw_rsc_vdev *rsc, int i)
+{
+	struct fw_rsc_vdev_vring *vring = &rsc->vring[i];
+	int size;
+	int order;
+	void *pa;
+
+	debug("vdev rsc: vring%d: da %x, qsz %d, align %d\n",
+	      i, vring->da, vring->num, vring->align);
+
+	/*
+	 * verify queue size and vring alignment are sane
+	 */
+	if (!vring->num || !vring->align) {
+		debug("invalid qsz (%d) or alignment (%d)\n", vring->num,
+		      vring->align);
+		return -EINVAL;
+	}
+
+	/*
+	 * actual size of vring (in bytes)
+	 */
+	size = RPROC_PAGE_ALIGN(vring_size(vring->num, vring->align));
+	order = vring->align >> RPROC_PAGE_SHIFT;
+
+	pa = rproc_alloc_mem(dev, size, order);
+	if (!pa) {
+		debug("failed to allocate vring rsc\n");
+		return -ENOMEM;
+	}
+	debug("alloc_mem(%#x, %d): %p\n", size, order, pa);
+	vring->da = (uintptr_t)pa;
+
+	return !pa;
+}
+
+static int handle_vdev(struct udevice *dev, struct fw_rsc_vdev *rsc,
+		       int offset, int avail)
+{
+	int i, ret;
+	void *pa;
+
+	/*
+	 * make sure resource isn't truncated
+	 */
+	if (sizeof(*rsc) + rsc->num_of_vrings * sizeof(struct fw_rsc_vdev_vring)
+	    + rsc->config_len > avail) {
+		debug("vdev rsc is truncated\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * make sure reserved bytes are zeroes
+	 */
+	if (rsc->reserved[0] || rsc->reserved[1]) {
+		debug("vdev rsc has non zero reserved bytes\n");
+		return -EINVAL;
+	}
+
+	debug("vdev rsc: id %d, dfeatures %x, cfg len %d, %d vrings\n",
+	      rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings);
+
+	/*
+	 * we currently support only two vrings per rvdev
+	 */
+	if (rsc->num_of_vrings > 2) {
+		debug("too many vrings: %d\n", rsc->num_of_vrings);
+		return -EINVAL;
+	}
+
+	/*
+	 * allocate the vrings
+	 */
+	for (i = 0; i < rsc->num_of_vrings; i++) {
+		ret = alloc_vring(dev, rsc, i);
+		if (ret)
+			goto alloc_error;
+	}
+
+	pa = rproc_alloc_mem(dev, RPMSG_TOTAL_BUF_SPACE, 6);
+	if (!pa) {
+		debug("failed to allocate vdev rsc\n");
+		return -ENOMEM;
+	}
+	debug("vring buffer alloc_mem(%#x, 6): %p\n", RPMSG_TOTAL_BUF_SPACE,
+	      pa);
+
+	return 0;
+
+ alloc_error:
+	return ret;
+}
+
+/*
+ * A lookup table for resource handlers. The indices are defined in
+ * enum fw_resource_type.
+ */
+static handle_resource_t loading_handlers[RSC_LAST] = {
+	[RSC_CARVEOUT] = (handle_resource_t)handle_carveout,
+	[RSC_DEVMEM] = (handle_resource_t)handle_devmem,
+	[RSC_TRACE] = (handle_resource_t)handle_trace,
+	[RSC_VDEV] = (handle_resource_t)handle_vdev,
+};
+
+/*
+ * handle firmware resource entries before booting the remote processor
+ */
+static int handle_resources(struct udevice *dev, int len,
+			    handle_resource_t handlers[RSC_LAST])
+{
+	handle_resource_t handler;
+	int ret = 0, i;
+
+	for (i = 0; i < rsc_table->num; i++) {
+		int offset = rsc_table->offset[i];
+		struct fw_rsc_hdr *hdr = (void *)rsc_table + offset;
+		int avail = len - offset - sizeof(*hdr);
+		void *rsc = (void *)hdr + sizeof(*hdr);
+
+		/*
+		 * make sure table isn't truncated
+		 */
+		if (avail < 0) {
+			debug("rsc table is truncated\n");
+			return -EINVAL;
+		}
+
+		debug("rsc: type %d\n", hdr->type);
+
+		if (hdr->type >= RSC_LAST) {
+			debug("unsupported resource %d\n", hdr->type);
+			continue;
+		}
+
+		handler = handlers[hdr->type];
+		if (!handler)
+			continue;
+
+		ret = handler(dev, rsc, offset + sizeof(*hdr), avail);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static int
+handle_intmem_to_l3_mapping(struct udevice *dev,
+			    struct rproc_intmem_to_l3_mapping *l3_mapping)
+{
+	u32 i = 0;
+
+	for (i = 0; i < l3_mapping->num_entries; i++) {
+		struct l3_map *curr_map = &l3_mapping->mappings[i];
+		struct rproc_mem_entry *mapping;
+
+		mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+		if (!mapping)
+			return -ENOMEM;
+
+		mapping->dma = curr_map->l3_addr;
+		mapping->da = curr_map->priv_addr;
+		mapping->len = curr_map->len;
+		rproc_add_res(dev, mapping);
+	}
+
+	return 0;
+}
+
+static Elf32_Shdr *rproc_find_table(unsigned int addr)
+{
+	Elf32_Ehdr *ehdr;	/* Elf header structure pointer */
+	Elf32_Shdr *shdr;	/* Section header structure pointer */
+	Elf32_Shdr sectionheader;
+	int i;
+	u8 *elf_data;
+	char *name_table;
+	struct resource_table *ptable;
+
+	ehdr = (Elf32_Ehdr *)(uintptr_t)addr;
+	elf_data = (u8 *)ehdr;
+	shdr = (Elf32_Shdr *)(elf_data + ehdr->e_shoff);
+	memcpy(&sectionheader, &shdr[ehdr->e_shstrndx], sizeof(sectionheader));
+	name_table = (char *)(elf_data + sectionheader.sh_offset);
+
+	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+		memcpy(&sectionheader, shdr, sizeof(sectionheader));
+		u32 size = sectionheader.sh_size;
+		u32 offset = sectionheader.sh_offset;
+
+		if (strcmp
+		    (name_table + sectionheader.sh_name, ".resource_table"))
+			continue;
+
+		ptable = (struct resource_table *)(elf_data + offset);
+
+		/*
+		 * make sure table has at least the header
+		 */
+		if (sizeof(struct resource_table) > size) {
+			debug("header-less resource table\n");
+			return NULL;
+		}
+
+		/*
+		 * we don't support any version beyond the first
+		 */
+		if (ptable->ver != 1) {
+			debug("unsupported fw ver: %d\n", ptable->ver);
+			return NULL;
+		}
+
+		/*
+		 * make sure reserved bytes are zeroes
+		 */
+		if (ptable->reserved[0] || ptable->reserved[1]) {
+			debug("non zero reserved bytes\n");
+			return NULL;
+		}
+
+		/*
+		 * make sure the offsets array isn't truncated
+		 */
+		if (ptable->num * sizeof(ptable->offset[0]) +
+		    sizeof(struct resource_table) > size) {
+			debug("resource table incomplete\n");
+			return NULL;
+		}
+
+		return shdr;
+	}
+
+	return NULL;
+}
+
+struct resource_table *rproc_find_resource_table(struct udevice *dev,
+						 unsigned int addr,
+						 int *tablesz)
+{
+	Elf32_Shdr *shdr;
+	Elf32_Shdr sectionheader;
+	struct resource_table *ptable;
+	u8 *elf_data = (u8 *)(uintptr_t)addr;
+
+	shdr = rproc_find_table(addr);
+	if (!shdr) {
+		debug("%s: failed to get resource section header\n", __func__);
+		return NULL;
+	}
+
+	memcpy(&sectionheader, shdr, sizeof(sectionheader));
+	ptable = (struct resource_table *)(elf_data + sectionheader.sh_offset);
+	if (tablesz)
+		*tablesz = sectionheader.sh_size;
+
+	return ptable;
+}
+
+unsigned long rproc_parse_resource_table(struct udevice *dev, struct rproc *cfg)
+{
+	struct resource_table *ptable = NULL;
+	int tablesz;
+	int ret;
+	unsigned long addr;
+
+	addr = cfg->load_addr;
+
+	ptable = rproc_find_resource_table(dev, addr, &tablesz);
+	if (!ptable) {
+		debug("%s : failed to find resource table\n", __func__);
+		return 0;
+	}
+
+	debug("%s : found resource table\n", __func__);
+	rsc_table = kzalloc(tablesz, GFP_KERNEL);
+	if (!rsc_table) {
+		debug("resource table alloc failed!\n");
+		return 0;
+	}
+
+	/*
+	 * Copy the resource table into a local buffer before handling the
+	 * resource table.
+	 */
+	memcpy(rsc_table, ptable, tablesz);
+	if (cfg->intmem_to_l3_mapping)
+		handle_intmem_to_l3_mapping(dev, cfg->intmem_to_l3_mapping);
+	ret = handle_resources(dev, tablesz, loading_handlers);
+	if (ret) {
+		debug("handle_resources failed: %d\n", ret);
+		return 0;
+	}
+
+	/*
+	 * Instead of trying to mimic the kernel flow of copying the
+	 * processed resource table into its post ELF load location in DDR
+	 * copying it into its original location.
+	 */
+	memcpy(ptable, rsc_table, tablesz);
+	free(rsc_table);
+	rsc_table = NULL;
+
+	return 1;
+}
diff --git a/include/remoteproc.h b/include/remoteproc.h
index 089131f65fde..1a970bc23c52 100644
--- a/include/remoteproc.h
+++ b/include/remoteproc.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * (C) Copyright 2015
  * Texas Instruments Incorporated - http://www.ti.com/
@@ -15,6 +15,375 @@
  */
 #include <dm/platdata.h>	/* For platform data support - non dt world */
 
+/**
+ * struct fw_rsc_hdr - firmware resource entry header
+ * @type: resource type
+ * @data: resource data
+ *
+ * Every resource entry begins with a 'struct fw_rsc_hdr' header providing
+ * its @type. The content of the entry itself will immediately follow
+ * this header, and it should be parsed according to the resource type.
+ */
+struct fw_rsc_hdr {
+	u32 type;
+	u8 data[0];
+};
+
+/**
+ * enum fw_resource_type - types of resource entries
+ *
+ * @RSC_CARVEOUT:   request for allocation of a physically contiguous
+ *		    memory region.
+ * @RSC_DEVMEM:     request to iommu_map a memory-based peripheral.
+ * @RSC_TRACE:	    announces the availability of a trace buffer into which
+ *		    the remote processor will be writing logs.
+ * @RSC_VDEV:       declare support for a virtio device, and serve as its
+ *		    virtio header.
+ * @RSC_PRELOAD_VENDOR: a vendor resource type that needs to be handled by
+ *		    remoteproc implementations before loading
+ * @RSC_POSTLOAD_VENDOR: a vendor resource type that needs to be handled by
+ *		    remoteproc implementations after loading
+ * @RSC_LAST:       just keep this one at the end
+ *
+ * For more details regarding a specific resource type, please see its
+ * dedicated structure below.
+ *
+ * Please note that these values are used as indices to the rproc_handle_rsc
+ * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
+ * check the validity of an index before the lookup table is accessed, so
+ * please update it as needed.
+ */
+enum fw_resource_type {
+	RSC_CARVEOUT		= 0,
+	RSC_DEVMEM		= 1,
+	RSC_TRACE		= 2,
+	RSC_VDEV		= 3,
+	RSC_PRELOAD_VENDOR	= 4,
+	RSC_POSTLOAD_VENDOR	= 5,
+	RSC_LAST		= 6,
+};
+
+#define FW_RSC_ADDR_ANY (-1)
+
+/**
+ * struct fw_rsc_carveout - physically contiguous memory request
+ * @da: device address
+ * @pa: physical address
+ * @len: length (in bytes)
+ * @flags: iommu protection flags
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the requested memory region
+ *
+ * This resource entry requests the host to allocate a physically contiguous
+ * memory region.
+ *
+ * These request entries should precede other firmware resource entries,
+ * as other entries might request placing other data objects inside
+ * these memory regions (e.g. data/code segments, trace resource entries, ...).
+ *
+ * Allocating memory this way helps utilizing the reserved physical memory
+ * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries
+ * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB
+ * pressure is important; it may have a substantial impact on performance.
+ *
+ * If the firmware is compiled with static addresses, then @da should specify
+ * the expected device address of this memory region. If @da is set to
+ * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then
+ * overwrite @da with the dynamically allocated address.
+ *
+ * We will always use @da to negotiate the device addresses, even if it
+ * isn't using an iommu. In that case, though, it will obviously contain
+ * physical addresses.
+ *
+ * Some remote processors needs to know the allocated physical address
+ * even if they do use an iommu. This is needed, e.g., if they control
+ * hardware accelerators which access the physical memory directly (this
+ * is the case with OMAP4 for instance). In that case, the host will
+ * overwrite @pa with the dynamically allocated physical address.
+ * Generally we don't want to expose physical addresses if we don't have to
+ * (remote processors are generally _not_ trusted), so we might want to
+ * change this to happen _only_ when explicitly required by the hardware.
+ *
+ * @flags is used to provide IOMMU protection flags, and @name should
+ * (optionally) contain a human readable name of this carveout region
+ * (mainly for debugging purposes).
+ */
+struct fw_rsc_carveout {
+	u32 da;
+	u32 pa;
+	u32 len;
+	u32 flags;
+	u32 reserved;
+	u8 name[32];
+};
+
+/**
+ * struct fw_rsc_devmem - iommu mapping request
+ * @da: device address
+ * @pa: physical address
+ * @len: length (in bytes)
+ * @flags: iommu protection flags
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the requested region to be mapped
+ *
+ * This resource entry requests the host to iommu map a physically contiguous
+ * memory region. This is needed in case the remote processor requires
+ * access to certain memory-based peripherals; _never_ use it to access
+ * regular memory.
+ *
+ * This is obviously only needed if the remote processor is accessing memory
+ * via an iommu.
+ *
+ * @da should specify the required device address, @pa should specify
+ * the physical address we want to map, @len should specify the size of
+ * the mapping and @flags is the IOMMU protection flags. As always, @name may
+ * (optionally) contain a human readable name of this mapping (mainly for
+ * debugging purposes).
+ *
+ * Note: at this point we just "trust" those devmem entries to contain valid
+ * physical addresses, but this isn't safe and will be changed: eventually we
+ * want remoteproc implementations to provide us ranges of physical addresses
+ * the firmware is allowed to request, and not allow firmwares to request
+ * access to physical addresses that are outside those ranges.
+ */
+struct fw_rsc_devmem {
+	u32 da;
+	u32 pa;
+	u32 len;
+	u32 flags;
+	u32 reserved;
+	u8 name[32];
+};
+
+/**
+ * struct fw_rsc_trace - trace buffer declaration
+ * @da: device address
+ * @len: length (in bytes)
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the trace buffer
+ *
+ * This resource entry provides the host information about a trace buffer
+ * into which the remote processor will write log messages.
+ *
+ * @da specifies the device address of the buffer, @len specifies
+ * its size, and @name may contain a human readable name of the trace buffer.
+ *
+ * After booting the remote processor, the trace buffers are exposed to the
+ * user via debugfs entries (called trace0, trace1, etc..).
+ */
+struct fw_rsc_trace {
+	u32 da;
+	u32 len;
+	u32 reserved;
+	u8 name[32];
+};
+
+/**
+ * struct fw_rsc_vdev_vring - vring descriptor entry
+ * @da: device address
+ * @align: the alignment between the consumer and producer parts of the vring
+ * @num: num of buffers supported by this vring (must be power of two)
+ * @notifyid is a unique rproc-wide notify index for this vring. This notify
+ * index is used when kicking a remote processor, to let it know that this
+ * vring is triggered.
+ * @pa: physical address
+ *
+ * This descriptor is not a resource entry by itself; it is part of the
+ * vdev resource type (see below).
+ *
+ * Note that @da should either contain the device address where
+ * the remote processor is expecting the vring, or indicate that
+ * dynamically allocation of the vring's device address is supported.
+ */
+struct fw_rsc_vdev_vring {
+	u32 da;
+	u32 align;
+	u32 num;
+	u32 notifyid;
+	u32 pa;
+};
+
+/**
+ * struct fw_rsc_vdev - virtio device header
+ * @id: virtio device id (as in virtio_ids.h)
+ * @notifyid is a unique rproc-wide notify index for this vdev. This notify
+ * index is used when kicking a remote processor, to let it know that the
+ * status/features of this vdev have changes.
+ * @dfeatures specifies the virtio device features supported by the firmware
+ * @gfeatures is a place holder used by the host to write back the
+ * negotiated features that are supported by both sides.
+ * @config_len is the size of the virtio config space of this vdev. The config
+ * space lies in the resource table immediate after this vdev header.
+ * @status is a place holder where the host will indicate its virtio progress.
+ * @num_of_vrings indicates how many vrings are described in this vdev header
+ * @reserved: reserved (must be zero)
+ * @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'.
+ *
+ * This resource is a virtio device header: it provides information about
+ * the vdev, and is then used by the host and its peer remote processors
+ * to negotiate and share certain virtio properties.
+ *
+ * By providing this resource entry, the firmware essentially asks remoteproc
+ * to statically allocate a vdev upon registration of the rproc (dynamic vdev
+ * allocation is not yet supported).
+ *
+ * Note: unlike virtualization systems, the term 'host' here means
+ * the Linux side which is running remoteproc to control the remote
+ * processors. We use the name 'gfeatures' to comply with virtio's terms,
+ * though there isn't really any virtualized guest OS here: it's the host
+ * which is responsible for negotiating the final features.
+ * Yeah, it's a bit confusing.
+ *
+ * Note: immediately following this structure is the virtio config space for
+ * this vdev (which is specific to the vdev; for more info, read the virtio
+ * spec). the size of the config space is specified by @config_len.
+ */
+struct fw_rsc_vdev {
+	u32 id;
+	u32 notifyid;
+	u32 dfeatures;
+	u32 gfeatures;
+	u32 config_len;
+	u8 status;
+	u8 num_of_vrings;
+	u8 reserved[2];
+	struct fw_rsc_vdev_vring vring[0];
+};
+
+/**
+ * struct rproc_mem_entry - memory entry descriptor
+ * @va:	virtual address
+ * @dma: dma address
+ * @len: length, in bytes
+ * @da: device address
+ * @priv: associated data
+ * @name: associated memory region name (optional)
+ * @node: list node
+ */
+struct rproc_mem_entry {
+	void *va;
+	dma_addr_t dma;
+	int len;
+	u32 da;
+	void *priv;
+	char name[32];
+	struct list_head node;
+};
+
+struct rproc;
+
+typedef u32(*init_func_proto) (u32 core_id, struct rproc *cfg);
+
+struct l3_map {
+	u32 priv_addr;
+	u32 l3_addr;
+	u32 len;
+};
+
+struct rproc_intmem_to_l3_mapping {
+	u32 num_entries;
+	struct l3_map mappings[16];
+};
+
+/**
+ * enum rproc_crash_type - remote processor crash types
+ * @RPROC_MMUFAULT:	iommu fault
+ * @RPROC_WATCHDOG:	watchdog bite
+ * @RPROC_FATAL_ERROR	fatal error
+ *
+ * Each element of the enum is used as an array index. So that, the value of
+ * the elements should be always something sane.
+ *
+ * Feel free to add more types when needed.
+ */
+enum rproc_crash_type {
+	RPROC_MMUFAULT,
+	RPROC_WATCHDOG,
+	RPROC_FATAL_ERROR,
+};
+
+/* we currently support only two vrings per rvdev */
+#define RVDEV_NUM_VRINGS 2
+
+#define RPMSG_NUM_BUFS         (512)
+#define RPMSG_BUF_SIZE         (512)
+#define RPMSG_TOTAL_BUF_SPACE  (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
+
+/**
+ * struct rproc_vring - remoteproc vring state
+ * @va:	virtual address
+ * @dma: dma address
+ * @len: length, in bytes
+ * @da: device address
+ * @align: vring alignment
+ * @notifyid: rproc-specific unique vring index
+ * @rvdev: remote vdev
+ * @vq: the virtqueue of this vring
+ */
+struct rproc_vring {
+	void *va;
+	dma_addr_t dma;
+	int len;
+	u32 da;
+	u32 align;
+	int notifyid;
+	struct rproc_vdev *rvdev;
+	struct virtqueue *vq;
+};
+
+/** struct rproc - structure with all processor specific information for
+ * loading remotecore from boot loader.
+ *
+ * @num_iommus: Number of IOMMUs for this remote core. Zero indicates that the
+ * processor does not have an IOMMU.
+ *
+ * @cma_base: Base address of the carveout for this remotecore.
+ *
+ * @cma_size: Length of the carveout in bytes.
+ *
+ * @page_table_addr: array with the physical address of the page table. We are
+ * using the same page table for both IOMMU's. There is currently no strong
+ * usecase for maintaining different page tables for different MMU's servicing
+ * the same CPU.
+ *
+ * @mmu_base_addr: base address of the MMU
+ *
+ * @entry_point: address that is the entry point for the remote core. This
+ * address is in the memory view of the remotecore.
+ *
+ * @load_addr: Address to which the bootloader loads the firmware from
+ * persistent storage before invoking the ELF loader. Keeping this address
+ * configurable allows future optimizations such as loading the firmware from
+ * storage for remotecore2 via EDMA while the CPU is processing the ELF image
+ * of remotecore1. This address is in the memory view of the A15.
+ *
+ * @firmware_name: Name of the file that is expected to contain the ELF image.
+ *
+ * @has_rsc_table: Flag populated after parsing the ELF binary on target.
+ */
+
+struct rproc {
+	u32 num_iommus;
+	unsigned long cma_base;
+	u32 cma_size;
+	unsigned long page_table_addr;
+	unsigned long mmu_base_addr[2];
+	unsigned long load_addr;
+	unsigned long entry_point;
+	char *core_name;
+	char *firmware_name;
+	char *ptn;
+	init_func_proto start_clocks;
+	init_func_proto config_mmu;
+	init_func_proto config_peripherals;
+	init_func_proto start_core;
+	u32 has_rsc_table;
+	struct rproc_intmem_to_l3_mapping *intmem_to_l3_mapping;
+	u32 trace_pa;
+	u32 trace_len;
+};
+
+extern struct rproc *rproc_cfg_arr[2];
 /**
  * enum rproc_mem_type - What type of memory model does the rproc use
  * @RPROC_INTERNAL_MEMORY_MAPPED: Remote processor uses own memory and is memory
@@ -126,6 +495,12 @@ struct dm_rproc_ops {
 	 * @return virtual address.
 	 */
 	void * (*device_to_virt)(struct udevice *dev, ulong da, ulong size);
+	int (*add_res)(struct udevice *dev,
+		       struct rproc_mem_entry *mapping);
+	void * (*alloc_mem)(struct udevice *dev, unsigned long len,
+			    unsigned long align);
+	unsigned int (*config_pagetable)(struct udevice *dev, unsigned int virt,
+					 unsigned int phys, unsigned int len);
 };
 
 /* Accessor */
@@ -322,6 +697,13 @@ int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
  */
 int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
 			     ulong fw_size, ulong *rsc_addr, ulong *rsc_size);
+
+unsigned long rproc_parse_resource_table(struct udevice *dev,
+					 struct rproc *cfg);
+
+struct resource_table *rproc_find_resource_table(struct udevice *dev,
+						 unsigned int addr,
+						 int *tablesz);
 #else
 static inline int rproc_init(void) { return -ENOSYS; }
 static inline int rproc_dev_init(int id) { return -ENOSYS; }
-- 
2.25.1


  parent reply	other threads:[~2022-01-18 10:15 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-18 10:12 [PATCH v3 00/11] dra7: bring up and support IPU load/start Amjad Ouled-Ameur
2022-01-18 10:12 ` [PATCH v3 01/11] configs: dra7xx_evm: Increase the size of SPL_MULTI_DTB_FIT Amjad Ouled-Ameur
2022-01-18 10:12 ` [PATCH v3 02/11] reset: dra7: Add a reset driver Amjad Ouled-Ameur
2022-01-18 10:12 ` [PATCH v3 03/11] arm: mach-omap2: load/start remoteproc IPU1/IPU2 Amjad Ouled-Ameur
2022-01-18 10:12 ` [PATCH v3 04/11] drivers: misc: Makefile: Enable fs_loader compilation at SPL Level Amjad Ouled-Ameur
2022-01-26  3:37   ` Tom Rini
2022-01-27 12:18     ` Amjad Ouled-Ameur
2022-01-18 10:12 ` [PATCH v3 05/11] linux: bitmap.h: Add find_next_zero_area function Amjad Ouled-Ameur
2022-01-18 10:12 ` Amjad Ouled-Ameur [this message]
2022-01-27 15:05   ` [PATCH v3 06/11] remoteproc: uclass: Add remoteproc resource handling helpers Simon Glass
2022-01-18 10:12 ` [PATCH v3 07/11] remoteproc: ipu: Add driver to bring up ipu Amjad Ouled-Ameur
2022-01-18 10:12 ` [PATCH v3 08/11] dts: dra7-ipu-common-early-boot.dtsi: Add all the ipu early boot related nodes Amjad Ouled-Ameur
2022-01-18 10:12 ` [PATCH v3 09/11] arm: dts: dra7: Add ipu and " Amjad Ouled-Ameur
2022-01-18 10:12 ` [PATCH v3 10/11] arm: dts: dra7*/am57xx-idk-evm-u-boot: Add ipu early boot DT changes Amjad Ouled-Ameur
2022-01-18 10:12 ` [PATCH v3 11/11] dts: am57xx*: " Amjad Ouled-Ameur

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220118101249.87031-7-aouledameur@baylibre.com \
    --to=aouledameur@baylibre.com \
    --cc=j-keerthy@ti.com \
    --cc=khilman@baylibre.com \
    --cc=patrick.delaunay@foss.st.com \
    --cc=sjg@chromium.org \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.