From 3ed768a2ce3b35e64c56cd69eb48e4436bdc4c12 Mon Sep 17 00:00:00 2001 From: wangbowen6 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 --- 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 #include +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