All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mathieu Poirier <mathieu.poirier@linaro.org>
To: patrick.oppenlander@gmail.com
Cc: linux-remoteproc@vger.kernel.org, andersson@kernel.org
Subject: Re: [PATCH] rpmsg: virtio: EPOLLOUT support
Date: Sun, 14 Dec 2025 18:04:43 -0700	[thread overview]
Message-ID: <aT9eq2AGdgXtppdT@p14s> (raw)
In-Reply-To: <20251022032817.320378-1-patrick.oppenlander@gmail.com>

On Wed, Oct 22, 2025 at 02:28:17PM +1100, patrick.oppenlander@gmail.com wrote:
> From: Patrick Oppenlander <patrick.oppenlander@gmail.com>
> 
> Previously, polling an rpmsg endpoint (e.g. /dev/ttyRPMSGx) would
> generate EPOLLIN events but no EPOLLOUT events.
> 
> Unfortunately, poll support means that we can no longer disable
> tx-complete interrupts as there is no way to know whether a poller is
> waiting in sendq, so we always need notifications.
> 
> Signed-off-by: Patrick Oppenlander <patrick.oppenlander@gmail.com>
> ---
>  drivers/rpmsg/virtio_rpmsg_bus.c | 101 ++++++++++---------------------
>  1 file changed, 32 insertions(+), 69 deletions(-)
>

As we previously agreed, I have added this patch to my tree under the condition
it doesn't break anything.  Let's see how things go.

