[PATCH net-next v2] virtio-net: xsk: Support wakeup on RX side

Bui Quang Minh posted 1 patch 1 month, 1 week ago
There is a newer version of this series
drivers/net/virtio_net.c | 35 +++++++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 8 deletions(-)
[PATCH net-next v2] virtio-net: xsk: Support wakeup on RX side
Posted by Bui Quang Minh 1 month, 1 week ago
When XDP_USE_NEED_WAKEUP is used and the fill ring is empty so no buffer
is allocated on RX side, allow RX NAPI to be descheduled. This avoids
wasting CPU cycles on polling. Users will be notified and they need to
make a wakeup call after refilling the ring.

Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
---
Changes in v2:
- Fix the flag check in virtnet_xsk_wakeup
- Link to v1: https://lore.kernel.org/netdev/20260227150949.13089-1-minhquangbui99@gmail.com/
---
 drivers/net/virtio_net.c | 35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index db88dcaefb20..3614002fc87c 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -1454,8 +1454,19 @@ static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue
 	xsk_buffs = rq->xsk_buffs;
 
 	num = xsk_buff_alloc_batch(pool, xsk_buffs, rq->vq->num_free);
-	if (!num)
+	if (!num) {
+		if (xsk_uses_need_wakeup(pool)) {
+			xsk_set_rx_need_wakeup(pool);
+			/* Return 0 instead of -ENOMEM so that NAPI is
+			 * descheduled.
+			 */
+			return 0;
+		}
+
 		return -ENOMEM;
+	} else {
+		xsk_clear_rx_need_wakeup(pool);
+	}
 
 	len = xsk_pool_get_rx_frame_size(pool) + vi->hdr_len;
 
@@ -1588,20 +1599,19 @@ static bool virtnet_xsk_xmit(struct send_queue *sq, struct xsk_buff_pool *pool,
 	return sent;
 }
 
-static void xsk_wakeup(struct send_queue *sq)
+static void xsk_wakeup(struct napi_struct *napi, struct virtqueue *vq)
 {
-	if (napi_if_scheduled_mark_missed(&sq->napi))
+	if (napi_if_scheduled_mark_missed(napi))
 		return;
 
 	local_bh_disable();
-	virtqueue_napi_schedule(&sq->napi, sq->vq);
+	virtqueue_napi_schedule(napi, vq);
 	local_bh_enable();
 }
 
 static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag)
 {
 	struct virtnet_info *vi = netdev_priv(dev);
-	struct send_queue *sq;
 
 	if (!netif_running(dev))
 		return -ENETDOWN;
@@ -1609,9 +1619,18 @@ static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag)
 	if (qid >= vi->curr_queue_pairs)
 		return -EINVAL;
 
-	sq = &vi->sq[qid];
+	if (flag & XDP_WAKEUP_TX) {
+		struct send_queue *sq = &vi->sq[qid];
+
+		xsk_wakeup(&sq->napi, sq->vq);
+	}
+
+	if (flag & XDP_WAKEUP_RX) {
+		struct receive_queue *rq = &vi->rq[qid];
+
+		xsk_wakeup(&rq->napi, rq->vq);
+	}
 
-	xsk_wakeup(sq);
 	return 0;
 }
 
@@ -1623,7 +1642,7 @@ static void virtnet_xsk_completed(struct send_queue *sq, int num)
 	 * wakeup the tx napi to consume the xsk tx queue, because the tx
 	 * interrupt may not be triggered.
 	 */
