From f81e22f183cf3582a3950b910ee3a5bfb891b548 Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Mon, 16 Oct 2023 10:42:38 +0800 Subject: [PATCH] remoteproc_virtio: optimize the remoteproc virtio transport layer 1. Implement the rproc_virtio_create_virtqueues() and rproc_virtio_delete_virtqueues(). 2. Because 1, also modified the rpmsg init. Signed-off-by: Bowen Wang --- lib/include/openamp/rpmsg_virtio.h | 73 +++++++++++++++- lib/remoteproc/remoteproc_virtio.c | 130 ++++++++++++++++++++--------- lib/rpmsg/rpmsg_virtio.c | 31 +++++-- 3 files changed, 186 insertions(+), 48 deletions(-) diff --git a/lib/include/openamp/rpmsg_virtio.h b/lib/include/openamp/rpmsg_virtio.h index ae2446638..58308f70a 100644 --- a/lib/include/openamp/rpmsg_virtio.h +++ b/lib/include/openamp/rpmsg_virtio.h @@ -118,29 +118,64 @@ __deprecated static inline int deprecated_rpmsg_slave(void) return RPMSG_REMOTE; } +/** + * @brief Get rpmsg virtio device role. + * + * @param rvdev Pointer to rpmsg virtio device. + * + * @return RPMSG_REMOTE or RPMSG_HOST + */ static inline unsigned int rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev) { return rvdev->vdev->role; } +/** + * @brief Set rpmsg virtio device status. + * + * @param rvdev Pointer to rpmsg virtio device. + * @param status Value to be set as rpmsg virtio device status. + */ static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev, uint8_t status) { rvdev->vdev->func->set_status(rvdev->vdev, status); } +/** + * @brief Retrieve rpmsg virtio device status. + * + * @param rvdev Pointer to rpmsg virtio device. + * + * @return The rpmsg virtio device status. + */ static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev) { return rvdev->vdev->func->get_status(rvdev->vdev); } +/** + * @brief Get the rpmsg virtio device features. + * + * @param rvdev Pointer to the rpmsg virtio device. + * + * @return The features supported by both the rpmsg driver and rpmsg device. + */ static inline uint32_t rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev) { return rvdev->vdev->func->get_features(rvdev->vdev); } +/** + * @brief Retrieve configuration data from the rpmsg virtio device. + * + * @param rvdev Pointer to the rpmsg virtio device. + * @param offset Offset of the data within the configuration area. + * @param dst Address of the buffer that will hold the data. + * @param length Length of the data to be retrieved. + */ static inline void rpmsg_virtio_read_config(struct rpmsg_virtio_device *rvdev, uint32_t offset, void *dst, int length) @@ -148,13 +183,34 @@ rpmsg_virtio_read_config(struct rpmsg_virtio_device *rvdev, rvdev->vdev->func->read_config(rvdev->vdev, offset, dst, length); } +/** + * @brief Write configuration data to the rpmsg virtio device. + * + * @param rvdev Pointer to the rpmsg virtio device. + * @param offset Offset of the data within the configuration area. + * @param src Address of the buffer that holds the data to write. + * @param length Length of the data to be written. + * + * @return 0 on success, otherwise error code. + */ static inline void rpmsg_virtio_write_config(struct rpmsg_virtio_device *rvdev, - uint32_t offset, void *dst, int length) + uint32_t offset, void *src, int length) { - rvdev->vdev->func->write_config(rvdev->vdev, offset, dst, length); + rvdev->vdev->func->write_config(rvdev->vdev, offset, src, length); } +/** + * @brief Create the rpmsg virtio device virtqueue. + * + * @param rvdev Pointer to the rpmsg virtio device. + * @param flags Create flag. + * @param nvqs The virtqueue number. + * @param names Virtqueue names. + * @param callbacks Virtqueue callback functions. + * + * @return 0 on success, otherwise error code. + */ static inline int rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, int flags, unsigned int nvqs, @@ -166,7 +222,18 @@ rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, } /** - * @brief Get rpmsg virtio Tx buffer size + * @brief Delete the virtqueues created in rpmsg_virtio_create_virtqueues() + * + * @param rvdev Pointer to the rpmsg virtio device + */ +static inline void +rpmsg_virtio_delete_virtqueues(struct rpmsg_virtio_device *rvdev) +{ + virtio_delete_virtqueues(rvdev->vdev); +} + +/** + * @brief Get rpmsg virtio buffer size * * @param rdev Pointer to the rpmsg device * diff --git a/lib/remoteproc/remoteproc_virtio.c b/lib/remoteproc/remoteproc_virtio.c index 74b799918..5a2da82b3 100644 --- a/lib/remoteproc/remoteproc_virtio.c +++ b/lib/remoteproc/remoteproc_virtio.c @@ -16,6 +16,89 @@ #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) + return; + + for (i = 0; i < vdev->vrings_num; i++) { + vring_info = &vdev->vrings_info[i]; + if (vring_info->vq) + virtqueue_free(vring_info->vq); + } +} + +static int rproc_virtio_create_virtqueue(struct virtio_device *vdev, + unsigned int flags, + unsigned int idx, + const char *name, + vq_callback callback) +{ + struct virtio_vring_info *vring_info; + struct vring_alloc_info *vring_alloc; + int ret; + (void)flags; + + /* Get the vring information */ + vring_info = &vdev->vrings_info[idx]; + vring_alloc = &vring_info->info; + + /* Fail if the virtqueue has already been created */ + if (vring_info->vq) + return ERROR_VQUEUE_INVLD_PARAM; + + /* 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); + size_t size = vring_size(vring_alloc->num_descs, vring_alloc->align); + + metal_io_block_set(vring_info->io, offset, 0, size); + } +#endif + ret = virtqueue_create(vdev, idx, 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[], + void *callback_args[]) +{ + unsigned int i; + int ret; + (void)callback_args; + + /* Check virtqueue numbers and the vrings_info */ + if (nvqs > vdev->vrings_num || !vdev || !vdev->vrings_info) + return ERROR_VQUEUE_INVLD_PARAM; + + /* 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; @@ -198,6 +281,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, @@ -229,46 +314,28 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, 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; + goto err; memset(rpvdev, 0, sizeof(*rpvdev)); memset(vrings_info, 0, sizeof(*vrings_info) * num_vrings); - 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; - } + /* Initialize the remoteproc virtio */ rpvdev->notify = notify; rpvdev->priv = priv; - vdev->vrings_info = vrings_info; /* Assuming the shared memory has been mapped and registered if * necessary */ rpvdev->vdev_rsc = vdev_rsc; rpvdev->vdev_rsc_io = rsc_io; + /* Initialize the virtio device */ + vdev = &rpvdev->vdev; + vdev->vrings_info = vrings_info; vdev->notifyid = notifyid; vdev->id.device = vdev_rsc->id; vdev->role = role; @@ -285,14 +352,7 @@ 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: +err: metal_free_memory(rpvdev); return NULL; } @@ -300,18 +360,10 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, 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 b/lib/rpmsg/rpmsg_virtio.c index 1384542e4..66623e54b 100644 --- a/lib/rpmsg/rpmsg_virtio.c +++ b/lib/rpmsg/rpmsg_virtio.c @@ -870,8 +870,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*/ @@ -882,8 +880,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; @@ -895,6 +891,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 @@ -922,7 +933,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; @@ -936,7 +948,7 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, buffer); if (status != RPMSG_SUCCESS) { - return status; + goto err; } } } @@ -960,7 +972,13 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, rpmsg_virtio_set_status(rvdev, VIRTIO_CONFIG_STATUS_DRIVER_OK); #endif /*!VIRTIO_DEVICE_ONLY*/ + return RPMSG_SUCCESS; + +#ifndef VIRTIO_DEVICE_ONLY +err: + rpmsg_virtio_delete_virtqueues(rvdev); return status; +#endif /*!VIRTIO_DEVICE_ONLY*/ } void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev) @@ -980,6 +998,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); } }