Now, inside virtqueue_disable_and_recycle, the recycle() just has two parameters(vq, buf) after detach operate. But if we are in premapped mode, we may need to get some dma info when detach buf like virtqueue_get_buf_ctx_dma(). So we call recycle directly, this callback detaches bufs self. It should complete the work of detaching all the unused buffers. Signed-off-by: Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx> --- drivers/net/virtio/main.c | 60 +++++++++++++++++++----------------- drivers/virtio/virtio_ring.c | 10 +++--- include/linux/virtio.h | 4 +-- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/drivers/net/virtio/main.c b/drivers/net/virtio/main.c index ac3a529c7729..186b2cf5d8fc 100644 --- a/drivers/net/virtio/main.c +++ b/drivers/net/virtio/main.c @@ -150,7 +150,8 @@ struct virtio_net_common_hdr { }; }; -static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf); +static void virtnet_rq_free_unused_bufs(struct virtqueue *vq); +static void virtnet_sq_free_unused_bufs(struct virtqueue *vq); static bool is_xdp_frame(void *ptr) { @@ -587,20 +588,6 @@ static void virtnet_rq_set_premapped(struct virtnet_info *vi) } } -static void virtnet_rq_unmap_free_buf(struct virtqueue *vq, void *buf) -{ - struct virtnet_info *vi = vq->vdev->priv; - struct virtnet_rq *rq; - int i = vq2rxq(vq); - - rq = &vi->rq[i]; - - if (rq->do_dma) - virtnet_rq_unmap(rq, buf, 0); - - virtnet_rq_free_buf(vi, rq, buf); -} - static void free_old_xmit(struct virtnet_sq *sq, bool in_napi) { u64 bytes = 0, packets = 0; @@ -2244,7 +2231,7 @@ static int virtnet_rx_resize(struct virtnet_info *vi, cancel_work_sync(&rq->dim.work); } - err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf); + err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_free_unused_bufs); if (err) netdev_err(vi->dev, "resize rx fail: rx queue index: %d err: %d\n", qindex, err); @@ -2283,7 +2270,7 @@ static int virtnet_tx_resize(struct virtnet_info *vi, __netif_tx_unlock_bh(txq); - err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf); + err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_bufs); if (err) netdev_err(vi->dev, "resize tx fail: tx queue index: %d err: %d\n", qindex, err); @@ -4026,31 +4013,48 @@ static void free_receive_page_frags(struct virtnet_info *vi) } } -static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf) +static void virtnet_sq_free_unused_bufs(struct virtqueue *vq) { - if (!is_xdp_frame(buf)) - dev_kfree_skb(buf); - else - xdp_return_frame(ptr_to_xdp(buf)); + void *buf; + + while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) { + if (!is_xdp_frame(buf)) + dev_kfree_skb(buf); + else + xdp_return_frame(ptr_to_xdp(buf)); + } } -static void free_unused_bufs(struct virtnet_info *vi) +static void virtnet_rq_free_unused_bufs(struct virtqueue *vq) { + struct virtnet_info *vi = vq->vdev->priv; + struct virtnet_rq *rq; + int i = vq2rxq(vq); void *buf; + + rq = &vi->rq[i]; + + while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) { + if (rq->do_dma) + virtnet_rq_unmap(rq, buf, 0); + + virtnet_rq_free_buf(vi, rq, buf); + } +} + +static void free_unused_bufs(struct virtnet_info *vi) +{ int i; for (i = 0; i < vi->max_queue_pairs; i++) { struct virtqueue *vq = vi->sq[i].vq; - while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) - virtnet_sq_free_unused_buf(vq, buf); + virtnet_sq_free_unused_bufs(vq); cond_resched(); } for (i = 0; i < vi->max_queue_pairs; i++) { struct virtqueue *vq = vi->rq[i].vq; - - while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) - virtnet_rq_unmap_free_buf(vq, buf); + virtnet_rq_free_unused_bufs(vq); cond_resched(); } } diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 82f72428605b..ecbaf7568251 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -2198,11 +2198,10 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num) } static int virtqueue_disable_and_recycle(struct virtqueue *_vq, - void (*recycle)(struct virtqueue *vq, void *buf)) + void (*recycle)(struct virtqueue *vq)) { struct vring_virtqueue *vq = to_vvq(_vq); struct virtio_device *vdev = vq->vq.vdev; - void *buf; int err; if (!vq->we_own_ring) @@ -2218,8 +2217,7 @@ static int virtqueue_disable_and_recycle(struct virtqueue *_vq, if (err) return err; - while ((buf = virtqueue_detach_unused_buf(_vq)) != NULL) - recycle(_vq, buf); + recycle(_vq); return 0; } @@ -2814,7 +2812,7 @@ EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma); * */ int virtqueue_resize(struct virtqueue *_vq, u32 num, - void (*recycle)(struct virtqueue *vq, void *buf)) + void (*recycle)(struct virtqueue *vq)) { struct vring_virtqueue *vq = to_vvq(_vq); int err; @@ -2905,7 +2903,7 @@ EXPORT_SYMBOL_GPL(virtqueue_set_dma_premapped); * -EPERM: Operation not permitted */ int virtqueue_reset(struct virtqueue *_vq, - void (*recycle)(struct virtqueue *vq, void *buf)) + void (*recycle)(struct virtqueue *vq)) { struct vring_virtqueue *vq = to_vvq(_vq); int err; diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 572aecec205b..7a5e9ea7d420 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -115,9 +115,9 @@ dma_addr_t virtqueue_get_avail_addr(const struct virtqueue *vq); dma_addr_t virtqueue_get_used_addr(const struct virtqueue *vq); int virtqueue_resize(struct virtqueue *vq, u32 num, - void (*recycle)(struct virtqueue *vq, void *buf)); + void (*recycle)(struct virtqueue *vq)); int virtqueue_reset(struct virtqueue *vq, - void (*recycle)(struct virtqueue *vq, void *buf)); + void (*recycle)(struct virtqueue *vq)); /** * struct virtio_device - representation of a device using virtio -- 2.32.0.3.g01195cf9f