diff mbox series

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

Message ID 20230725140650.951581-4-tanmay.shah@amd.com
State RFC
Delegated to: Tom Rini
Headers show
Series Add RPMsg framework | expand

Commit Message

Tanmay Shah July 25, 2023, 2:06 p.m. UTC
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@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

Comments

Simon Glass July 27, 2023, 12:50 a.m. UTC | #1
Hi Tanmay,

On Tue, 25 Jul 2023 at 08:08, Tanmay Shah <tanmay.shah@amd.com> wrote:
>
> 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@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

Can you split this patch up a bit? It seems to add a new method and
lots of other stuff.

>
> 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@amd.com>
> +S:     Maintained
> +F:     drivers/remoteproc/rproc_virtio.c
> +F:     include/rproc_virtio.h
> +
>  RISC-V
>  M:     Rick Chen <rick@andestech.com>
>  M:     Leo <ycliang@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)

Do we need ret?

> +                       return mapping;
> +       }
> +
> +       debug("%s: %s carveout not found\n", dev->name, name);

We typically put a blank line before the final return

> +       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))) {

Why the special case for sandbox? Can't it work like real hardware?

> +               return rproc_virtio_create_dev(dev, rsc, offset);
> +       }
> +
> +       /*
> +        * allocate the vrings traditional way
>          */

Single-line comment style

>         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)

if (!dcache_status())

> +               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);
> +       }
> +}

[..]

Regards,
Simon
diff mbox series

Patch

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@amd.com>
+S:	Maintained
+F:	drivers/remoteproc/rproc_virtio.c
+F:	include/rproc_virtio.h
+
 RISC-V
 M:	Rick Chen <rick@andestech.com>
 M:	Leo <ycliang@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@iki.fi>
  * Copyright (C) 2018, Bin Meng <bmeng.cn@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
  *