On Mon, 4 Jul 2022 11:59:03 +0800, Jason Wang <jasowang@xxxxxxxxxx> wrote: > > 在 2022/7/1 16:45, Xuan Zhuo 写道: > > On Fri, 1 Jul 2022 16:26:25 +0800, Jason Wang <jasowang@xxxxxxxxxx> wrote: > >> 在 2022/6/29 14:56, Xuan Zhuo 写道: > >>> Separate the logic of split to create vring queue. > >>> > >>> This feature is required for subsequent virtuqueue reset vring. > >>> > >>> Signed-off-by: Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx> > >>> --- > >>> drivers/virtio/virtio_ring.c | 68 ++++++++++++++++++++++-------------- > >>> 1 file changed, 42 insertions(+), 26 deletions(-) > >>> > >>> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c > >>> index 49d61e412dc6..a9ceb9c16c54 100644 > >>> --- a/drivers/virtio/virtio_ring.c > >>> +++ b/drivers/virtio/virtio_ring.c > >>> @@ -949,28 +949,19 @@ static void vring_free_split(struct vring_virtqueue_split *vring, > >>> kfree(vring->desc_extra); > >>> } > >>> > >>> -static struct virtqueue *vring_create_virtqueue_split( > >>> - unsigned int index, > >>> - unsigned int num, > >>> - unsigned int vring_align, > >>> - struct virtio_device *vdev, > >>> - bool weak_barriers, > >>> - bool may_reduce_num, > >>> - bool context, > >>> - bool (*notify)(struct virtqueue *), > >>> - void (*callback)(struct virtqueue *), > >>> - const char *name) > >>> +static int vring_alloc_queue_split(struct vring_virtqueue_split *vring, > >>> + struct virtio_device *vdev, > >>> + u32 num, > >>> + unsigned int vring_align, > >>> + bool may_reduce_num) > >>> { > >>> - struct virtqueue *vq; > >>> void *queue = NULL; > >>> dma_addr_t dma_addr; > >>> - size_t queue_size_in_bytes; > >>> - struct vring vring; > >>> > >>> /* We assume num is a power of 2. */ > >>> if (num & (num - 1)) { > >>> dev_warn(&vdev->dev, "Bad virtqueue length %u\n", num); > >>> - return NULL; > >>> + return -EINVAL; > >>> } > >>> > >>> /* TODO: allocate each queue chunk individually */ > >>> @@ -981,11 +972,11 @@ static struct virtqueue *vring_create_virtqueue_split( > >>> if (queue) > >>> break; > >>> if (!may_reduce_num) > >>> - return NULL; > >>> + return -ENOMEM; > >>> } > >>> > >>> if (!num) > >>> - return NULL; > >>> + return -ENOMEM; > >>> > >>> if (!queue) { > >>> /* Try to get a single page. You are my only hope! */ > >>> @@ -993,21 +984,46 @@ static struct virtqueue *vring_create_virtqueue_split( > >>> &dma_addr, GFP_KERNEL|__GFP_ZERO); > >>> } > >>> if (!queue) > >>> - return NULL; > >>> + return -ENOMEM; > >>> + > >>> + vring_init(&vring->vring, num, queue, vring_align); > >>> > >>> - queue_size_in_bytes = vring_size(num, vring_align); > >>> - vring_init(&vring, num, queue, vring_align); > >>> + vring->queue_dma_addr = dma_addr; > >>> + vring->queue_size_in_bytes = vring_size(num, vring_align); > >>> + > >>> + return 0; > >>> +} > >>> + > >>> +static struct virtqueue *vring_create_virtqueue_split( > >>> + unsigned int index, > >>> + unsigned int num, > >>> + unsigned int vring_align, > >>> + struct virtio_device *vdev, > >>> + bool weak_barriers, > >>> + bool may_reduce_num, > >>> + bool context, > >>> + bool (*notify)(struct virtqueue *), > >>> + void (*callback)(struct virtqueue *), > >>> + const char *name) > >>> +{ > >>> + struct vring_virtqueue_split vring = {}; > >>> + struct virtqueue *vq; > >>> + int err; > >>> + > >>> + err = vring_alloc_queue_split(&vring, vdev, num, vring_align, > >>> + may_reduce_num); > >>> + if (err) > >>> + return NULL; > >>> > >>> - vq = __vring_new_virtqueue(index, vring, vdev, weak_barriers, context, > >>> - notify, callback, name); > >>> + vq = __vring_new_virtqueue(index, vring.vring, vdev, weak_barriers, > >>> + context, notify, callback, name); > >>> if (!vq) { > >>> - vring_free_queue(vdev, queue_size_in_bytes, queue, > >>> - dma_addr); > >>> + vring_free_split(&vring, vdev); > >>> return NULL; > >>> } > >>> > >>> - to_vvq(vq)->split.queue_dma_addr = dma_addr; > >>> - to_vvq(vq)->split.queue_size_in_bytes = queue_size_in_bytes; > >>> + to_vvq(vq)->split.queue_dma_addr = vring.queue_dma_addr; > >> > >> Nit: having two queue_dma_addr seems redundant (so did queue_size_in_bytes). > > two? > > > > Where is the problem I don't understand? > > > > Thanks. > > > I meant we had: > > vring.vring = _vring; > > in __vring_new_virtqueue(). > > This means we'd better initialize vring fully before that? > > E.g > > vring.queue_dma_addr = dma_addr; > > ... > > __vring_new_virtqueue() oh, my bad, maybe the repeated use of the name "vring" led to a misunderstanding. What is passed to __vring_new_virtqueue is the structure struct vring struct vring { unsigned int num; vring_desc_t *desc; vring_avail_t *avail; vring_used_t *used; }; And what contains queue_dma_addr is our newly split structure struct vring_virtqueue_split struct vring_virtqueue_split { /* Actual memory layout for this queue. */ struct vring vring; /* Last written value to avail->flags */ u16 avail_flags_shadow; /* * Last written value to avail->idx in * guest byte order. */ u16 avail_idx_shadow; /* Per-descriptor state. */ struct vring_desc_state_split *desc_state; struct vring_desc_extra *desc_extra; /* DMA address and size information */ dma_addr_t queue_dma_addr; size_t queue_size_in_bytes; /* * The parameters for creating vrings are reserved for creating new * vring. */ u32 vring_align; bool may_reduce_num; }; We have no way to pass queue_dma_addr into __vring_new_virtqueue. But for the uniformity of the interface, I create a temporary struct vring_virtqueue_split vring_split(your suggestion) in __vring_new_virtqueue. Then assign the passed in struct vring to it vring.vring = _vring. So here vring is an empty temporary variable. As you have replied in other patches, my re-use of the name vring is a mistake, I will change some places to vring_split and vring_packed. Thanks. > > Thanks > > > > > >> Thanks > >> > >> > >>> + to_vvq(vq)->split.queue_size_in_bytes = vring.queue_size_in_bytes; > >>> to_vvq(vq)->we_own_ring = true; > >>> > >>> return vq; >