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

Reply via email to