[RFC PATCH 03/10] remoteproc: add remoteproc virtio transport driver

Tanmay Shah tanmay.shah at amd.com
Tue Jul 25 16:06:43 CEST 2023


Remoteproc virtio is virtio transport layer driver for remoteproc.
Implement virtio config ops used by actual virtio
driver using remoteproc virtio device

Ported from the Linux kernel version 6.4-rc2 (d848a4819d85),
Introduced in kernel version v3.10 (ac8954a41393)
file: drivers/remoteproc/remoteproc_virtio.c.

Signed-off-by: Tanmay Shah <tanmay.shah at amd.com>
---
 MAINTAINERS                       |   6 +
 drivers/remoteproc/Kconfig        |  11 +
 drivers/remoteproc/Makefile       |   1 +
 drivers/remoteproc/rproc-uclass.c |  42 ++-
 drivers/remoteproc/rproc_virtio.c | 422 ++++++++++++++++++++++++++++++
 drivers/virtio/virtio_ring.c      |  16 ++
 include/remoteproc.h              |  66 +++--
 include/rproc_virtio.h            |  29 ++
 include/virtio.h                  |   3 +
 include/virtio_ring.h             |  17 ++
 10 files changed, 593 insertions(+), 20 deletions(-)
 create mode 100644 drivers/remoteproc/rproc_virtio.c
 create mode 100644 include/rproc_virtio.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 87991cccdd..c4a32a0956 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1319,6 +1319,12 @@ S:	Maintained
 T:	git https://source.denx.de/u-boot/custodians/u-boot-nand-flash.git
 F:	drivers/mtd/nand/raw/
 
+REMOTEPROC
+M:	Tanmay Shah <tanmay.shah at amd.com>
+S:	Maintained
+F:	drivers/remoteproc/rproc_virtio.c
+F:	include/rproc_virtio.h
+
 RISC-V
 M:	Rick Chen <rick at andestech.com>
 M:	Leo <ycliang at andestech.com>
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 27e4a60ff5..b758c248e4 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -102,4 +102,15 @@ config REMOTEPROC_TI_IPU
 	help
 	  Say 'y' here to add support for TI' K3 remoteproc driver.
 
+config REMOTEPROC_VIRTIO
+	bool "Support remoteproc virtio devices"
+	select REMOTEPROC
+	select VIRTIO
+	depends on DM
+	help
+	  Say 'y' here to add support of remoteproc virtio devices.
+	  rproc_virtio is virtio transport layer driver. The transport
+	  drivers provide a set of ops for the real virtio device
+	  driver to call.
+
 endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index fbe9c172bc..61fdb87efb 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o
 obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o
 obj-$(CONFIG_REMOTEPROC_TI_PRU) += pru_rproc.o
 obj-$(CONFIG_REMOTEPROC_TI_IPU) += ipu_rproc.o
+obj-$(CONFIG_REMOTEPROC_VIRTIO) += rproc_virtio.o
diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c
index d697639cdd..3aebaf6187 100644
--- a/drivers/remoteproc/rproc-uclass.c
+++ b/drivers/remoteproc/rproc-uclass.c
@@ -14,6 +14,7 @@
 #include <malloc.h>
 #include <virtio_ring.h>
 #include <remoteproc.h>
+#include <rproc_virtio.h>
 #include <asm/io.h>
 #include <dm/device-internal.h>
 #include <dm.h>
@@ -279,6 +280,33 @@ static int rproc_config_pagetable(struct udevice *dev, unsigned int virt,
 	return 0;
 }
 
