| From 3ed768a2ce3b35e64c56cd69eb48e4436bdc4c12 Mon Sep 17 00:00:00 2001 |
| From: wangbowen6 <wangbowen6@xiaomi.com> |
| Date: Tue, 9 May 2023 12:53:21 +0800 |
| Subject: [PATCH 2/2] virtio: decoupling the transport layer and virtio device |
| layer |
| |
| 1. Add virtio device api to decouple the transport layer and virtio |
| device layer. |
| 2. Move the vrings info and virtqueue allocation/free to the |
| remoteproc transport layer; |
| 3. Because 2, modify the rpmsg device also; |
| |
| Change-Id: Ideb5fc388dd1626ce4ac1efd4c5120863918057b |
| Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com> |
| --- |
| lib/include/openamp/rpmsg_virtio.h | 10 +- |
| lib/include/openamp/virtio.h | 128 +++++++++++++++++++- |
| lib/remoteproc/remoteproc.c | 32 ----- |
| lib/remoteproc/remoteproc_virtio.c | 188 +++++++++++++++++++++-------- |
| lib/rpmsg/rpmsg_virtio.c | 29 ++++- |
| lib/virtio/virtio.c | 40 ------ |
| 6 files changed, 293 insertions(+), 134 deletions(-) |
| |
| diff --git a/lib/include/openamp/rpmsg_virtio.h open-amp/lib/include/openamp/rpmsg_virtio.h |
| index bdc6cc6..e2d166f 100644 |
| --- a/lib/include/openamp/rpmsg_virtio.h |
| +++ open-amp/lib/include/openamp/rpmsg_virtio.h |
| @@ -144,8 +144,14 @@ rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, |
| const char *names[], |
| vq_callback *callbacks) |
| { |
| - return virtio_create_virtqueues(rvdev->vdev, flags, nvqs, names, |
| - callbacks); |
| + return rvdev->vdev->func->create_virtqueues(rvdev->vdev, flags, nvqs, |
| + names, callbacks); |
| +} |
| + |
| +static inline void |
| +rpmsg_virtio_delete_virtqueues(struct rpmsg_virtio_device *rvdev) |
| +{ |
| + rvdev->vdev->func->delete_virtqueues(rvdev->vdev); |
| } |
| |
| static inline int |
| diff --git a/lib/include/openamp/virtio.h open-amp/lib/include/openamp/virtio.h |
| index 3001a06..fb68c19 100644 |
| --- a/lib/include/openamp/virtio.h |
| +++ open-amp/lib/include/openamp/virtio.h |
| @@ -161,6 +161,11 @@ void virtio_describe(struct virtio_device *dev, const char *msg, |
| */ |
| |
| struct virtio_dispatch { |
| + int (*create_virtqueues)(struct virtio_device *vdev, |
| + unsigned int flags, |
| + unsigned int nvqs, const char *names[], |
| + vq_callback callbacks[]); |
| + void (*delete_virtqueues)(struct virtio_device *vdev); |
| uint8_t (*get_status)(struct virtio_device *dev); |
| void (*set_status)(struct virtio_device *dev, uint8_t status); |
| uint32_t (*get_features)(struct virtio_device *dev); |
| @@ -182,9 +187,126 @@ struct virtio_dispatch { |
| int (*notify_wait)(struct virtio_device *dev, struct virtqueue *vq); |
| }; |
| |
| -int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, |
| - unsigned int nvqs, const char *names[], |
| - vq_callback callbacks[]); |
| +/** |
| + * @brief Create the virtio device virtqueue. |
| + * |
| + * @param vdev Pointer to virtio device structure. |
| + * @param flags Create flag. |
| + * @param nvqs The virtqueue number. |
| + * @param names Virtqueue names. |
| + * @param callbacks Virtqueue callback functions. |
| + * |
| + * @return Pointer to virtio device structure. |
| + */ |
| +static inline int virtio_create_virtqueues(struct virtio_device *vdev, |
| + unsigned int flags, |
| + unsigned int nvqs, |
| + const char *names[], |
| + vq_callback callbacks[]) |
| +{ |
| + return vdev->func->create_virtqueues(vdev, flags, nvqs, names, |
| + callbacks); |
| +} |
| + |
| +/** |
| + * @brief Delete the virtio device virtqueue. |
| + * |
| + * @param vdev Pointer to virtio device structure. |
| + * |
| + * @return pointer to virtio device structure. |
| + */ |
| +static inline void virtio_delete_virtqueues(struct virtio_device *vdev) |
| +{ |
| + return vdev->func->delete_virtqueues(vdev); |
| +} |
| + |
| +/** |
| + * @brief Retrieve device status. |
| + * |
| + * @param dev Pointer to device structure. |
| + * |
| + * @return status of the device. |
| + */ |
| +static inline uint8_t virtio_get_status(struct virtio_device *vdev) |
| +{ |
| + return vdev->func->get_status(vdev); |
| +} |
| + |
| +/** |
| + * @brief Set device status. |
| + * |
| + * @param dev Pointer to device structure. |
| + * @param status Value to be set as device status. |
| + */ |
| +static inline void virtio_set_status(struct virtio_device *vdev, |
| + uint8_t status) |
| +{ |
| + vdev->func->set_status(vdev, status); |
| +} |
| + |
| +/** |
| + * @brief Retrieve configuration data from the device. |
| + * |
| + * @param dev Pointer to device structure. |
| + * @param offset Offset of the data within the configuration area. |
| + * @param dst Address of the buffer that will hold the data. |
| + * @param len Length of the data to be retrieved. |
| + */ |
| +static inline void virtio_read_config(struct virtio_device *vdev, |
| + uint32_t offset, void *dst, |
| + int length) |
| +{ |
| + vdev->func->read_config(vdev, offset, dst, length); |
| +} |
| + |
| +/** |
| + * @brief Write configuration data to the device. |
| + * |
| + * @param dev Pointer to device structure. |
| + * @param offset Offset of the data within the configuration area. |
| + * @param src Address of the buffer that holds the data to write. |
| + * @param len Length of the data to be written. |
| + */ |
| +static inline void virtio_write_config(struct virtio_device *vdev, |
| + uint32_t offset, void *src, |
| + int length) |
| +{ |
| + vdev->func->write_config(vdev, offset, src, length); |
| +} |
| + |
| +/** |
| + * @brief Get the virtio device features. |
| + * |
| + * @param[in] dev Pointer to device structure. |
| + * |
| + * @return Features supported by both the driver and the device as a bitfield. |
| + */ |
| +static inline uint32_t virtio_get_features(struct virtio_device *vdev) |
| +{ |
| + return vdev->func->get_features(vdev); |
| +} |
| + |
| +/** |
| + * @brief Set features supported by the VIRTIO driver. |
| + * |
| + * @param dev Pointer to device structure. |
| + * @param features Features supported by the driver as a bitfield. |
| + */ |
| +static inline void virtio_set_features(struct virtio_device *vdev, |
| + uint32_t features) |
| +{ |
| + return vdev->func->set_features(vdev, features); |
| +} |
| + |
| +/** |
| + * @brief Reset virtio device. |
| + * |
| + * @param vdev Pointer to virtio_device structure. |
| + */ |
| +static inline void virtio_reset_device(struct virtio_device *vdev) |
| +{ |
| + vdev->func->reset_device(vdev); |
| +} |
| |
| #if defined __cplusplus |
| } |
| diff --git a/lib/remoteproc/remoteproc.c open-amp/lib/remoteproc/remoteproc.c |
| index 001b11b..5a38fe1 100644 |
| --- a/lib/remoteproc/remoteproc.c |
| +++ open-amp/lib/remoteproc/remoteproc.c |
| @@ -921,7 +921,6 @@ remoteproc_create_virtio(struct remoteproc *rproc, |
| struct remoteproc_virtio *rpvdev; |
| size_t vdev_rsc_offset; |
| unsigned int notifyid; |
| - unsigned int num_vrings, i; |
| struct metal_list *node; |
| |
| #ifdef VIRTIO_DRIVER_ONLY |
| @@ -969,39 +968,8 @@ remoteproc_create_virtio(struct remoteproc *rproc, |
| rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); |
| rpvdev->notify_wait = remoteproc_virtio_notify_wait; |
| metal_list_add_tail(&rproc->vdevs, &rpvdev->node); |
| - num_vrings = vdev_rsc->num_of_vrings; |
| - |
| - /* set the notification id for vrings */ |
| - for (i = 0; i < num_vrings; i++) { |
| - struct fw_rsc_vdev_vring *vring_rsc; |
| - metal_phys_addr_t da; |
| - unsigned int num_descs, align; |
| - struct metal_io_region *io; |
| - void *va; |
| - size_t size; |
| - int ret; |
| - |
| - vring_rsc = &vdev_rsc->vring[i]; |
| - notifyid = vring_rsc->notifyid; |
| - da = vring_rsc->da; |
| - num_descs = vring_rsc->num; |
| - align = vring_rsc->align; |
| - size = vring_size(num_descs, align); |
| - va = remoteproc_mmap(rproc, NULL, &da, size, 0, &io); |
| - if (!va) |
| - goto err1; |
| - ret = rproc_virtio_init_vring(vdev, i, notifyid, |
| - va, io, num_descs, align); |
| - if (ret) |
| - goto err1; |
| - } |
| metal_mutex_release(&rproc->lock); |
| return vdev; |
| - |
| -err1: |
| - remoteproc_remove_virtio(rproc, vdev); |
| - metal_mutex_release(&rproc->lock); |
| - return NULL; |
| } |
| |
| void remoteproc_remove_virtio(struct remoteproc *rproc, |
| diff --git a/lib/remoteproc/remoteproc_virtio.c open-amp/lib/remoteproc/remoteproc_virtio.c |
| index 4375c4c..96767c1 100644 |
| --- a/lib/remoteproc/remoteproc_virtio.c |
| +++ open-amp/lib/remoteproc/remoteproc_virtio.c |
| @@ -16,6 +16,139 @@ |
| #include <metal/utilities.h> |
| #include <metal/alloc.h> |
| |
| +static void rproc_virtio_delete_virtqueues(struct virtio_device *vdev) |
| +{ |
| + struct virtio_vring_info *vring_info; |
| + unsigned int i; |
| + |
| + if (vdev->vrings_info != NULL) { |
| + for (i = 0; i < vdev->vrings_num; i++) { |
| + vring_info = &vdev->vrings_info[i]; |
| + if (vring_info->vq != NULL) { |
| + virtqueue_free(vring_info->vq); |
| + } |
| + } |
| + |
| + metal_free_memory(vdev->vrings_info); |
| + } |
| +} |
| + |
| +static int rproc_virtio_create_virtqueue(struct virtio_device *vdev, |
| + unsigned int flags, |
| + unsigned int i, |
| + const char *name, |
| + vq_callback callback) |
| +{ |
| + struct remoteproc_virtio *rpvdev; |
| + struct fw_rsc_vdev_vring *vring_rsc; |
| + struct fw_rsc_vdev *vdev_rsc; |
| + struct remoteproc *rproc; |
| + struct virtio_vring_info *vring_info; |
| + struct vring_alloc_info *vring_alloc; |
| + struct metal_io_region *io; |
| + metal_phys_addr_t da; |
| + size_t vringsize; |
| + void *va; |
| + int ret; |
| + |
| + /* Get remoteproc virtio device */ |
| + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); |
| + |
| + /* Get the remoteproc */ |
| + rproc = rpvdev->priv; |
| + |
| + /* Get the rsc table */ |
| + vdev_rsc = rpvdev->vdev_rsc; |
| + vring_rsc = &vdev_rsc->vring[i]; |
| + |
| + /* |
| + * Initialize the vring information according to the vring resource |
| + * table. |
| + */ |
| + da = vring_rsc->da; |
| + vringsize = vring_size(vring_rsc->num, vring_rsc->align); |
| + va = remoteproc_mmap(rproc, NULL, &da, vringsize, 0, &io); |
| + if (!va) { |
| + return ERROR_VQUEUE_INVLD_PARAM; |
| + } |
| + |
| + ret = rproc_virtio_init_vring(vdev, i, vring_rsc->notifyid, va, io, |
| + vring_rsc->num, vring_rsc->align); |
| + if (ret) { |
| + return ret; |
| + } |
| + |
| + /* Get the vring information */ |
| + vring_info = &vdev->vrings_info[i]; |
| + vring_alloc = &vring_info->info; |
| + |
| + /* Alloc the virtqueue and init it */ |
| + vring_info->vq = virtqueue_allocate(vring_alloc->num_descs); |
| + if (!vring_info->vq) { |
| + return ERROR_NO_MEM; |
| + } |
| + |
| +#ifndef VIRTIO_DEVICE_ONLY |
| + if (vdev->role == VIRTIO_DEV_DRIVER) { |
| + size_t offset = metal_io_virt_to_offset(vring_info->io, |
| + vring_alloc->vaddr); |
| + metal_io_block_set(vring_info->io, offset, 0, vringsize); |
| + } |
| +#endif |
| + ret = virtqueue_create(vdev, i, name, vring_alloc, callback, |
| + vdev->func->notify, vring_info->vq); |
| + if (ret) { |
| + return ret; |
| + } |
| + return 0; |
| +} |
| + |
| +static int rproc_virtio_create_virtqueues(struct virtio_device *vdev, |
| + unsigned int flags, |
| + unsigned int nvqs, |
| + const char *names[], |
| + vq_callback callbacks[]) |
| +{ |
| + struct remoteproc_virtio *rpvdev; |
| + struct virtio_vring_info *vrings_info; |
| + struct fw_rsc_vdev *vdev_rsc; |
| + unsigned int i; |
| + int ret; |
| + (void)flags; |
| + |
| + /* Get remoteproc virtio device, rsc table, remoteproc */ |
| + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); |
| + vdev_rsc = rpvdev->vdev_rsc; |
| + |
| + /* Check vrings number */ |
| + if (nvqs > vdev_rsc->num_of_vrings) |
| + return ERROR_VQUEUE_INVLD_PARAM; |
| + |
| + /* Alloc vrings info for the virtio device */ |
| + vrings_info = metal_allocate_memory(sizeof(*vrings_info) * nvqs); |
| + if (!vrings_info) { |
| + return ERROR_NO_MEM; |
| + } |
| + |
| + memset(vrings_info, 0, sizeof(*vrings_info) * nvqs); |
| + vdev->vrings_info = vrings_info; |
| + vdev->vrings_num = nvqs; |
| + |
| + /* set the notification id for vrings */ |
| + for (i = 0; i < nvqs; i++) { |
| + ret = rproc_virtio_create_virtqueue(vdev, flags, i, names[i], |
| + callbacks[i]); |
| + if (ret) { |
| + goto err; |
| + } |
| + } |
| + return 0; |
| + |
| +err: |
| + rproc_virtio_delete_virtqueues(vdev); |
| + return ret; |
| +} |
| + |
| static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) |
| { |
| struct remoteproc_virtio *rpvdev; |
| @@ -148,7 +281,7 @@ static void rproc_virtio_read_config(struct virtio_device *vdev, |
| |
| rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); |
| vdev_rsc = rpvdev->vdev_rsc; |
| - config = (char *)(&vdev_rsc->vring[vdev->vrings_num]); |
| + config = (char *)(&vdev_rsc->vring[vdev_rsc->num_of_vrings]); |
| io = rpvdev->vdev_rsc_io; |
| |
| if (offset + length <= vdev_rsc->config_len) |
| @@ -168,7 +301,7 @@ static void rproc_virtio_write_config(struct virtio_device *vdev, |
| |
| rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); |
| vdev_rsc = rpvdev->vdev_rsc; |
| - config = (char *)(&vdev_rsc->vring[vdev->vrings_num]); |
| + config = (char *)(&vdev_rsc->vring[vdev_rsc->num_of_vrings]); |
| io = rpvdev->vdev_rsc_io; |
| |
| if (offset + length <= vdev_rsc->config_len) { |
| @@ -188,6 +321,8 @@ static void rproc_virtio_reset_device(struct virtio_device *vdev) |
| #endif |
| |
| static const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { |
| + .create_virtqueues = rproc_virtio_create_virtqueues, |
| + .delete_virtqueues = rproc_virtio_delete_virtqueues, |
| .get_status = rproc_virtio_get_status, |
| .get_features = rproc_virtio_get_features, |
| .read_config = rproc_virtio_read_config, |
| @@ -215,44 +350,16 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, |
| virtio_dev_reset_cb rst_cb) |
| { |
| struct remoteproc_virtio *rpvdev; |
| - struct virtio_vring_info *vrings_info; |
| struct fw_rsc_vdev *vdev_rsc = rsc; |
| struct virtio_device *vdev; |
| - unsigned int num_vrings = vdev_rsc->num_of_vrings; |
| - unsigned int i; |
| |
| rpvdev = metal_allocate_memory(sizeof(*rpvdev)); |
| if (!rpvdev) |
| return NULL; |
| - vrings_info = metal_allocate_memory(sizeof(*vrings_info) * num_vrings); |
| - if (!vrings_info) |
| - goto err0; |
| memset(rpvdev, 0, sizeof(*rpvdev)); |
| - memset(vrings_info, 0, sizeof(*vrings_info)); |
| vdev = &rpvdev->vdev; |
| - |
| - for (i = 0; i < num_vrings; i++) { |
| - struct virtqueue *vq; |
| -#ifndef VIRTIO_DEVICE_ONLY |
| - struct fw_rsc_vdev_vring *vring_rsc; |
| -#endif |
| - unsigned int num_extra_desc = 0; |
| - |
| -#ifndef VIRTIO_DEVICE_ONLY |
| - vring_rsc = &vdev_rsc->vring[i]; |
| - if (role == VIRTIO_DEV_DRIVER) { |
| - num_extra_desc = vring_rsc->num; |
| - } |
| -#endif |
| - vq = virtqueue_allocate(num_extra_desc); |
| - if (!vq) |
| - goto err1; |
| - vrings_info[i].vq = vq; |
| - } |
| - |
| rpvdev->notify = notify; |
| rpvdev->priv = priv; |
| - vdev->vrings_info = vrings_info; |
| /* Assuming the shared memory has been mapped and registered if |
| * necessary |
| */ |
| @@ -262,7 +369,6 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, |
| vdev->notifyid = notifyid; |
| vdev->role = role; |
| vdev->reset_cb = rst_cb; |
| - vdev->vrings_num = num_vrings; |
| vdev->func = &remoteproc_virtio_dispatch_funcs; |
| |
| #ifndef VIRTIO_DEVICE_ONLY |
| @@ -274,35 +380,15 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, |
| #endif |
| |
| return &rpvdev->vdev; |
| - |
| -err1: |
| - for (i = 0; i < num_vrings; i++) { |
| - if (vrings_info[i].vq) |
| - metal_free_memory(vrings_info[i].vq); |
| - } |
| - metal_free_memory(vrings_info); |
| -err0: |
| - metal_free_memory(rpvdev); |
| - return NULL; |
| } |
| |
| void rproc_virtio_remove_vdev(struct virtio_device *vdev) |
| { |
| struct remoteproc_virtio *rpvdev; |
| - unsigned int i; |
| |
| if (!vdev) |
| return; |
| rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); |
| - for (i = 0; i < vdev->vrings_num; i++) { |
| - struct virtqueue *vq; |
| - |
| - vq = vdev->vrings_info[i].vq; |
| - if (vq) |
| - metal_free_memory(vq); |
| - } |
| - if (vdev->vrings_info) |
| - metal_free_memory(vdev->vrings_info); |
| metal_free_memory(rpvdev); |
| } |
| |
| diff --git a/lib/rpmsg/rpmsg_virtio.c open-amp/lib/rpmsg/rpmsg_virtio.c |
| index 2f38faa..b30eccc 100644 |
| --- a/lib/rpmsg/rpmsg_virtio.c |
| +++ open-amp/lib/rpmsg/rpmsg_virtio.c |
| @@ -821,8 +821,6 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, |
| vq_names[1] = "tx_vq"; |
| callback[0] = rpmsg_virtio_rx_callback; |
| callback[1] = rpmsg_virtio_tx_callback; |
| - rvdev->rvq = vdev->vrings_info[0].vq; |
| - rvdev->svq = vdev->vrings_info[1].vq; |
| } |
| #endif /*!VIRTIO_DEVICE_ONLY*/ |
| |
| @@ -833,8 +831,6 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, |
| vq_names[1] = "rx_vq"; |
| callback[0] = rpmsg_virtio_tx_callback; |
| callback[1] = rpmsg_virtio_rx_callback; |
| - rvdev->rvq = vdev->vrings_info[1].vq; |
| - rvdev->svq = vdev->vrings_info[0].vq; |
| } |
| #endif /*!VIRTIO_DRIVER_ONLY*/ |
| rvdev->shbuf_io = shm_io; |
| @@ -846,6 +842,21 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, |
| if (status != RPMSG_SUCCESS) |
| return status; |
| |
| + /* Create virtqueue success, assign back the virtqueue */ |
| +#ifndef VIRTIO_DEVICE_ONLY |
| + if (role == RPMSG_HOST) { |
| + rvdev->rvq = vdev->vrings_info[0].vq; |
| + rvdev->svq = vdev->vrings_info[1].vq; |
| + } |
| +#endif /*!VIRTIO_DEVICE_ONLY*/ |
| + |
| +#ifndef VIRTIO_DRIVER_ONLY |
| + if (role == RPMSG_REMOTE) { |
| + rvdev->rvq = vdev->vrings_info[1].vq; |
| + rvdev->svq = vdev->vrings_info[0].vq; |
| + } |
| +#endif /*!VIRTIO_DRIVER_ONLY*/ |
| + |
| /* |
| * Suppress "tx-complete" interrupts |
| * since send method use busy loop when buffer pool exhaust |
| @@ -873,7 +884,8 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, |
| rvdev->config.r2h_buf_size); |
| |
| if (!buffer) { |
| - return RPMSG_ERR_NO_BUFF; |
| + status = RPMSG_ERR_NO_BUFF; |
| + goto err; |
| } |
| |
| vqbuf.buf = buffer; |
| @@ -887,7 +899,7 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, |
| buffer); |
| |
| if (status != RPMSG_SUCCESS) { |
| - return status; |
| + goto err; |
| } |
| } |
| } |
| @@ -912,6 +924,10 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, |
| #endif /*!VIRTIO_DEVICE_ONLY*/ |
| |
| return status; |
| + |
| +err: |
| + rpmsg_virtio_delete_virtqueues(rvdev); |
| + return status; |
| } |
| |
| void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev) |
| @@ -931,6 +947,7 @@ void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev) |
| rvdev->rvq = 0; |
| rvdev->svq = 0; |
| |
| + rpmsg_virtio_delete_virtqueues(rvdev); |
| metal_mutex_deinit(&rdev->lock); |
| } |
| } |
| diff --git a/lib/virtio/virtio.c open-amp/lib/virtio/virtio.c |
| index d25aec3..e67e97d 100644 |
| --- a/lib/virtio/virtio.c |
| +++ open-amp/lib/virtio/virtio.c |
| @@ -96,43 +96,3 @@ void virtio_describe(struct virtio_device *dev, const char *msg, |
| /* TODO: Not used currently - keeping it for future use*/ |
| virtio_feature_name(0, desc); |
| } |
| - |
| -int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, |
| - unsigned int nvqs, const char *names[], |
| - vq_callback callbacks[]) |
| -{ |
| - struct virtio_vring_info *vring_info; |
| - struct vring_alloc_info *vring_alloc; |
| - unsigned int num_vrings, i; |
| - int ret; |
| - (void)flags; |
| - |
| - num_vrings = vdev->vrings_num; |
| - if (nvqs > num_vrings) |
| - return ERROR_VQUEUE_INVLD_PARAM; |
| - /* Initialize virtqueue for each vring */ |
| - for (i = 0; i < nvqs; i++) { |
| - vring_info = &vdev->vrings_info[i]; |
| - |
| - vring_alloc = &vring_info->info; |
| -#ifndef VIRTIO_DEVICE_ONLY |
| - if (vdev->role == VIRTIO_DEV_DRIVER) { |
| - size_t offset; |
| - struct metal_io_region *io = vring_info->io; |
| - |
| - offset = metal_io_virt_to_offset(io, |
| - vring_alloc->vaddr); |
| - metal_io_block_set(io, offset, 0, |
| - vring_size(vring_alloc->num_descs, |
| - vring_alloc->align)); |
| - } |
| -#endif |
| - ret = virtqueue_create(vdev, i, names[i], vring_alloc, |
| - callbacks[i], vdev->func->notify, |
| - vring_info->vq); |
| - if (ret) |
| - return ret; |
| - } |
| - return 0; |
| -} |
| - |
| -- |
| 2.25.1 |
| |