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