+/**
+ * rproc_find_res_by_name() - After parsing the resource table add the mappings
+ * @dev:	device we finished probing
+ * @name: name of rproc_mem_entry resource
+ *
+ * Return: If failed NULL, else first carveout entry with matching name.
+ */
+struct rproc_mem_entry *rproc_find_res_by_name(struct udevice *dev,
+					       const char *name)
+{
+	struct rproc *rproc = rproc_get_cfg(dev);
+	struct rproc_mem_entry *mapping = NULL;
+	int ret;
+
+	if (!rproc)
+		return NULL;
+
+	list_for_each_entry(mapping, &rproc->mappings.node, node) {
+		ret = strcmp(mapping->name, name);
+		if (!ret)
+			return mapping;
+	}
+
+	debug("%s: %s carveout not found\n", dev->name, name);
+	return NULL;
+}
+
 UCLASS_DRIVER(rproc) = {
 	.id = UCLASS_REMOTEPROC,
 	.name = "remoteproc",
@@ -688,6 +716,7 @@ static int alloc_vring(struct udevice *dev, struct fw_rsc_vdev *rsc, int i)
 static int handle_vdev(struct udevice *dev, struct fw_rsc_vdev *rsc,
 		       int offset, int avail)
 {
+	struct rproc *rproc;
 	int i, ret;
 	void *pa;
 
@@ -720,7 +749,18 @@ static int handle_vdev(struct udevice *dev, struct fw_rsc_vdev *rsc,
 	}
 
 	/*
-	 * allocate the vrings
+	 * If virtio device creation is supported, then prefer to get vrings
+	 * during find_vq op
+	 */
+	rproc = rproc_get_cfg(dev);
+
+	if (rproc && rproc->support_rpmsg_virtio &&
+	    !(IS_ENABLED(CONFIG_SANDBOX))) {
+		return rproc_virtio_create_dev(dev, rsc, offset);
+	}
+
+	/*
+	 * allocate the vrings traditional way
 	 */
 	for (i = 0; i < rsc->num_of_vrings; i++) {
 		ret = alloc_vring(dev, rsc, i);
diff --git a/drivers/remoteproc/rproc_virtio.c b/drivers/remoteproc/rproc_virtio.c
new file mode 100644
index 0000000000..5e7cdfa12f
--- /dev/null
+++ b/drivers/remoteproc/rproc_virtio.c
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Remote Processor Messaging transport
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2023, Advanced Micro Devices Inc.
+ *
+ * VirtIO RPMsg transport driver
+ * Ported from Linux drivers/remoteproc/remoteproc_virtio.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <remoteproc.h>
+#include <rproc_virtio.h>
+#include <virtio.h>
+#include <virtio_ring.h>
+#include <virtio_types.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <linux/bug.h>
+#include <linux/compat.h>
+#include <linux/err.h>
+
+/**
+ * rproc_flush_dcache() - flush shared memory regions
+ * @dev: valid remoteproc virtio device
+ *
+ * Some platforms have dcache enabled. If dcache is on then data written
+ * to shared memory is actually written to cache memory. This function
+ * checks if cache is on or not and if it is on, then it performs
+ * flush and invalidate operation on address range or reserved memory
+ * created by platform driver for remoteproc
+ *
+ * Return: none
+ */
+void rproc_flush_dcache(struct udevice *dev)
+{
+	struct rproc *rproc = rproc_get_cfg(dev->parent);
+	struct rproc_mem_entry *mapping = NULL;
+	struct list_head *mapping_node = NULL;
+
+	/* If dcache is off, don't perform cache operation */
+	if (dcache_status() == false)
+		return;
+
+	/*
+	 * If cache is on, then flush cache
+	 * specially reserved mem regions for,
+	 * resource table, vrings and vdevbuffer of platform dev
+	 */
+	list_for_each(mapping_node, &rproc->mappings.node) {
+		mapping = container_of(mapping_node, struct rproc_mem_entry,
+				       node);
+
+		/*
+		 * First flush data so current data from cache is written
+		 * to actual memory from cache. Then invalidate cache so
+		 * next time data will be accessed from actual memory
+		 */
+		flush_dcache_range(mapping->da, mapping->da + mapping->len);
+		invalidate_dcache_range(mapping->da, mapping->da + mapping->len);
+	}
+}
+
+int rproc_virtio_create_dev(struct udevice *parent, struct fw_rsc_vdev *rsc,
+			    int offset)
+{
+	struct rproc_rvdev_data *rvdev_data;
+	struct udevice *vdev = NULL;
+	struct rproc *rproc;
+	char *dev_name;
+	int ret;
+
+	rproc = rproc_get_cfg(parent);
+	if (!rproc)
+		return -EINVAL;
+
+	rvdev_data = kzalloc(sizeof(*rvdev_data), GFP_KERNEL);
+	rvdev_data->id = rsc->id;
+	rvdev_data->rsc_offset = offset;
+
+	dev_name = kcalloc(32, sizeof(char), GFP_KERNEL);
+	sprintf(dev_name, "rproc-virtio#%d", rproc->rproc_id);
+
+	rvdev_data->index = rproc->rproc_id;
+	ret = device_bind(parent, DM_DRIVER_GET(rproc_virtio),
+			  dev_name, rvdev_data, ofnode_null(),
+			  &vdev);
+	if (ret) {
+		debug("failed to bind %s device\n", dev_name);
+		return ret;
+	}
+
+	ret = device_probe(vdev);
+	if (ret) {
+		debug("probing device %s failed\n", dev_name);
+		return ret;
+	}
+
+	free(dev_name);
+	dev_name = NULL;
+
+	return 0;
+}
+
+static int rproc_virtio_get_config(struct udevice *dev, unsigned int offset,
+				   void *buf, unsigned int len)
+{
+	struct rproc_rvdev_data *rvdev_data;
+	struct fw_rsc_vdev *rsc;
+	struct rproc *rproc;
+	void *cfg;
+
+	rvdev_data = dev_get_plat(dev);
+	rproc = rproc_get_cfg(dev->parent);
+
+	rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset;
+
+	/* flush cache before reading configurations */
+	rproc_flush_dcache(dev);
+
+	cfg = &rsc->vring[rsc->num_of_vrings];
+
+	if (offset + len > rsc->config_len || offset + len < len) {
+		dev_err(dev, "rproc_virtio_get: access out of bounds\n");
+		return -EINVAL;
+	}
+
+	memcpy(buf, cfg + offset, len);
+
+	return 0;
+}
+
+static void rproc_transport_features(struct udevice *dev)
+{
+	/*
+	 * Packed ring isn't enabled on remoteproc for now,
+	 * because remoteproc uses vring_new_virtqueue() which
+	 * creates virtio rings on preallocated memory.
+	 */
+	__virtio_clear_bit(dev, VIRTIO_F_RING_PACKED);
+}
+
+static int rproc_virtio_set_config(struct udevice *dev, unsigned int offset,
+				   const void *buf, unsigned int len)
+{
+	struct rproc_rvdev_data *rvdev_data;
+	struct fw_rsc_vdev *rsc;
+	struct rproc *rproc;
+	void *cfg;
+
+	rvdev_data = dev_get_plat(dev);
+	rproc = rproc_get_cfg(dev->parent);
+
+	rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset;
+	cfg = &rsc->vring[rsc->num_of_vrings];
+
+	if (offset + len > rsc->config_len || offset + len < len) {
+		dev_err(dev, "rproc_virtio_set: access out of bounds\n");
+		return -EINVAL;
+	}
+
+	memcpy(cfg + offset, buf, len);
+	rproc_flush_dcache(dev);
+
+	return 0;
+}
+
+static int rproc_virtio_get_status(struct udevice *dev, u8 *status)
+{
+	struct rproc_rvdev_data *rvdev_data;
+	struct fw_rsc_vdev *rsc;
+	struct rproc *rproc;
+
+	rvdev_data = dev_get_plat(dev);
+	rproc = rproc_get_cfg(dev->parent);
+
+	rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset;
+
+	*status = rsc->status;
+
+	rproc_flush_dcache(dev);
+
+	return 0;
+}
+
+static int rproc_virtio_set_status(struct udevice *dev, u8 status)
+{
+	struct rproc_rvdev_data *rvdev_data;
+	struct fw_rsc_vdev *rsc;
+	struct rproc *rproc;
+
+	rvdev_data = dev_get_plat(dev);
+	rproc = rproc_get_cfg(dev->parent);
+
+	rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset;
+
+	rsc->status = status;
+
+	rproc_flush_dcache(dev);
+
+	return 0;
+}
+
+static int rproc_virtio_reset(struct udevice *dev)
+{
+	struct rproc_rvdev_data *rvdev_data;
+	struct fw_rsc_vdev *rsc;
+	struct rproc *rproc;
+
+	rvdev_data = dev_get_plat(dev);
+	rproc = rproc_get_cfg(dev->parent);
+
+	rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset;
+
+	rsc->status = 0;
+
+	rproc_flush_dcache(dev);
+
+	return 0;
+}
+
+static int rproc_virtio_get_features(struct udevice *dev, u64 *features)
+{
+	struct rproc_rvdev_data *rvdev_data;
+	struct fw_rsc_vdev *rsc;
+	struct rproc *rproc;
+
+	rvdev_data = dev_get_plat(dev);
+	rproc = rproc_get_cfg(dev->parent);
+
+	rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset;
+
+	rproc_flush_dcache(dev);
+
+	*features = rsc->dfeatures;
+
+	return 0;
+}
+
+static int rproc_virtio_set_features(struct udevice *dev)
+{
+	struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct rproc_rvdev_data *rvdev_data;
+	struct fw_rsc_vdev *rsc;
+	struct rproc *rproc;
+
+	rvdev_data = dev_get_plat(dev);
+	rproc = rproc_get_cfg(dev->parent);
+
+	rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset;
+
+	/* Give virtio_rproc a chance to accept features. */
+	rproc_transport_features(dev);
+
+	/* reject any features > 32 bits! */
+	if (WARN_ON((u32)uc_priv->features != uc_priv->features))
+		return -EINVAL;
+
+	/*
+	 * Remember the finalized features of our vdev, and provide it
+	 * to the remote processor once it is powered on.
+	 */
+	rsc->gfeatures = uc_priv->features;
+
+	rproc_flush_dcache(dev);
+
+	return 0;
+}
+
+static void rproc_virtio_del_vq(struct virtqueue *vq)
+{
+	vring_del_virtqueue(vq);
+}
+
+static int rproc_virtio_del_vqs(struct udevice *vdev)
+{
+	struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(vdev);
+	struct virtqueue *vq, *n;
+
+	list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
+		rproc_virtio_del_vq(vq);
+
+	return 0;
+}
+
+static int rproc_virtio_find_vqs(struct udevice *vdev, unsigned int nvqs,
+				 struct virtqueue *vqs[])
+{
+	int queue_index = 0, align, i, core_id, da;
+	struct rproc_rvdev_data *rvdev_data;
+	struct fw_rsc_vdev_vring *rvring;
+	struct rproc_mem_entry *mapping;
+	struct fw_rsc_vdev *rsc;
+	char name[32] = {0};
+	struct rproc *rproc;
+	struct vring vring;
+	unsigned int num;
+
+	rvdev_data = dev_get_plat(vdev);
+	rproc = rproc_get_cfg(vdev->parent);
+
+	if (nvqs > 2)
+		return -EINVAL;
+
+	core_id = rvdev_data->index;
+
+	rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset;
+
+	for (i = 0; i < nvqs; i++) {
+		sprintf(name, "vdev%dvring%d", core_id, i);
+		mapping = rproc_find_res_by_name(vdev->parent, name);
+		if (!mapping) {
+			dev_err(vdev, "carveout %s not found\n", name);
+			return -EINVAL;
+		}
+
+		num = rsc->vring[i].num;
+		/* assume num is a power of 2 */
+		if (num & (num - 1)) {
+			dev_err(vdev, "Bad virtqueue length %u\n", num);
+			return -EINVAL;
+		}
+
+		align = rsc->vring[i].align;
+		rvring = &rvdev_data->vring[i];
+
+		memset(mapping->va, 0, vring_size(num, align));
+		vring_init(&vring, num, mapping->va, align, NULL);
+
+		vqs[i] = vring_new_virtqueue(queue_index, vring, vdev);
+		if (!vqs[i]) {
+			dev_err(vdev, "failed to create vq\n");
+			return -EINVAL;
+		}
+
+		rvring->da = da;
+		rvring->notifyid = vqs[i]->index;
+		rvring->num = num;
+		rvring->align = align;
+
+		/* update vring in resource table */
+		rsc->vring[i].notifyid = rvring->notifyid;
+		rsc->vring[i].da = mapping->da;
+		rsc->vring[i].pa = mapping->da;
+		queue_index++;
+
+		rproc_flush_dcache(vdev);
+	}
+
+	return 0;
+}
+
+static int rproc_virtio_notify(struct udevice *dev, struct virtqueue *vq)
+{
+	struct dm_rproc_ops *ops;
+
+	ops = rproc_get_ops(dev->parent);
+	if (!ops || !ops->kick) {
+		dev_err(dev, "kick op not available for dev %s\n",
+			dev->parent->name);
+		return -EINVAL;
+	}
+
+	rproc_flush_dcache(dev);
+
+	return ops->kick(dev->parent, vq->index);
+}
+
+static int rproc_virtio_probe(struct udevice *vdev)
+{
+	struct virtio_dev_priv *ucpriv = dev_get_uclass_priv(vdev);
+	struct rproc_rvdev_data *rvdev_data;
+	struct udevice *rproc_dev;
+	char rvdev_name[32] = {0};
+
+	rvdev_data = dev_get_plat(vdev);
+
+	rproc_dev = vdev->parent;
+
+	sprintf(rvdev_name, "vdev%dbuffer", rvdev_data->index);
+	rvdev_data->vdev_buf = rproc_find_res_by_name(vdev->parent, rvdev_name);
+	if (!rvdev_data->vdev_buf) {
+		dev_err(vdev, "%s carveout not found", rvdev_name);
+		return -EINVAL;
+	}
+
+	ucpriv->vdev = vdev;
+	ucpriv->device = rvdev_data->id;
+
+	return 0;
+}
+
+static const struct dm_virtio_ops rproc_virtio_ops = {
+	.get_config	= rproc_virtio_get_config,
+	.set_config	= rproc_virtio_set_config,
+	.get_status	= rproc_virtio_get_status,
+	.set_status	= rproc_virtio_set_status,
+	.reset		= rproc_virtio_reset,
+	.get_features	= rproc_virtio_get_features,
+	.set_features	= rproc_virtio_set_features,
+	.find_vqs	= rproc_virtio_find_vqs,
+	.del_vqs	= rproc_virtio_del_vqs,
+	.notify		= rproc_virtio_notify,
+};
+
+static const struct udevice_id rproc_virtio_ids[] = {
+	{ .compatible = "rproc,virtio" },
+};
+
+U_BOOT_DRIVER(rproc_virtio) = {
+	.name	= "rproc_virtio",
+	.id	= UCLASS_VIRTIO,
+	.of_match = rproc_virtio_ids,
+	.ops	= &rproc_virtio_ops,
+	.probe	= rproc_virtio_probe,
+	.plat_auto	= sizeof(struct rproc_rvdev_data),
+};
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index c9adcce5c0..4a9645fac4 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -331,6 +331,22 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
 	return vq;
 }
 
+struct virtqueue *vring_new_virtqueue(unsigned int index,
+				      struct vring vring,
+				      struct udevice *udev)
+{
+	struct virtqueue *vq;
+
+	vq = __vring_new_virtqueue(index, vring, udev);
+	if (!vq)
+		return NULL;
+
+	debug("(%s): created vring @ %p for vq @ %p\n", udev->name,
+	      vring.desc, vq);
+
+	return vq;
+}
+
 struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num,
 					 unsigned int vring_align,
 					 struct udevice *udev)
diff --git a/include/remoteproc.h b/include/remoteproc.h
index af5c584e6e..4251af52bd 100644
--- a/include/remoteproc.h
+++ b/include/remoteproc.h
@@ -343,25 +343,20 @@ enum rproc_crash_type {
 #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_rvdev_data - remoteproc virito device data
+ *
+ * @rsc_offset: resource offset
+ * @id: virtio dev id
+ * @index: vdev position vs other vdev declared in resource table
+ * @vring:  store tx and rx vrings description
+ * @vdev_buf: vdev0buffer carveout mapping
+ */
+struct rproc_rvdev_data {
+	u32 rsc_offset;
+	unsigned int id;
+	u32 index;
+	struct fw_rsc_vdev_vring vring[2];
+	struct rproc_mem_entry *vdev_buf;
 };
 
 /** struct rproc - structure with all processor specific information for
@@ -383,6 +378,7 @@ struct rproc_vring {
  *
  * @entry_point: address that is the entry point for the remote core. This
  * address is in the memory view of the remotecore.
+ * @rproc_id: per core id
  *
  * @load_addr: Address to which the bootloader loads the firmware from
  * persistent storage before invoking the ELF loader. Keeping this address
@@ -393,6 +389,11 @@ struct rproc_vring {
  * @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.
+ * @support_rpmsg_virtio: set in rproc platform driver to support new rpmsg framework
+ * @mappings: list of reserved memory regions created by platform driver
+ *  such as vring0, vring1, vdevbuffer etc...
+ * @table_ptr: holds address of resource table from shared memory between host
+ * and remote processors
  */
 
 struct rproc {
@@ -403,6 +404,7 @@ struct rproc {
 	unsigned long mmu_base_addr[2];
 	unsigned long load_addr;
 	unsigned long entry_point;
+	int rproc_id;
 	char *core_name;
 	char *firmware_name;
 	char *ptn;
@@ -414,6 +416,9 @@ struct rproc {
 	struct rproc_intmem_to_l3_mapping *intmem_to_l3_mapping;
 	u32 trace_pa;
 	u32 trace_len;
+	bool support_rpmsg_virtio;
+	struct rproc_mem_entry mappings;
+	struct resource_table *table_ptr;
 };
 
 extern struct rproc *rproc_cfg_arr[2];
@@ -444,6 +449,7 @@ struct dm_rproc_uclass_pdata {
 	const char *name;
 	enum rproc_mem_type mem_type;
 	void *driver_plat_data;
+	struct rproc *rproc;
 };
 
 /**
@@ -534,10 +540,22 @@ struct dm_rproc_ops {
 			    unsigned long align);
 	unsigned int (*config_pagetable)(struct udevice *dev, unsigned int virt,
 					 unsigned int phys, unsigned int len);
+	struct resource_table *(*get_loaded_rsc_table)(struct udevice *dev,
+						       int *tablesz);
+	/**
+	 * kick() - kick the remote device for communication (needed for rpmsg)
+	 *
+	 * @dev:	Remote proc device
+	 * @notify_id:	vq id to be notified
+	 * @return 0 on success, 1 if not responding, -ve on other errors.
+	 */
+	int (*kick)(struct udevice *dev, int notify_id);
 };
 
 /* Accessor */
 #define rproc_get_ops(dev) ((struct dm_rproc_ops *)(dev)->driver->ops)
+#define rproc_get_cfg(dev) (((struct dm_rproc_uclass_pdata *) \
+			    dev_get_plat(dev))->rproc)
 
 #if CONFIG_IS_ENABLED(REMOTEPROC)
 /**
@@ -737,6 +755,10 @@ unsigned long rproc_parse_resource_table(struct udevice *dev,
 struct resource_table *rproc_find_resource_table(struct udevice *dev,
 						 unsigned int addr,
 						 int *tablesz);
+struct resource_table *rproc_get_loaded_rsc_table(struct udevice *dev,
+						  struct rproc *cfg);
+struct rproc_mem_entry *rproc_find_res_by_name(struct udevice *dev,
+					       const char *name);
 #else
 static inline int rproc_init(void) { return -ENOSYS; }
 static inline int rproc_dev_init(int id) { return -ENOSYS; }
@@ -776,6 +798,12 @@ static inline int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
 					   ulong fw_size, ulong *rsc_addr,
 					   ulong *rsc_size)
 { return -ENOSYS; }
+
+static inline struct rproc_mem_entry *rproc_find_res_by_name(struct udevice *dev,
+							     const char *name)
+{
+	return NULL;
+}
 #endif
 
 #endif	/* _RPROC_H_ */
diff --git a/include/rproc_virtio.h b/include/rproc_virtio.h
new file mode 100644
index 0000000000..cbe8ff420f
--- /dev/null
+++ b/include/rproc_virtio.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023, Advanced Micro Devices Inc.
+ */
+
+#ifndef _RPROC_VIRTIO_H_
+#define _RPROC_VIRTIO_H_
+
+#include <remoteproc.h>
+#include <dm/device.h>
+
+void rproc_flush_dcache(struct udevice *dev);
+
+#ifndef CONFIG_SANDBOX
+
+int rproc_virtio_create_dev(struct udevice *parent, struct fw_rsc_vdev *rsc,
+			    int offset);
+
+#else
+
+int rproc_virtio_create_dev(struct udevice *parent, struct fw_rsc_vdev *rsc,
+			    int offset)
+{
+	return -ENODEV;
+}
+
+#endif /* CONFIG_SANDBOX */
+
+#endif /* _RPROC_VIRTIO_H_ */
diff --git a/include/virtio.h b/include/virtio.h
index 062a24630c..16d0f8aa7f 100644
--- a/include/virtio.h
+++ b/include/virtio.h
@@ -69,6 +69,9 @@
 /* v1.0 compliant */
 #define VIRTIO_F_VERSION_1		32
 
+/* packed virtqueue layout */
+#define VIRTIO_F_RING_PACKED		34
+
 /*
  * If clear - device has the IOMMU bypass quirk feature.
  * If set - use platform tools to detect the IOMMU.
diff --git a/include/virtio_ring.h b/include/virtio_ring.h
index e8e91044a2..4a9b4078ee 100644
--- a/include/virtio_ring.h
+++ b/include/virtio_ring.h
@@ -2,6 +2,7 @@
 /*
  * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen at iki.fi>
  * Copyright (C) 2018, Bin Meng <bmeng.cn at gmail.com>
+ * Copyright (C) 2023, Advanced Micro Devices Inc.
  *
  * From Linux kernel include/uapi/linux/virtio_ring.h
  */
@@ -227,6 +228,22 @@ void virtqueue_kick(struct virtqueue *vq);
  */
 void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
 
+/**
+ * vring_new_virtqueue - create a virtqueue at user defined vring address
+ *
+ * @index:	the index of the queue
+ * @vring:	vring created at user defined address
+ * @udev:	the virtio transport udevice
+ * @return: the virtqueue pointer or NULL if failed
+ *
+ * This creates a virtqueue using vring address decided by the user of API
+ *
+ * This API is supposed to be called by the virtio transport driver in the
+ * virtio find_vqs() uclass method.
+ */
+struct virtqueue *vring_new_virtqueue(unsigned int index, struct vring vring,
+				      struct udevice *udev);
+
 /**
  * vring_create_virtqueue - create a virtqueue for a virtio device
  *
-- 
2.25.1



More information about the U-Boot mailing list