-	xsk_wakeup(sq);
+	xsk_wakeup(&sq->napi, sq->vq);
 }
 
 static int __virtnet_xdp_xmit_one(struct virtnet_info *vi,
-- 
2.43.0
Re: [PATCH net-next v2] virtio-net: xsk: Support wakeup on RX side
Posted by Jason Xing 1 month ago
On Tue, Mar 3, 2026 at 1:03 AM Bui Quang Minh <minhquangbui99@gmail.com> wrote:
>
> When XDP_USE_NEED_WAKEUP is used and the fill ring is empty so no buffer
> is allocated on RX side, allow RX NAPI to be descheduled. This avoids
> wasting CPU cycles on polling. Users will be notified and they need to
> make a wakeup call after refilling the ring.
>
> Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>

Thanks for handling that problem. Please carry my tag in the next version:

Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>

You seem to have forgotten to add Xuan Zhuo's tag...

Thanks,
Jason
Re: [PATCH net-next v2] virtio-net: xsk: Support wakeup on RX side
Posted by Bui Quang Minh 1 month ago
On 3/4/26 14:41, Jason Xing wrote:
> On Tue, Mar 3, 2026 at 1:03 AM Bui Quang Minh <minhquangbui99@gmail.com> wrote:
>> When XDP_USE_NEED_WAKEUP is used and the fill ring is empty so no buffer
>> is allocated on RX side, allow RX NAPI to be descheduled. This avoids
>> wasting CPU cycles on polling. Users will be notified and they need to
>> make a wakeup call after refilling the ring.
>>
>> Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
> Thanks for handling that problem. Please carry my tag in the next version:
>
> Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
>
> You seem to have forgotten to add Xuan Zhuo's tag...

This version contains a bug fix which is a non-trivial change so I think 
it might not be the same as the version that he approved of.

Thanks,
Quang Minh.
Re: [PATCH net-next v2] virtio-net: xsk: Support wakeup on RX side
Posted by Michael S. Tsirkin 1 month, 1 week ago
On Mon, Mar 02, 2026 at 11:41:58PM +0700, Bui Quang Minh wrote:
> When XDP_USE_NEED_WAKEUP is used and the fill ring is empty so no buffer
> is allocated on RX side, allow RX NAPI to be descheduled. This avoids
> wasting CPU cycles on polling. Users will be notified and they need to
> make a wakeup call after refilling the ring.
> 
> Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
> ---
> Changes in v2:
> - Fix the flag check in virtnet_xsk_wakeup
> - Link to v1: https://lore.kernel.org/netdev/20260227150949.13089-1-minhquangbui99@gmail.com/
> ---
>  drivers/net/virtio_net.c | 35 +++++++++++++++++++++++++++--------
>  1 file changed, 27 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index db88dcaefb20..3614002fc87c 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -1454,8 +1454,19 @@ static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue
>  	xsk_buffs = rq->xsk_buffs;
>  
>  	num = xsk_buff_alloc_batch(pool, xsk_buffs, rq->vq->num_free);
> -	if (!num)
> +	if (!num) {
> +		if (xsk_uses_need_wakeup(pool)) {
> +			xsk_set_rx_need_wakeup(pool);
> +			/* Return 0 instead of -ENOMEM so that NAPI is
> +			 * descheduled.
> +			 */
> +			return 0;

With this change, try_fill_recv() can return true even though zero RX
buffers were posted in need_wakeup mode, which contradicts its
documentation ("Returns false if we couldn't fill entirely (OOM)").

Methinks we need to at least update the comment near try_fill_recv.



> +		}
> +
>  		return -ENOMEM;
> +	} else {
> +		xsk_clear_rx_need_wakeup(pool);
> +	}
>  
>  	len = xsk_pool_get_rx_frame_size(pool) + vi->hdr_len;
>  
> @@ -1588,20 +1599,19 @@ static bool virtnet_xsk_xmit(struct send_queue *sq, struct xsk_buff_pool *pool,
>  	return sent;
>  }
>  
> -static void xsk_wakeup(struct send_queue *sq)
> +static void xsk_wakeup(struct napi_struct *napi, struct virtqueue *vq)
>  {
> -	if (napi_if_scheduled_mark_missed(&sq->napi))
> +	if (napi_if_scheduled_mark_missed(napi))
>  		return;
>  
>  	local_bh_disable();
> -	virtqueue_napi_schedule(&sq->napi, sq->vq);
> +	virtqueue_napi_schedule(napi, vq);
>  	local_bh_enable();
>  }
>  
>  static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag)
>  {
>  	struct virtnet_info *vi = netdev_priv(dev);
> -	struct send_queue *sq;
>  
>  	if (!netif_running(dev))
>  		return -ENETDOWN;
> @@ -1609,9 +1619,18 @@ static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag)
>  	if (qid >= vi->curr_queue_pairs)
>  		return -EINVAL;
>  
> -	sq = &vi->sq[qid];
> +	if (flag & XDP_WAKEUP_TX) {
> +		struct send_queue *sq = &vi->sq[qid];
> +
> +		xsk_wakeup(&sq->napi, sq->vq);
> +	}
> +
> +	if (flag & XDP_WAKEUP_RX) {
> +		struct receive_queue *rq = &vi->rq[qid];
> +
> +		xsk_wakeup(&rq->napi, rq->vq);
> +	}
>  
> -	xsk_wakeup(sq);
>  	return 0;
>  }
>  
> @@ -1623,7 +1642,7 @@ static void virtnet_xsk_completed(struct send_queue *sq, int num)
>  	 * wakeup the tx napi to consume the xsk tx queue, because the tx
>  	 * interrupt may not be triggered.
>  	 */
> -	xsk_wakeup(sq);
> +	xsk_wakeup(&sq->napi, sq->vq);
>  }
>  
>  static int __virtnet_xdp_xmit_one(struct virtnet_info *vi,
> -- 
> 2.43.0
Re: [PATCH net-next v2] virtio-net: xsk: Support wakeup on RX side
Posted by Bui Quang Minh 1 month ago
On 3/3/26 01:53, Michael S. Tsirkin wrote:
> On Mon, Mar 02, 2026 at 11:41:58PM +0700, Bui Quang Minh wrote:
>> When XDP_USE_NEED_WAKEUP is used and the fill ring is empty so no buffer
>> is allocated on RX side, allow RX NAPI to be descheduled. This avoids
>> wasting CPU cycles on polling. Users will be notified and they need to
>> make a wakeup call after refilling the ring.
>>
>> Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
>> ---
>> Changes in v2:
>> - Fix the flag check in virtnet_xsk_wakeup
>> - Link to v1: https://lore.kernel.org/netdev/20260227150949.13089-1-minhquangbui99@gmail.com/
>> ---
>>   drivers/net/virtio_net.c | 35 +++++++++++++++++++++++++++--------
>>   1 file changed, 27 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
>> index db88dcaefb20..3614002fc87c 100644
>> --- a/drivers/net/virtio_net.c
>> +++ b/drivers/net/virtio_net.c
>> @@ -1454,8 +1454,19 @@ static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue
>>   	xsk_buffs = rq->xsk_buffs;
>>   
>>   	num = xsk_buff_alloc_batch(pool, xsk_buffs, rq->vq->num_free);
>> -	if (!num)
>> +	if (!num) {
>> +		if (xsk_uses_need_wakeup(pool)) {
>> +			xsk_set_rx_need_wakeup(pool);
>> +			/* Return 0 instead of -ENOMEM so that NAPI is
>> +			 * descheduled.
>> +			 */
>> +			return 0;
> With this change, try_fill_recv() can return true even though zero RX
> buffers were posted in need_wakeup mode, which contradicts its
> documentation ("Returns false if we couldn't fill entirely (OOM)").
>
> Methinks we need to at least update the comment near try_fill_recv.

I'll update the comment of try_fill_recv function.

Thanks,
Quang Minh.

>
>
>
>> +		}
>> +
>>   		return -ENOMEM;
>> +	} else {
>> +		xsk_clear_rx_need_wakeup(pool);
>> +	}
>>   
>>   	len = xsk_pool_get_rx_frame_size(pool) + vi->hdr_len;
>>   
>> @@ -1588,20 +1599,19 @@ static bool virtnet_xsk_xmit(struct send_queue *sq, struct xsk_buff_pool *pool,
>>   	return sent;
>>   }
>>   
>> -static void xsk_wakeup(struct send_queue *sq)
>> +static void xsk_wakeup(struct napi_struct *napi, struct virtqueue *vq)
>>   {
>> -	if (napi_if_scheduled_mark_missed(&sq->napi))
>> +	if (napi_if_scheduled_mark_missed(napi))
>>   		return;
>>   
>>   	local_bh_disable();
>> -	virtqueue_napi_schedule(&sq->napi, sq->vq);
>> +	virtqueue_napi_schedule(napi, vq);
>>   	local_bh_enable();
>>   }
>>   
>>   static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag)
>>   {
>>   	struct virtnet_info *vi = netdev_priv(dev);
>> -	struct send_queue *sq;
>>   
>>   	if (!netif_running(dev))
>>   		return -ENETDOWN;
>> @@ -1609,9 +1619,18 @@ static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag)
>>   	if (qid >= vi->curr_queue_pairs)
>>   		return -EINVAL;
>>   
>> -	sq = &vi->sq[qid];
>> +	if (flag & XDP_WAKEUP_TX) {
>> +		struct send_queue *sq = &vi->sq[qid];
>> +
>> +		xsk_wakeup(&sq->napi, sq->vq);
>> +	}
>> +
>> +	if (flag & XDP_WAKEUP_RX) {
>> +		struct receive_queue *rq = &vi->rq[qid];
>> +
>> +		xsk_wakeup(&rq->napi, rq->vq);
>> +	}
>>   
>> -	xsk_wakeup(sq);
>>   	return 0;
>>   }
>>   
>> @@ -1623,7 +1642,7 @@ static void virtnet_xsk_completed(struct send_queue *sq, int num)
>>   	 * wakeup the tx napi to consume the xsk tx queue, because the tx
>>   	 * interrupt may not be triggered.
>>   	 */
>> -	xsk_wakeup(sq);
>> +	xsk_wakeup(&sq->napi, sq->vq);
>>   }
>>   
>>   static int __virtnet_xdp_xmit_one(struct virtnet_info *vi,
>> -- 
>> 2.43.0