This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit cee8d23b5833031a8318ee895e16618f131cffd9 Author: Yongrong Wang <[email protected]> AuthorDate: Thu May 22 19:37:00 2025 +0800 drivers/rpmsg/rpmsg_virtio: set the rx callback before the vring is live rpmsg_virtio replaced openamp's rx callback with its own only after rpmsg_init_vdev_with_config() returned, so an rx interrupt arriving in between ran openamp's handler instead of the rpmsg_virtio one. Pass the callbacks through the config so they are in place from the start, and have the rx path use the virtqueue it was called with: rvdev->rvq is not set yet when such an early interrupt comes in. Signed-off-by: Yongrong Wang <[email protected]> Signed-off-by: wangshaoxin <[email protected]> Signed-off-by: Bowen Wang <[email protected]> --- drivers/rpmsg/rpmsg_virtio.c | 97 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 12 deletions(-) diff --git a/drivers/rpmsg/rpmsg_virtio.c b/drivers/rpmsg/rpmsg_virtio.c index db17cb55696..962bf38bcec 100644 --- a/drivers/rpmsg/rpmsg_virtio.c +++ b/drivers/rpmsg/rpmsg_virtio.c @@ -71,8 +71,6 @@ struct rpmsg_virtio_priv_s sem_t semrx; sem_t semtx; pid_t tid; - vq_callback cbrx; - vq_callback cbtx; vq_notify notifytx; uint16_t headrx; #ifdef CONFIG_RPMSG_VIRTIO_PM @@ -252,10 +250,87 @@ static bool rpmsg_virtio_is_recursive(FAR struct rpmsg_virtio_priv_s *priv) static void rpmsg_virtio_rx_worker(FAR struct rpmsg_virtio_priv_s *priv) { - if (rpmsg_virtio_available_rx(priv)) + FAR struct virtio_device *vdev = priv->vdev; + FAR struct rpmsg_virtio_device *rvdev = vdev->priv; + FAR struct rpmsg_device *rdev = &rvdev->rdev; + FAR struct rpmsg_endpoint *ept; + FAR struct rpmsg_hdr *rp_hdr; + bool release = false; + bool last = false; + uint32_t len; + uint16_t idx; + int status; + + if (!rpmsg_virtio_available_rx(priv)) { - priv->cbrx(priv->rvdev.rvq); + return; } + + metal_mutex_acquire(&rdev->lock); + while (!last) + { + /* Process the received data from remote node */ + + rp_hdr = rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx, &last); + if (!rp_hdr) + { + break; + } + + rp_hdr->reserved = idx; + + /* Get the channel node from the remote device channels list; drop a + * message whose length does not fit its buffer. + */ + + ept = len >= sizeof(*rp_hdr) && + rp_hdr->len <= len - sizeof(*rp_hdr) ? + rpmsg_get_ept_from_addr(rdev, rp_hdr->dst) : NULL; + rpmsg_ept_incref(ept); + RPMSG_BUF_HELD_INC(rp_hdr); + metal_mutex_release(&rdev->lock); + + if (ept) + { + if (ept->dest_addr == RPMSG_ADDR_ANY) + { + /* First message received from the remote side, + * update channel destination address + */ + + ept->dest_addr = rp_hdr->src; + } + + status = ept->cb(ept, RPMSG_LOCATE_DATA(rp_hdr), + rp_hdr->len, rp_hdr->src, ept->priv); + + RPMSG_ASSERT(status >= 0 || + status == RPMSG_SUCCESS_BUFFER_RELEASED, + "unexpected callback status\r\n"); + } + else + { + status = RPMSG_SUCCESS; + } + + metal_mutex_acquire(&rdev->lock); + rpmsg_ept_decref(ept); + if (status != RPMSG_SUCCESS_BUFFER_RELEASED && + rpmsg_virtio_buf_held_dec_test(rp_hdr)) + { + rpmsg_virtio_release_rx_buffer_nolock(rvdev, rp_hdr); + release = true; + } + } + + if (release) + { + /* tell peer we return some rx buffer */ + + virtqueue_kick(rvdev->rvq); + } + + metal_mutex_release(&rdev->lock); } /**************************************************************************** @@ -448,10 +523,10 @@ static void rpmsg_virtio_dump(FAR struct rpmsg_s *rpmsg) * Name: rpmsg_virtio_update_rx ****************************************************************************/ -static void rpmsg_virtio_update_rx(FAR struct rpmsg_virtio_priv_s *priv) +static void rpmsg_virtio_update_rx(FAR struct rpmsg_virtio_priv_s *priv, + FAR struct virtqueue *rvq) { FAR struct rpmsg_virtio_device *rvdev = &priv->rvdev; - FAR struct virtqueue *rvq = rvdev->rvq; if (rpmsg_virtio_get_role(rvdev) == RPMSG_HOST) { @@ -474,7 +549,7 @@ static void rpmsg_virtio_rx_callback(FAR struct virtqueue *vq) FAR struct rpmsg_virtio_priv_s *priv = metal_container_of(vq->vq_dev->priv, struct rpmsg_virtio_priv_s, rvdev); - rpmsg_virtio_update_rx(priv); + rpmsg_virtio_update_rx(priv, vq); rpmsg_virtio_wakeup_rx(priv); } @@ -550,6 +625,8 @@ static int rpmsg_virtio_start(FAR struct rpmsg_virtio_priv_s *priv) RPMSG_BUFFER_SIZE, RPMSG_BUFFER_SIZE, false, + rpmsg_virtio_rx_callback, + rpmsg_virtio_tx_callback, }; int ret; @@ -602,18 +679,14 @@ static int rpmsg_virtio_start(FAR struct rpmsg_virtio_priv_s *priv) return ret; } - priv->cbrx = priv->rvdev.rvq->callback; - priv->cbtx = priv->rvdev.svq->callback; priv->notifytx = priv->rvdev.svq->notify; - priv->rvdev.rvq->callback = rpmsg_virtio_rx_callback; - priv->rvdev.svq->callback = rpmsg_virtio_tx_callback; priv->rvdev.svq->notify = rpmsg_virtio_tx_notify; priv->rvdev.notify_wait_cb = rpmsg_virtio_notify_wait; priv->rvdev.rdev.ns_unbind_cb = rpmsg_ns_unbind; /* Wake up the rx thread to process message */ - rpmsg_virtio_update_rx(priv); + rpmsg_virtio_update_rx(priv, priv->rvdev.rvq); rpmsg_virtio_wakeup_rx(priv); /* Open tx buffer return callback before the services created below can