Thanks,
Mathieu

 
> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> index 484890b4a6a74..79d983055b4d6 100644
> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> @@ -41,13 +41,12 @@
>   * @buf_size:   size of one rx or tx buffer
>   * @last_sbuf:	index of last tx buffer used
>   * @bufs_dma:	dma base addr of the buffers
> - * @tx_lock:	protects svq, sbufs and sleepers, to allow concurrent senders.
> + * @tx_lock:	protects svq and sbufs, to allow concurrent senders.
>   *		sending a message might require waking up a dozing remote
>   *		processor, which involves sleeping, hence the mutex.
>   * @endpoints:	idr of local endpoints, allows fast retrieval
>   * @endpoints_lock: lock of the endpoints set
>   * @sendq:	wait queue of sending contexts waiting for a tx buffers
> - * @sleepers:	number of senders that are waiting for a tx buffer
>   *
>   * This structure stores the rpmsg state of a given virtio remote processor
>   * device (there might be several virtio proc devices for each physical
> @@ -65,7 +64,6 @@ struct virtproc_info {
>  	struct idr endpoints;
>  	struct mutex endpoints_lock;
>  	wait_queue_head_t sendq;
> -	atomic_t sleepers;
>  };
>  
>  /* The feature bitmap for virtio rpmsg */
> @@ -144,6 +142,8 @@ static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len,
>  static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len);
>  static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
>  				  int len, u32 dst);
> +static __poll_t virtio_rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp,
> +				  poll_table *wait);
>  static ssize_t virtio_rpmsg_get_mtu(struct rpmsg_endpoint *ept);
>  static struct rpmsg_device *__rpmsg_create_channel(struct virtproc_info *vrp,
>  						   struct rpmsg_channel_info *chinfo);
> @@ -154,6 +154,7 @@ static const struct rpmsg_endpoint_ops virtio_endpoint_ops = {
>  	.sendto = virtio_rpmsg_sendto,
>  	.trysend = virtio_rpmsg_trysend,
>  	.trysendto = virtio_rpmsg_trysendto,
> +	.poll = virtio_rpmsg_poll,
>  	.get_mtu = virtio_rpmsg_get_mtu,
>  };
>  
> @@ -436,7 +437,6 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
>  	unsigned int len;
>  	void *ret;
>  
> -	/* support multiple concurrent senders */
>  	mutex_lock(&vrp->tx_lock);
>  
>  	/*
> @@ -454,62 +454,6 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
>  	return ret;
>  }
>  
> -/**
> - * rpmsg_upref_sleepers() - enable "tx-complete" interrupts, if needed
> - * @vrp: virtual remote processor state
> - *
> - * This function is called before a sender is blocked, waiting for
> - * a tx buffer to become available.
> - *
> - * If we already have blocking senders, this function merely increases
> - * the "sleepers" reference count, and exits.
> - *
> - * Otherwise, if this is the first sender to block, we also enable
> - * virtio's tx callbacks, so we'd be immediately notified when a tx
> - * buffer is consumed (we rely on virtio's tx callback in order
> - * to wake up sleeping senders as soon as a tx buffer is used by the
> - * remote processor).
> - */
> -static void rpmsg_upref_sleepers(struct virtproc_info *vrp)
> -{
> -	/* support multiple concurrent senders */
> -	mutex_lock(&vrp->tx_lock);
> -
> -	/* are we the first sleeping context waiting for tx buffers ? */
> -	if (atomic_inc_return(&vrp->sleepers) == 1)
> -		/* enable "tx-complete" interrupts before dozing off */
> -		virtqueue_enable_cb(vrp->svq);
> -
> -	mutex_unlock(&vrp->tx_lock);
> -}
> -
> -/**
> - * rpmsg_downref_sleepers() - disable "tx-complete" interrupts, if needed
> - * @vrp: virtual remote processor state
> - *
> - * This function is called after a sender, that waited for a tx buffer
> - * to become available, is unblocked.
> - *
> - * If we still have blocking senders, this function merely decreases
> - * the "sleepers" reference count, and exits.
> - *
> - * Otherwise, if there are no more blocking senders, we also disable
> - * virtio's tx callbacks, to avoid the overhead incurred with handling
> - * those (now redundant) interrupts.
> - */
> -static void rpmsg_downref_sleepers(struct virtproc_info *vrp)
> -{
> -	/* support multiple concurrent senders */
> -	mutex_lock(&vrp->tx_lock);
> -
> -	/* are we the last sleeping context waiting for tx buffers ? */
> -	if (atomic_dec_and_test(&vrp->sleepers))
> -		/* disable "tx-complete" interrupts */
> -		virtqueue_disable_cb(vrp->svq);
> -
> -	mutex_unlock(&vrp->tx_lock);
> -}
> -
>  /**
>   * rpmsg_send_offchannel_raw() - send a message across to the remote processor
>   * @rpdev: the rpmsg channel
> @@ -582,9 +526,6 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
>  
>  	/* no free buffer ? wait for one (but bail after 15 seconds) */
>  	while (!msg) {
> -		/* enable "tx-complete" interrupts, if not already enabled */
> -		rpmsg_upref_sleepers(vrp);
> -
>  		/*
>  		 * sleep until a free buffer is available or 15 secs elapse.
>  		 * the timeout period is not configurable because there's
> @@ -595,9 +536,6 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
>  					(msg = get_a_tx_buf(vrp)),
>  					msecs_to_jiffies(15000));
>  
> -		/* disable "tx-complete" interrupts if we're the last sleeper */
> -		rpmsg_downref_sleepers(vrp);
> -
>  		/* timeout ? */
>  		if (!err) {
>  			dev_err(dev, "timeout waiting for a tx buffer\n");
> @@ -676,6 +614,34 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
>  	return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
>  }
>  
> +static __poll_t virtio_rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp,
> +				  poll_table *wait)
> +{
> +	struct rpmsg_device *rpdev = ept->rpdev;
> +	struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
> +	struct virtproc_info *vrp = vch->vrp;
> +	__poll_t mask = 0;
> +
> +	poll_wait(filp, &vrp->sendq, wait);
> +
> +	/* support multiple concurrent senders */
> +	mutex_lock(&vrp->tx_lock);
> +
> +	/*
> +	 * check for a free buffer, either:
> +	 * - we haven't used all of the available transmit buffers (half of the
> +	 *   allocated buffers are used for transmit, hence num_bufs / 2), or,
> +	 * - we ask the virtqueue if there's a buffer available
> +	 */
> +	if (vrp->last_sbuf < vrp->num_bufs / 2 ||
> +	    !virtqueue_enable_cb(vrp->svq))
> +		mask |= EPOLLOUT;
> +
> +	mutex_unlock(&vrp->tx_lock);
> +
> +	return mask;
> +}
> +
>  static ssize_t virtio_rpmsg_get_mtu(struct rpmsg_endpoint *ept)
>  {
>  	struct rpmsg_device *rpdev = ept->rpdev;
> @@ -922,9 +888,6 @@ static int rpmsg_probe(struct virtio_device *vdev)
>  		WARN_ON(err); /* sanity check; this can't really happen */
>  	}
>  
> -	/* suppress "tx-complete" interrupts */
> -	virtqueue_disable_cb(vrp->svq);
> -
>  	vdev->priv = vrp;
>  
>  	rpdev_ctrl = rpmsg_virtio_add_ctrl_dev(vdev);
> -- 
> 2.51.1.dirty
> 

      parent reply	other threads:[~2025-12-15  1:04 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-22  3:28 [PATCH] rpmsg: virtio: EPOLLOUT support patrick.oppenlander
2025-10-22 13:35 ` Zhongqiu Han
2025-10-22 21:59   ` Patrick Oppenlander
2025-10-31 17:56     ` Mathieu Poirier
2025-10-31 21:28       ` Patrick Oppenlander
2025-11-10 15:28         ` Mathieu Poirier
2025-11-10 21:27           ` Patrick Oppenlander
2025-10-28 17:00 ` Mathieu Poirier
2025-10-28 20:54   ` Patrick Oppenlander
2025-12-15  1:04 ` Mathieu Poirier [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aT9eq2AGdgXtppdT@p14s \
    --to=mathieu.poirier@linaro.org \
    --cc=andersson@kernel.org \
    --cc=linux-remoteproc@vger.kernel.org \
    --cc=patrick.oppenlander@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.