diff --git a/lib/include/openamp/remoteproc.h b/lib/include/openamp/remoteproc.h index 41f5d5741..5a3392990 100644 --- a/lib/include/openamp/remoteproc.h +++ b/lib/include/openamp/remoteproc.h @@ -411,6 +411,18 @@ struct remoteproc_ops { int (*stop)(struct remoteproc *rproc); int (*shutdown)(struct remoteproc *rproc); int (*notify)(struct remoteproc *rproc, uint32_t id); + /** + * notify_wait + * + * Wait for remote notified, when there is no TX buffer anymore. + * Set to NULL means use usleep to wait TX buffer available. + * + * @rproc - pointer to remoteproc instance + * @id - the notifyid + * + * return 0 means there is notify available, otherwise negative value. + */ + int (*notify_wait)(struct remoteproc *rproc, uint32_t id); /** * get_mem * diff --git a/lib/include/openamp/remoteproc_virtio.h b/lib/include/openamp/remoteproc_virtio.h index a5c609308..02d2f5a6f 100644 --- a/lib/include/openamp/remoteproc_virtio.h +++ b/lib/include/openamp/remoteproc_virtio.h @@ -22,6 +22,7 @@ extern "C" { /* define vdev notification function user should implement */ typedef int (*rpvdev_notify_func)(void *priv, uint32_t id); +typedef int (*rpvdev_notify_wait)(void *priv, uint32_t id); /** * struct remoteproc_virtio @@ -37,6 +38,7 @@ struct remoteproc_virtio { void *vdev_rsc; struct metal_io_region *vdev_rsc_io; rpvdev_notify_func notify; + rpvdev_notify_wait notify_wait; struct virtio_device vdev; struct metal_list node; }; diff --git a/lib/include/openamp/rpmsg.h b/lib/include/openamp/rpmsg.h index 5b2d5bed8..76e26ed74 100644 --- a/lib/include/openamp/rpmsg.h +++ b/lib/include/openamp/rpmsg.h @@ -42,6 +42,7 @@ extern "C" { #define RPMSG_ERR_BUFF_SIZE (RPMSG_ERROR_BASE - 5) #define RPMSG_ERR_INIT (RPMSG_ERROR_BASE - 6) #define RPMSG_ERR_ADDR (RPMSG_ERROR_BASE - 7) +#define RPMSG_ERR_NXIO (RPMSG_ERROR_BASE - 8) struct rpmsg_endpoint; struct rpmsg_device; diff --git a/lib/include/openamp/rpmsg_virtio.h b/lib/include/openamp/rpmsg_virtio.h index ff1e17119..7c0d8714e 100644 --- a/lib/include/openamp/rpmsg_virtio.h +++ b/lib/include/openamp/rpmsg_virtio.h @@ -140,6 +140,15 @@ rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, callbacks); } +static inline int +rpmsg_virtio_notify_wait(struct rpmsg_virtio_device *rvdev, + struct virtqueue *vq) +{ + return rvdev->vdev->func->notify_wait ? + rvdev->vdev->func->notify_wait(rvdev->vdev, vq) : + RPMSG_ERR_NXIO; +} + /** * rpmsg_virtio_get_buffer_size - get rpmsg virtio buffer size * diff --git a/lib/include/openamp/virtio.h b/lib/include/openamp/virtio.h index 916132b47..0303a5b3b 100644 --- a/lib/include/openamp/virtio.h +++ b/lib/include/openamp/virtio.h @@ -162,6 +162,7 @@ struct virtio_dispatch { void *src, int length); void (*reset_device)(struct virtio_device *dev); void (*notify)(struct virtqueue *vq); + int (*notify_wait)(struct virtio_device *dev, struct virtqueue *vq); }; int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, diff --git a/lib/remoteproc/remoteproc.c b/lib/remoteproc/remoteproc.c index 9a0cf3e01..4c101dbbf 100644 --- a/lib/remoteproc/remoteproc.c +++ b/lib/remoteproc/remoteproc.c @@ -880,6 +880,16 @@ static int remoteproc_virtio_notify(void *priv, uint32_t id) return 0; } +static int remoteproc_virtio_notify_wait(void *priv, uint32_t id) +{ + struct remoteproc *rproc = priv; + + if (rproc->ops->notify_wait) + return rproc->ops->notify_wait(rproc, id); + + return 0; +} + struct virtio_device * remoteproc_create_virtio(struct remoteproc *rproc, int vdev_id, unsigned int role, @@ -927,6 +937,7 @@ remoteproc_create_virtio(struct remoteproc *rproc, rproc_virtio_wait_remote_ready(vdev); 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; diff --git a/lib/remoteproc/remoteproc_virtio.c b/lib/remoteproc/remoteproc_virtio.c index a623276ea..9b1b067dc 100644 --- a/lib/remoteproc/remoteproc_virtio.c +++ b/lib/remoteproc/remoteproc_virtio.c @@ -30,6 +30,19 @@ static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) rpvdev->notify(rpvdev->priv, vring_info->notifyid); } +static int rproc_virtio_notify_wait(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->notify_wait(rpvdev->priv, vring_info->notifyid); +} + static unsigned char rproc_virtio_get_status(struct virtio_device *vdev) { struct remoteproc_virtio *rpvdev; @@ -179,6 +192,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, + .notify_wait = rproc_virtio_notify_wait, #ifndef VIRTIO_DEVICE_ONLY /* * We suppose here that the vdev is in a shared memory so that can diff --git a/lib/rpmsg/rpmsg_virtio.c b/lib/rpmsg/rpmsg_virtio.c index cd08f40b7..d2518a696 100644 --- a/lib/rpmsg/rpmsg_virtio.c +++ b/lib/rpmsg/rpmsg_virtio.c @@ -347,6 +347,13 @@ 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_notify_wait(rvdev, rvdev->rvq); + if (status == RPMSG_SUCCESS) + continue; + else if (status != RPMSG_ERR_NXIO) + break; + metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL); tick_count--; }