From 8fb21ee138f62c8765fd13a5ed5ba5581227e815 Mon Sep 17 00:00:00 2001 From: Guiding Li Date: Thu, 18 Nov 2021 20:54:45 +0800 Subject: [PATCH] openamp: add new ops wait_notified() to avoid looping in tx buffer get Give users a chance to handle the no tx buffer situation when get tx buffer, with this patch, user can call rproc_virtio_set_wait_notified() to set the wait_notified() callback and this callback function will be called when no tx buffer in tx virtqueue. Signed-off-by: Guiding Li Signed-off-by: Bowen Wang --- lib/include/openamp/remoteproc.h | 12 +++++++++++ lib/include/openamp/remoteproc_virtio.h | 22 +++++++++++++++++++ lib/include/openamp/rpmsg_virtio.h | 9 ++++++++ lib/include/openamp/virtio.h | 1 + lib/remoteproc/remoteproc.c | 11 ++++++++++ lib/remoteproc/remoteproc_virtio.c | 28 +++++++++++++++++++++++++ lib/rpmsg/rpmsg_virtio.c | 5 +++++ 7 files changed, 88 insertions(+) diff --git a/lib/include/openamp/remoteproc.h b/lib/include/openamp/remoteproc.h index 23f917861..42475e4c3 100644 --- a/lib/include/openamp/remoteproc.h +++ b/lib/include/openamp/remoteproc.h @@ -462,6 +462,17 @@ struct remoteproc_ops { /** Notify the remote */ int (*notify)(struct remoteproc *rproc, uint32_t id); + /** + * @brief Wait for remote notified, when there is no TX buffer anymore. + * Set to NULL means use usleep to wait TX buffer available. + * + * @param rproc pointer to remoteproc instance + * @param id the notifyid + * + * return 0 means there is notify available, otherwise negative value. + */ + int (*wait_notified)(struct remoteproc *rproc, uint32_t id); + /** * @brief Get remoteproc memory I/O region by either name, virtual * address, physical address or device address. @@ -497,6 +508,7 @@ struct remoteproc_ops { #define RPROC_ERR_RSC_TAB_NP (RPROC_EBASE + 10) #define RPROC_ERR_RSC_TAB_NS (RPROC_EBASE + 11) #define RPROC_ERR_LOADER_STATE (RPROC_EBASE + 12) +#define RPROC_EXIO (RPROC_EBASE + 13) #define RPROC_EMAX (RPROC_EBASE + 16) #define RPROC_EPTR (void *)(-1) #define RPROC_EOF (void *)(-1) diff --git a/lib/include/openamp/remoteproc_virtio.h b/lib/include/openamp/remoteproc_virtio.h index 0b747cacc..1583ef17f 100644 --- a/lib/include/openamp/remoteproc_virtio.h +++ b/lib/include/openamp/remoteproc_virtio.h @@ -39,6 +39,12 @@ extern "C" { /* define vdev notification function user should implement */ typedef int (*rpvdev_notify_func)(void *priv, uint32_t id); +/* define vdev wait notified function, user can implement this + * function to wait peer return the tx buffer when no tx buffer found, + * and this is optional + */ +typedef int (*rpvdev_wait_notified_func)(void *priv, uint32_t id); + /** @brief Virtio structure for remoteproc instance */ struct remoteproc_virtio { /** Pointer to private data */ @@ -53,6 +59,9 @@ struct remoteproc_virtio { /** Notification function */ rpvdev_notify_func notify; + /** Wait notification function */ + rpvdev_wait_notified_func wait_notified; + /** Virtio device */ struct virtio_device vdev; @@ -126,6 +135,19 @@ int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid); */ void rproc_virtio_wait_remote_ready(struct virtio_device *vdev); +/** + * @brief set the remoteproc virtio notified function, this function will be + * called when no tx buffer to let user to handle the customisze buffer wait + * function. + * + * @param vdev Pointer to the virtio device + * @param wait_notified The wait notified callback function + * + * @return 0 for successful, negative value for failure + */ +int rproc_virtio_set_wait_notified(struct virtio_device *vdev, + rpvdev_wait_notified_func wait_notified); + #if defined __cplusplus } #endif diff --git a/lib/include/openamp/rpmsg_virtio.h b/lib/include/openamp/rpmsg_virtio.h index aea2edf56..fec5098df 100644 --- a/lib/include/openamp/rpmsg_virtio.h +++ b/lib/include/openamp/rpmsg_virtio.h @@ -165,6 +165,15 @@ rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, callbacks, NULL); } +static inline int +rpmsg_virtio_wait_notified(struct rpmsg_virtio_device *rvdev, + struct virtqueue *vq) +{ + return rvdev->vdev->func->wait_notified ? + rvdev->vdev->func->wait_notified(rvdev->vdev, vq) : + RPMSG_ERR_PERM; +} + /** * @brief Get rpmsg virtio buffer size * diff --git a/lib/include/openamp/virtio.h b/lib/include/openamp/virtio.h index c3185ac6b..5aa8a6191 100644 --- a/lib/include/openamp/virtio.h +++ b/lib/include/openamp/virtio.h @@ -275,6 +275,7 @@ struct virtio_dispatch { /** Notify the other side that a virtio vring as been updated. */ void (*notify)(struct virtqueue *vq); + int (*wait_notified)(struct virtio_device *dev, struct virtqueue *vq); }; /** diff --git a/lib/remoteproc/remoteproc.c b/lib/remoteproc/remoteproc.c index ad16a2d7e..5a4ce1b2a 100644 --- a/lib/remoteproc/remoteproc.c +++ b/lib/remoteproc/remoteproc.c @@ -900,6 +900,16 @@ static int remoteproc_virtio_notify(void *priv, uint32_t id) return 0; } +static int remoteproc_virtio_wait_notified(void *priv, uint32_t id) +{ + struct remoteproc *rproc = priv; + + if (rproc->ops->wait_notified) + return rproc->ops->wait_notified(rproc, id); + + return 0; +} + struct virtio_device * remoteproc_create_virtio(struct remoteproc *rproc, int vdev_id, unsigned int role, @@ -958,6 +968,7 @@ remoteproc_create_virtio(struct remoteproc *rproc, rproc_virtio_wait_remote_ready(vdev); rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + rpvdev->wait_notified = remoteproc_virtio_wait_notified; metal_list_add_tail(&rproc->vdevs, &rpvdev->node); num_vrings = vdev_rsc->num_of_vrings; diff --git a/lib/remoteproc/remoteproc_virtio.c b/lib/remoteproc/remoteproc_virtio.c index 7ef1064d8..515346880 100644 --- a/lib/remoteproc/remoteproc_virtio.c +++ b/lib/remoteproc/remoteproc_virtio.c @@ -30,6 +30,21 @@ static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) rpvdev->notify(rpvdev->priv, vring_info->notifyid); } +static int rproc_virtio_wait_notified(struct virtio_device *vdev, + struct virtqueue *vq) +{ + struct remoteproc_virtio *rpvdev; + struct virtio_vring_info *vring_info; + unsigned int vq_id = vq->vq_queue_index; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vring_info = &vdev->vrings_info[vq_id]; + + return rpvdev->wait_notified ? + rpvdev->wait_notified(rpvdev->priv, vring_info->notifyid) : + -RPROC_EXIO; +} + static unsigned char rproc_virtio_get_status(struct virtio_device *vdev) { struct remoteproc_virtio *rpvdev; @@ -187,6 +202,7 @@ static const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { .get_features = rproc_virtio_get_features, .read_config = rproc_virtio_read_config, .notify = rproc_virtio_virtqueue_notify, + .wait_notified = rproc_virtio_wait_notified, #ifndef VIRTIO_DEVICE_ONLY /* * We suppose here that the vdev is in a shared memory so that can @@ -364,3 +380,15 @@ void rproc_virtio_wait_remote_ready(struct virtio_device *vdev) metal_cpu_yield(); } } + +int rproc_virtio_set_wait_notified(struct virtio_device *vdev, + rpvdev_wait_notified_func wait_notified) +{ + struct remoteproc_virtio *rpvdev; + + if (!vdev || !wait_notified) + return -RPROC_EINVAL; + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + rpvdev->wait_notified = wait_notified; + return 0; +} diff --git a/lib/rpmsg/rpmsg_virtio.c b/lib/rpmsg/rpmsg_virtio.c index ea4cc0d9e..6cefe4b75 100644 --- a/lib/rpmsg/rpmsg_virtio.c +++ b/lib/rpmsg/rpmsg_virtio.c @@ -376,6 +376,11 @@ static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, metal_mutex_release(&rdev->lock); if (rp_hdr || !tick_count) break; + + status = rpmsg_virtio_wait_notified(rvdev, rvdev->rvq); + if (status == RPMSG_SUCCESS) + continue; + metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL); tick_count--; }