Re: [PATCH vhost 01/17] virtio_ring: introduce vring_need_unmap_buffer

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  wrote:
>
> To make the code readable, introduce vring_need_unmap_buffer() to
> replace do_unmap.
>
>use_dma_api premapped -> vring_need_unmap_buffer()
> 1. false   falsefalse
> 2. truefalsetrue
> 3. truetrue false
>
> Signed-off-by: Xuan Zhuo 

Acked-by: Jason Wang 

Thanks




Re: [PATCH vhost 02/17] virtio_ring: packed: remove double check of the unmap ops

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  wrote:
>
> In the functions vring_unmap_extra_packed and vring_unmap_desc_packed,
> multiple checks are made whether unmap is performed and whether it is
> INDIRECT.
>
> These two functions are usually called in a loop, and we should put the
> check outside the loop.
>
> And we unmap the descs with VRING_DESC_F_INDIRECT on the same path with
> other descs, that make the thing more complex. If we distinguish the
> descs with VRING_DESC_F_INDIRECT before unmap, thing will be clearer.
>
> 1. only one desc of the desc table is used, we do not need the loop
> 2. the called unmap api is difference from the other desc
> 3. the vq->premapped is not needed to check
> 4. the vq->indirect is not needed to check
> 5. the state->indir_desc must not be null
>
> Signed-off-by: Xuan Zhuo 
> ---
>  drivers/virtio/virtio_ring.c | 76 ++--
>  1 file changed, 39 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 4677831e6c26..7280a1706cca 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -1220,6 +1220,7 @@ static u16 packed_last_used(u16 last_used_idx)
> return last_used_idx & ~(-(1 << VRING_PACKED_EVENT_F_WRAP_CTR));
>  }
>
> +/* caller must check vring_need_unmap_buffer() */
>  static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
>  const struct vring_desc_extra *extra)
>  {
> @@ -1227,33 +1228,18 @@ static void vring_unmap_extra_packed(const struct 
> vring_virtqueue *vq,
>
> flags = extra->flags;
>
> -   if (flags & VRING_DESC_F_INDIRECT) {
> -   if (!vq->use_dma_api)
> -   return;
> -
> -   dma_unmap_single(vring_dma_dev(vq),
> -extra->addr, extra->len,
> -(flags & VRING_DESC_F_WRITE) ?
> -DMA_FROM_DEVICE : DMA_TO_DEVICE);
> -   } else {
> -   if (!vring_need_unmap_buffer(vq))
> -   return;
> -
> -   dma_unmap_page(vring_dma_dev(vq),
> -  extra->addr, extra->len,
> -  (flags & VRING_DESC_F_WRITE) ?
> -  DMA_FROM_DEVICE : DMA_TO_DEVICE);
> -   }
> +   dma_unmap_page(vring_dma_dev(vq),
> +  extra->addr, extra->len,
> +  (flags & VRING_DESC_F_WRITE) ?
> +  DMA_FROM_DEVICE : DMA_TO_DEVICE);
>  }
>
> +/* caller must check vring_need_unmap_buffer() */
>  static void vring_unmap_desc_packed(const struct vring_virtqueue *vq,
> const struct vring_packed_desc *desc)
>  {
> u16 flags;
>
> -   if (!vring_need_unmap_buffer(vq))
> -   return;
> -
> flags = le16_to_cpu(desc->flags);
>
> dma_unmap_page(vring_dma_dev(vq),
> @@ -1329,7 +1315,7 @@ static int virtqueue_add_indirect_packed(struct 
> vring_virtqueue *vq,
> total_sg * sizeof(struct vring_packed_desc),
> DMA_TO_DEVICE);
> if (vring_mapping_error(vq, addr)) {
> -   if (vq->premapped)
> +   if (!vring_need_unmap_buffer(vq))
> goto free_desc;
>
> goto unmap_release;
> @@ -1344,10 +1330,11 @@ static int virtqueue_add_indirect_packed(struct 
> vring_virtqueue *vq,
> vq->packed.desc_extra[id].addr = addr;
> vq->packed.desc_extra[id].len = total_sg *
> sizeof(struct vring_packed_desc);
> -   vq->packed.desc_extra[id].flags = VRING_DESC_F_INDIRECT |
> - vq->packed.avail_used_flags;
> }
>
> +   vq->packed.desc_extra[id].flags = VRING_DESC_F_INDIRECT |
> +   vq->packed.avail_used_flags;

Is this a bug fix? Or if we only need to check _F_INDIRECT, we can
simply avoid doing this by checking vq->indirect && state->indir_desc?

> +
> /*
>  * A driver MUST NOT make the first descriptor in the list
>  * available before all subsequent descriptors comprising
> @@ -1388,6 +1375,8 @@ static int virtqueue_add_indirect_packed(struct 
> vring_virtqueue *vq,
>  unmap_release:
> err_idx = i;
>
> +   WARN_ON(!vring_need_unmap_buffer(vq));

Nitpick, using BUG_ON might be better as it may lead to unexpected
results which we can't recover from.

> +
> for (i = 0; i < err_idx; i++)
> vring_unmap_desc_packed(vq, &desc[i]);
>
> @@ -1484,9 +1473,10 @@ static inline int virtqueue_add_packed(struct 
> virtqueue *_vq,
> if (unlikely(vring_need_unmap_buffer(vq))) {
> vq->packed.desc_extra[curr].addr = addr;
> vq->packed.desc_extra[curr].len = sg->length

Re: [PATCH vhost 06/17] virtio_ring: no store dma info when unmap is not needed

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  wrote:
>
> As discussed:
> http://lore.kernel.org/all/CACGkMEug-=C+VQhkMYSgUKMC==04m7-uem_yc21bggkkzh8...@mail.gmail.com
>
> When the vq is premapped mode, the driver manages the dma
> info is a good way.
>
> So this commit make the virtio core not to store the dma
> info and release the memory which is used to store the dma
> info.
>
> If the use_dma_api is false, the memory is also not allocated.
>
> Signed-off-by: Xuan Zhuo 
> ---
>  drivers/virtio/virtio_ring.c | 89 
>  1 file changed, 70 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 831667a57429..5bea25167259 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -94,12 +94,15 @@ struct vring_desc_state_packed {
>  };
>
>  struct vring_desc_extra {
> -   dma_addr_t addr;/* Descriptor DMA addr. */
> -   u32 len;/* Descriptor length. */
> u16 flags;  /* Descriptor flags. */
> u16 next;   /* The next desc state in a list. */
>  };
>
> +struct vring_desc_dma {
> +   dma_addr_t addr;/* Descriptor DMA addr. */
> +   u32 len;/* Descriptor length. */
> +};
> +
>  struct vring_virtqueue_split {
> /* Actual memory layout for this queue. */
> struct vring vring;
> @@ -116,6 +119,7 @@ struct vring_virtqueue_split {
> /* Per-descriptor state. */
> struct vring_desc_state_split *desc_state;
> struct vring_desc_extra *desc_extra;
> +   struct vring_desc_dma *desc_dma;
>
> /* DMA address and size information */
> dma_addr_t queue_dma_addr;
> @@ -156,6 +160,7 @@ struct vring_virtqueue_packed {
> /* Per-descriptor state. */
> struct vring_desc_state_packed *desc_state;
> struct vring_desc_extra *desc_extra;
> +   struct vring_desc_dma *desc_dma;
>
> /* DMA address and size information */
> dma_addr_t ring_dma_addr;
> @@ -472,13 +477,14 @@ static unsigned int vring_unmap_one_split(const struct 
> vring_virtqueue *vq,
>   unsigned int i)
>  {
> struct vring_desc_extra *extra = vq->split.desc_extra;
> +   struct vring_desc_dma *dma = vq->split.desc_dma;
> u16 flags;
>
> flags = extra[i].flags;
>
> dma_unmap_page(vring_dma_dev(vq),
> -  extra[i].addr,
> -  extra[i].len,
> +  dma[i].addr,
> +  dma[i].len,
>(flags & VRING_DESC_F_WRITE) ?
>DMA_FROM_DEVICE : DMA_TO_DEVICE);
>
> @@ -535,8 +541,11 @@ static inline unsigned int 
> virtqueue_add_desc_split(struct virtqueue *vq,
> next = extra[i].next;
> desc[i].next = cpu_to_virtio16(vq->vdev, next);
>
> -   extra[i].addr = addr;
> -   extra[i].len = len;
> +   if (vring->split.desc_dma) {
> +   vring->split.desc_dma[i].addr = addr;
> +   vring->split.desc_dma[i].len = len;
> +   }
> +
> extra[i].flags = flags;
> } else
> next = virtio16_to_cpu(vq->vdev, desc[i].next);
> @@ -1072,16 +1081,26 @@ static void virtqueue_vring_attach_split(struct 
> vring_virtqueue *vq,
> vq->free_head = 0;
>  }
>
> -static int vring_alloc_state_extra_split(struct vring_virtqueue_split 
> *vring_split)
> +static int vring_alloc_state_extra_split(struct vring_virtqueue_split 
> *vring_split,
> +bool need_unmap)
>  {
> struct vring_desc_state_split *state;
> struct vring_desc_extra *extra;
> +   struct vring_desc_dma *dma;
> u32 num = vring_split->vring.num;
>
> state = kmalloc_array(num, sizeof(struct vring_desc_state_split), 
> GFP_KERNEL);
> if (!state)
> goto err_state;
>
> +   if (need_unmap) {
> +   dma = kmalloc_array(num, sizeof(struct vring_desc_dma), 
> GFP_KERNEL);
> +   if (!dma)
> +   goto err_dma;
> +   } else {
> +   dma = NULL;
> +   }
> +
> extra = vring_alloc_desc_extra(num);
> if (!extra)
> goto err_extra;
> @@ -1090,9 +1109,12 @@ static int vring_alloc_state_extra_split(struct 
> vring_virtqueue_split *vring_spl
>
> vring_split->desc_state = state;
> vring_split->desc_extra = extra;
> +   vring_split->desc_dma = dma;
> return 0;
>
>  err_extra:
> +   kfree(dma);
> +err_dma:
> kfree(state);
>  err_state:
> return -ENOMEM;
> @@ -1108,6 +1130,7 @@ static void vring_free_split(struct 
> vring_virtqueue_split *vring_split,
>
> kfree(vring_split->desc_state);
> kfree(vring_split->desc_extr

Re: [PATCH vhost 04/17] virtio_ring: split: remove double check of the unmap ops

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  wrote:
>
> In the functions vring_unmap_one_split and
> vring_unmap_one_split_indirect,
> multiple checks are made whether unmap is performed and whether it is
> INDIRECT.
>
> These two functions are usually called in a loop, and we should put the
> check outside the loop.
>
> And we unmap the descs with VRING_DESC_F_INDIRECT on the same path with
> other descs, that make the thing more complex. If we distinguish the
> descs with VRING_DESC_F_INDIRECT before unmap, thing will be clearer.
>
> 1. only one desc of the desc table is used, we do not need the loop
> 2. the called unmap api is difference from the other desc
> 3. the vq->premapped is not needed to check
> 4. the vq->indirect is not needed to check
> 5. the state->indir_desc must not be null
>
> Signed-off-by: Xuan Zhuo 
> ---
>  drivers/virtio/virtio_ring.c | 80 ++--
>  1 file changed, 39 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index dd03bc5a81fe..2b41fdbce975 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -452,9 +452,6 @@ static void vring_unmap_one_split_indirect(const struct 
> vring_virtqueue *vq,
>  {
> u16 flags;
>
> -   if (!vring_need_unmap_buffer(vq))
> -   return;
> -
> flags = virtio16_to_cpu(vq->vq.vdev, desc->flags);
>
> dma_unmap_page(vring_dma_dev(vq),
> @@ -472,27 +469,12 @@ static unsigned int vring_unmap_one_split(const struct 
> vring_virtqueue *vq,
>
> flags = extra[i].flags;
>
> -   if (flags & VRING_DESC_F_INDIRECT) {
> -   if (!vq->use_dma_api)
> -   goto out;
> -
> -   dma_unmap_single(vring_dma_dev(vq),
> -extra[i].addr,
> -extra[i].len,
> -(flags & VRING_DESC_F_WRITE) ?
> -DMA_FROM_DEVICE : DMA_TO_DEVICE);
> -   } else {
> -   if (!vring_need_unmap_buffer(vq))
> -   goto out;
> -
> -   dma_unmap_page(vring_dma_dev(vq),
> -  extra[i].addr,
> -  extra[i].len,
> -  (flags & VRING_DESC_F_WRITE) ?
> -  DMA_FROM_DEVICE : DMA_TO_DEVICE);
> -   }
> +   dma_unmap_page(vring_dma_dev(vq),
> +  extra[i].addr,
> +  extra[i].len,
> +  (flags & VRING_DESC_F_WRITE) ?
> +  DMA_FROM_DEVICE : DMA_TO_DEVICE);
>
> -out:
> return extra[i].next;
>  }
>
> @@ -660,7 +642,7 @@ static inline int virtqueue_add_split(struct virtqueue 
> *_vq,
> vq, desc, total_sg * sizeof(struct vring_desc),
> DMA_TO_DEVICE);
> if (vring_mapping_error(vq, addr)) {
> -   if (vq->premapped)
> +   if (!vring_need_unmap_buffer(vq))
> goto free_indirect;
>
> goto unmap_release;
> @@ -713,6 +695,9 @@ static inline int virtqueue_add_split(struct virtqueue 
> *_vq,
> return 0;
>
>  unmap_release:
> +
> +   WARN_ON(!vring_need_unmap_buffer(vq));
> +
> err_idx = i;
>
> if (indirect)
> @@ -774,34 +759,42 @@ static void detach_buf_split(struct vring_virtqueue 
> *vq, unsigned int head,
>  {
> unsigned int i, j;
> __virtio16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT);
> +   u16 flags;
>
> /* Clear data ptr. */
> vq->split.desc_state[head].data = NULL;
> +   flags = vq->split.desc_extra[head].flags;
>
> /* Put back on free list: unmap first-level descriptors and find end 
> */
> i = head;
>
> -   while (vq->split.vring.desc[i].flags & nextflag) {
> -   vring_unmap_one_split(vq, i);
> -   i = vq->split.desc_extra[i].next;
> -   vq->vq.num_free++;
> -   }
> -
> -   vring_unmap_one_split(vq, i);
> -   vq->split.desc_extra[i].next = vq->free_head;
> -   vq->free_head = head;
> +   if (!(flags & VRING_DESC_F_INDIRECT)) {

So during add we do:

if (!indirect && vring_need_unmap_buffer(vq))
vq->split.desc_extra[prev & (vq->split.vring.num - 1)].flags &=
~VRING_DESC_F_NEXT;

Then using flags here unconditionally seems not reliable.

I post a patch to store flags unconditionally at:

https://lore.kernel.org/all/20220224122655-mutt-send-email-...@kernel.org/

> +   while (vq->split.vring.desc[i].flags & nextflag) {
> +   if (vring_need_unmap_buffer(vq))
> +   vring_unmap_one_split(vq, i);
> +   i = vq->split.desc_extra[i].next;
> +   vq->vq.num_free++;
> +   }
>
> -   

Re: [PATCH vhost 05/17] virtio_ring: split: structure the indirect desc table

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  wrote:
>
> This commit structure the indirect desc table.
> Then we can get the desc num directly when doing unmap.
>
> And save the dma info to the struct, then the indirect
> will not use the dma fields of the desc_extra. The subsequent
> commits will make the dma fields are optional. But for
> the indirect case, we must record the dma info.
>
> Signed-off-by: Xuan Zhuo 
> ---
>  drivers/virtio/virtio_ring.c | 86 ++--
>  1 file changed, 52 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 2b41fdbce975..831667a57429 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -67,9 +67,16 @@
>  #define LAST_ADD_TIME_INVALID(vq)
>  #endif

[...]

> +   kfree(in_desc);
> vq->split.desc_state[head].indir_desc = NULL;
> -

Unnecessary changes.

Thanks


> }
>
> vq->split.desc_extra[i].next = vq->free_head;
> --
> 2.32.0.3.g01195cf9f
>




Re: [PATCH vhost 08/17] virtio: vring_new_virtqueue(): pass struct instead of multi parameters

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  wrote:
>
> Just like find_vqs(), it is time to refactor the
> vring_new_virtqueue(). We pass the similar struct to
> vring_new_virtqueue.
>

Well, the vring_create_virtqueue() is converted with a structure.

We need to be consistent. And it seems better to use a separate patch
for vring_create_virtqueue() as well.

Thanks




Re: [PATCH vhost 03/17] virtio_ring: packed: structure the indirect desc table

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  wrote:
>
> This commit structure the indirect desc table.
> Then we can get the desc num directly when doing unmap.
>
> And save the dma info to the struct, then the indirect
> will not use the dma fields of the desc_extra. The subsequent
> commits will make the dma fields are optional. But for
> the indirect case, we must record the dma info.
>
> Signed-off-by: Xuan Zhuo 
> ---
>  drivers/virtio/virtio_ring.c | 63 
>  1 file changed, 35 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 7280a1706cca..dd03bc5a81fe 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -72,9 +72,16 @@ struct vring_desc_state_split {
> struct vring_desc *indir_desc;  /* Indirect descriptor, if any. */
>  };
>
> +struct vring_packed_desc_indir {
> +   dma_addr_t addr;/* Descriptor Array DMA addr. */
> +   u32 len;/* Descriptor Array length. */
> +   u32 num;
> +   struct vring_packed_desc desc[];
> +};
> +
>  struct vring_desc_state_packed {
> void *data; /* Data for callback. */
> -   struct vring_packed_desc *indir_desc; /* Indirect descriptor, if any. 
> */
> +   struct vring_packed_desc_indir *indir_desc; /* Indirect descriptor, 
> if any. */
> u16 num;/* Descriptor list length. */
> u16 last;   /* The last desc state in a list. */
>  };
> @@ -1249,10 +1256,13 @@ static void vring_unmap_desc_packed(const struct 
> vring_virtqueue *vq,
>DMA_FROM_DEVICE : DMA_TO_DEVICE);
>  }
>
> -static struct vring_packed_desc *alloc_indirect_packed(unsigned int total_sg,
> +static struct vring_packed_desc_indir *alloc_indirect_packed(unsigned int 
> total_sg,
>gfp_t gfp)
>  {
> -   struct vring_packed_desc *desc;
> +   struct vring_packed_desc_indir *in_desc;
> +   u32 size;
> +
> +   size = struct_size(in_desc, desc, total_sg);
>
> /*
>  * We require lowmem mappings for the descriptors because
> @@ -1261,9 +1271,10 @@ static struct vring_packed_desc 
> *alloc_indirect_packed(unsigned int total_sg,
>  */
> gfp &= ~__GFP_HIGHMEM;
>
> -   desc = kmalloc_array(total_sg, sizeof(struct vring_packed_desc), gfp);
>
> -   return desc;
> +   in_desc = kmalloc(size, gfp);
> +
> +   return in_desc;
>  }
>
>  static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
> @@ -1274,6 +1285,7 @@ static int virtqueue_add_indirect_packed(struct 
> vring_virtqueue *vq,
>  void *data,
>  gfp_t gfp)
>  {
> +   struct vring_packed_desc_indir *in_desc;
> struct vring_packed_desc *desc;
> struct scatterlist *sg;
> unsigned int i, n, err_idx;
> @@ -1281,10 +1293,12 @@ static int virtqueue_add_indirect_packed(struct 
> vring_virtqueue *vq,
> dma_addr_t addr;
>
> head = vq->packed.next_avail_idx;
> -   desc = alloc_indirect_packed(total_sg, gfp);
> -   if (!desc)
> +   in_desc = alloc_indirect_packed(total_sg, gfp);
> +   if (!in_desc)
> return -ENOMEM;
>
> +   desc = in_desc->desc;
> +
> if (unlikely(vq->vq.num_free < 1)) {
> pr_debug("Can't add buf len 1 - avail = 0\n");
> kfree(desc);
> @@ -1321,17 +1335,15 @@ static int virtqueue_add_indirect_packed(struct 
> vring_virtqueue *vq,
> goto unmap_release;
> }
>
> +   in_desc->num = i;
> +   in_desc->addr = addr;
> +   in_desc->len = total_sg * sizeof(struct vring_packed_desc);

It looks to me if we don't use dma_api we don't even need these steps?

> +
> vq->packed.vring.desc[head].addr = cpu_to_le64(addr);
> vq->packed.vring.desc[head].len = cpu_to_le32(total_sg *
> sizeof(struct vring_packed_desc));
> vq->packed.vring.desc[head].id = cpu_to_le16(id);
>
> -   if (vring_need_unmap_buffer(vq)) {
> -   vq->packed.desc_extra[id].addr = addr;
> -   vq->packed.desc_extra[id].len = total_sg *
> -   sizeof(struct vring_packed_desc);
> -   }
> -
> vq->packed.desc_extra[id].flags = VRING_DESC_F_INDIRECT |
> vq->packed.avail_used_flags;
>
> @@ -1362,7 +1374,7 @@ static int virtqueue_add_indirect_packed(struct 
> vring_virtqueue *vq,
> /* Store token and indirect buffer state. */
> vq->packed.desc_state[id].num = 1;
> vq->packed.desc_state[id].data = data;
> -   vq->packed.desc_state[id].indir_desc = desc;
> +   vq->packed.desc_state[id].indir_desc = in_desc;
> vq->packed.desc_state[id].last = id;
>
> vq->num_added += 1;
> @@ -138

Re: [PATCH vhost 07/17] virtio: find_vqs: pass struct instead of multi parameters

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  wrote:
>
> Now, we pass multi parameters to find_vqs. These parameters
> may work for transport or work for vring.
>
> And find_vqs has multi implements in many places:
>
> But every time,
>  arch/um/drivers/virtio_uml.c
>  drivers/platform/mellanox/mlxbf-tmfifo.c
>  drivers/remoteproc/remoteproc_virtio.c
>  drivers/s390/virtio/virtio_ccw.c
>  drivers/virtio/virtio_mmio.c
>  drivers/virtio/virtio_pci_legacy.c
>  drivers/virtio/virtio_pci_modern.c
>  drivers/virtio/virtio_vdpa.c
>
> Every time, we try to add a new parameter, that is difficult.
> We must change every find_vqs implement.
>
> One the other side, if we want to pass a parameter to vring,
> we must change the call path from transport to vring.
> Too many functions need to be changed.
>
> So it is time to refactor the find_vqs. We pass a structure
> cfg to find_vqs(), that will be passed to vring by transport.
>
> And squish the parameters from transport to a structure.

The patch did more than what is described here, it also switch to use
a structure for vring_create_virtqueue() etc.

Is it better to split?

>
> Signed-off-by: Xuan Zhuo 
> ---
>  arch/um/drivers/virtio_uml.c | 29 +++-
>  drivers/platform/mellanox/mlxbf-tmfifo.c | 14 +++---
>  drivers/remoteproc/remoteproc_virtio.c   | 28 ++-
>  drivers/s390/virtio/virtio_ccw.c | 33 ++---
>  drivers/virtio/virtio_mmio.c | 30 ++--
>  drivers/virtio/virtio_pci_common.c   | 59 +++-
>  drivers/virtio/virtio_pci_common.h   |  9 +---
>  drivers/virtio/virtio_pci_legacy.c   | 16 ---
>  drivers/virtio/virtio_pci_modern.c   | 24 +-
>  drivers/virtio/virtio_ring.c | 59 ++--
>  drivers/virtio/virtio_vdpa.c | 33 +++--
>  include/linux/virtio_config.h| 51 
>  include/linux/virtio_ring.h  | 40 ++--
>  13 files changed, 217 insertions(+), 208 deletions(-)
>
> diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
> index 8adca2000e51..161bac67e454 100644
> --- a/arch/um/drivers/virtio_uml.c
> +++ b/arch/um/drivers/virtio_uml.c
> @@ -937,11 +937,12 @@ static int vu_setup_vq_call_fd(struct virtio_uml_device 
> *vu_dev,
>  }
>
>  static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
> -unsigned index, vq_callback_t *callback,
> -const char *name, bool ctx)
> +unsigned index,
> +struct virtio_vq_config *cfg)
>  {
> struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
> struct platform_device *pdev = vu_dev->pdev;
> +   struct transport_vq_config tp_cfg = {};

Nit: what did "tp" short for?

> struct virtio_uml_vq_info *info;
> struct virtqueue *vq;
> int num = MAX_SUPPORTED_QUEUE_SIZE;
> @@ -953,10 +954,15 @@ static struct virtqueue *vu_setup_vq(struct 
> virtio_device *vdev,
> goto error_kzalloc;
> }
> snprintf(info->name, sizeof(info->name), "%s.%d-%s", pdev->name,
> -pdev->id, name);
> +pdev->id, cfg->names[cfg->cfg_idx]);
>
> -   vq = vring_create_virtqueue(index, num, PAGE_SIZE, vdev, true, true,
> -   ctx, vu_notify, callback, info->name);
> +   tp_cfg.num = num;
> +   tp_cfg.vring_align = PAGE_SIZE;
> +   tp_cfg.weak_barriers = true;
> +   tp_cfg.may_reduce_num = true;
> +   tp_cfg.notify = vu_notify;
> +
> +   vq = vring_create_virtqueue(vdev, index, &tp_cfg, cfg);
> if (!vq) {
> rc = -ENOMEM;
> goto error_create;
> @@ -1013,12 +1019,11 @@ static struct virtqueue *vu_setup_vq(struct 
> virtio_device *vdev,
> return ERR_PTR(rc);
>  }
>
> -static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
> -  struct virtqueue *vqs[], vq_callback_t *callbacks[],
> -  const char * const names[], const bool *ctx,
> -  struct irq_affinity *desc)
> +static int vu_find_vqs(struct virtio_device *vdev, struct virtio_vq_config 
> *cfg)
>  {
> struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
> +   struct virtqueue **vqs = cfg->vqs;
> +   unsigned int nvqs = cfg->nvqs;
> int i, queue_idx = 0, rc;
> struct virtqueue *vq;
>
> @@ -1031,13 +1036,13 @@ static int vu_find_vqs(struct virtio_device *vdev, 
> unsigned nvqs,
> return rc;
>
> for (i = 0; i < nvqs; ++i) {
> -   if (!names[i]) {
> +   if (!cfg->names[i]) {
> vqs[i] = NULL;
> continue;
> }
>
> -   vqs[i] = vu_setup_vq(vdev, queue_idx++, callbacks[i], 
> names[i],
> -

Re: [PATCH vhost 17/17] virtio_net: sq support premapped mode

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:43 PM Xuan Zhuo  wrote:
>
> If the xsk is enabling, the xsk tx will share the send queue.
> But the xsk requires that the send queue use the premapped mode.
> So the send queue must support premapped mode.
>
> Signed-off-by: Xuan Zhuo 
> ---
>  drivers/net/virtio_net.c | 167 ++-
>  1 file changed, 163 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 226ab830870e..cf0c67380b07 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -46,6 +46,7 @@ module_param(napi_tx, bool, 0644);
>  #define VIRTIO_XDP_REDIR   BIT(1)
>
>  #define VIRTIO_XDP_FLAGBIT(0)
> +#define VIRTIO_DMA_FLAGBIT(1)
>
>  /* RX packet size EWMA. The average packet size is used to determine the 
> packet
>   * buffer size when refilling RX rings. As the entire RX ring may be refilled
> @@ -140,6 +141,21 @@ struct virtnet_rq_dma {
> u16 need_sync;
>  };
>
> +struct virtnet_sq_dma {
> +   union {
> +   struct virtnet_sq_dma *next;
> +   void *data;
> +   };
> +   dma_addr_t addr;
> +   u32 len;
> +   bool is_tail;
> +};
> +
> +struct virtnet_sq_dma_head {
> +   struct virtnet_sq_dma *free;
> +   struct virtnet_sq_dma *head;

Any reason the head must be a pointer instead of a simple index?

> +};
> +
>  /* Internal representation of a send virtqueue */
>  struct send_queue {
> /* Virtqueue associated with this send _queue */
> @@ -159,6 +175,8 @@ struct send_queue {
>
> /* Record whether sq is in reset state. */
> bool reset;
> +
> +   struct virtnet_sq_dma_head dmainfo;
>  };
>
>  /* Internal representation of a receive virtqueue */
> @@ -348,6 +366,131 @@ static struct xdp_frame *ptr_to_xdp(void *ptr)
> return (struct xdp_frame *)((unsigned long)ptr & ~VIRTIO_XDP_FLAG);
>  }
>
> +static inline void *virtnet_sq_unmap(struct send_queue *sq, void *data)
> +{
> +   struct virtnet_sq_dma *head, *tail;
> +
> +   if (!((unsigned long)data & VIRTIO_DMA_FLAG))
> +   return data;
> +
> +   head = (void *)((unsigned long)data & ~VIRTIO_DMA_FLAG);
> +
> +   tail = head;
> +
> +   while (true) {
> +   virtqueue_dma_unmap_page_attrs(sq->vq, tail->addr, tail->len,
> +  DMA_TO_DEVICE, 0);
> +
> +   if (tail->is_tail)
> +   break;
> +
> +   tail = tail->next;
> +   }
> +
> +   data = tail->data;
> +   tail->is_tail = false;
> +
> +   tail->next = sq->dmainfo.free;
> +   sq->dmainfo.free = head;
> +
> +   return data;
> +}
> +
> +static void *virtnet_sq_dma_splice(struct send_queue *sq,
> +  struct virtnet_sq_dma *head,
> +  struct virtnet_sq_dma *tail,
> +  void *data)
> +{
> +   sq->dmainfo.free = tail->next;
> +
> +   tail->is_tail = true;
> +   tail->data = data;
> +
> +   head = (void *)((unsigned long)head | VIRTIO_DMA_FLAG);
> +
> +   return head;
> +}
> +
> +static struct virtnet_sq_dma *virtnet_sq_map_sg(struct send_queue *sq, int 
> nents, void *data)
> +{
> +   struct virtnet_sq_dma *head, *tail, *p;
> +   struct scatterlist *sg;
> +   dma_addr_t addr;
> +   int i;
> +
> +   head = sq->dmainfo.free;
> +   p = head;
> +
> +   tail = NULL;
> +
> +   for_each_sg(sq->sg, sg, nents, i) {
> +   addr = virtqueue_dma_map_page_attrs(sq->vq, sg_page(sg),
> +   sg->offset, sg->length,
> +   DMA_TO_DEVICE, 0);
> +   if (virtqueue_dma_mapping_error(sq->vq, addr))
> +   goto err;
> +
> +   sg->dma_address = addr;
> +
> +   tail = p;
> +   tail->addr = sg->dma_address;
> +   tail->len = sg->length;
> +
> +   p = p->next;
> +   }
> +
> +   return virtnet_sq_dma_splice(sq, head, tail, data);
> +
> +err:
> +   if (tail)
> +   virtnet_sq_unmap(sq, virtnet_sq_dma_splice(sq, head, tail, 
> data));
> +
> +   return NULL;
> +}
> +
> +static int virtnet_add_outbuf(struct send_queue *sq, u32 num, void *data)
> +{
> +   int ret;
> +
> +   if (sq->vq->premapped) {
> +   data = virtnet_sq_map_sg(sq, num, data);
> +   if (!data)
> +   return -ENOMEM;
> +   }
> +
> +   ret = virtqueue_add_outbuf(sq->vq, sq->sg, num, data, GFP_ATOMIC);
> +   if (ret && sq->vq->premapped)
> +   virtnet_sq_unmap(sq, data);
> +
> +   return ret;
> +}
> +
> +static int virtnet_sq_init_dma_mate(struct send_queue *sq)
> +{
> +   struct virtnet_sq_dma *d;
> +   int size, i;
> +
> +   size = virtqueue_get_vring_size(sq->vq);
> +
> +   

Re: [PATCH vhost 11/17] virtio_ring: export premapped to driver by struct virtqueue

2024-01-31 Thread Jason Wang
On Tue, Jan 30, 2024 at 7:43 PM Xuan Zhuo  wrote:
>
> Export the premapped to drivers, then drivers can check
> the vq premapped mode after the find_vqs().

This looks odd, it's the charge of the driver to set premapped, so it
should know it?

Thanks




Re: [PATCH vhost 03/17] virtio_ring: packed: structure the indirect desc table

2024-01-31 Thread Jason Wang
On Wed, Jan 31, 2024 at 6:01 PM Xuan Zhuo  wrote:
>
> On Wed, 31 Jan 2024 17:12:10 +0800, Jason Wang  wrote:
> > On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  
> > wrote:
> > >
> > > This commit structure the indirect desc table.
> > > Then we can get the desc num directly when doing unmap.
> > >
> > > And save the dma info to the struct, then the indirect
> > > will not use the dma fields of the desc_extra. The subsequent
> > > commits will make the dma fields are optional. But for
> > > the indirect case, we must record the dma info.
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > ---
> > >  drivers/virtio/virtio_ring.c | 63 
> > >  1 file changed, 35 insertions(+), 28 deletions(-)
> > >
> > > diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> > > index 7280a1706cca..dd03bc5a81fe 100644
> > > --- a/drivers/virtio/virtio_ring.c
> > > +++ b/drivers/virtio/virtio_ring.c
> > > @@ -72,9 +72,16 @@ struct vring_desc_state_split {
> > > struct vring_desc *indir_desc;  /* Indirect descriptor, if any. */
> > >  };
> > >
> > > +struct vring_packed_desc_indir {
> > > +   dma_addr_t addr;/* Descriptor Array DMA addr. */
> > > +   u32 len;/* Descriptor Array length. */
> > > +   u32 num;
> > > +   struct vring_packed_desc desc[];
> > > +};
> > > +
> > >  struct vring_desc_state_packed {
> > > void *data; /* Data for callback. */
> > > -   struct vring_packed_desc *indir_desc; /* Indirect descriptor, if 
> > > any. */
> > > +   struct vring_packed_desc_indir *indir_desc; /* Indirect 
> > > descriptor, if any. */
> > > u16 num;/* Descriptor list length. */
> > > u16 last;   /* The last desc state in a list. 
> > > */
> > >  };
> > > @@ -1249,10 +1256,13 @@ static void vring_unmap_desc_packed(const struct 
> > > vring_virtqueue *vq,
> > >DMA_FROM_DEVICE : DMA_TO_DEVICE);
> > >  }
> > >
> > > -static struct vring_packed_desc *alloc_indirect_packed(unsigned int 
> > > total_sg,
> > > +static struct vring_packed_desc_indir *alloc_indirect_packed(unsigned 
> > > int total_sg,
> > >gfp_t gfp)
> > >  {
> > > -   struct vring_packed_desc *desc;
> > > +   struct vring_packed_desc_indir *in_desc;
> > > +   u32 size;
> > > +
> > > +   size = struct_size(in_desc, desc, total_sg);
> > >
> > > /*
> > >  * We require lowmem mappings for the descriptors because
> > > @@ -1261,9 +1271,10 @@ static struct vring_packed_desc 
> > > *alloc_indirect_packed(unsigned int total_sg,
> > >  */
> > > gfp &= ~__GFP_HIGHMEM;
> > >
> > > -   desc = kmalloc_array(total_sg, sizeof(struct vring_packed_desc), 
> > > gfp);
> > >
> > > -   return desc;
> > > +   in_desc = kmalloc(size, gfp);
> > > +
> > > +   return in_desc;
> > >  }
> > >
> > >  static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
> > > @@ -1274,6 +1285,7 @@ static int virtqueue_add_indirect_packed(struct 
> > > vring_virtqueue *vq,
> > >  void *data,
> > >  gfp_t gfp)
> > >  {
> > > +   struct vring_packed_desc_indir *in_desc;
> > > struct vring_packed_desc *desc;
> > > struct scatterlist *sg;
> > > unsigned int i, n, err_idx;
> > > @@ -1281,10 +1293,12 @@ static int virtqueue_add_indirect_packed(struct 
> > > vring_virtqueue *vq,
> > > dma_addr_t addr;
> > >
> > > head = vq->packed.next_avail_idx;
> > > -   desc = alloc_indirect_packed(total_sg, gfp);
> > > -   if (!desc)
> > > +   in_desc = alloc_indirect_packed(total_sg, gfp);
> > > +   if (!in_desc)
> > > return -ENOMEM;
> > >
> > > +   desc = in_desc->desc;
> > > +
> > > if (unlikely(vq->vq.num_free < 1)) {
> > > pr_debug("Can't add buf len 1 - av

Re: [PATCH vhost 17/17] virtio_net: sq support premapped mode

2024-01-31 Thread Jason Wang
On Thu, Feb 1, 2024 at 11:28 AM Xuan Zhuo  wrote:
>
> On Wed, 31 Jan 2024 17:12:47 +0800, Jason Wang  wrote:
> > On Tue, Jan 30, 2024 at 7:43 PM Xuan Zhuo  
> > wrote:
> > >
> > > If the xsk is enabling, the xsk tx will share the send queue.
> > > But the xsk requires that the send queue use the premapped mode.
> > > So the send queue must support premapped mode.
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > ---
> > >  drivers/net/virtio_net.c | 167 ++-
> > >  1 file changed, 163 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > > index 226ab830870e..cf0c67380b07 100644
> > > --- a/drivers/net/virtio_net.c
> > > +++ b/drivers/net/virtio_net.c
> > > @@ -46,6 +46,7 @@ module_param(napi_tx, bool, 0644);
> > >  #define VIRTIO_XDP_REDIR   BIT(1)
> > >
> > >  #define VIRTIO_XDP_FLAGBIT(0)
> > > +#define VIRTIO_DMA_FLAGBIT(1)
> > >
> > >  /* RX packet size EWMA. The average packet size is used to determine the 
> > > packet
> > >   * buffer size when refilling RX rings. As the entire RX ring may be 
> > > refilled
> > > @@ -140,6 +141,21 @@ struct virtnet_rq_dma {
> > > u16 need_sync;
> > >  };
> > >
> > > +struct virtnet_sq_dma {
> > > +   union {
> > > +   struct virtnet_sq_dma *next;
> > > +   void *data;
> > > +   };
> > > +   dma_addr_t addr;
> > > +   u32 len;
> > > +   bool is_tail;
> > > +};
> > > +
> > > +struct virtnet_sq_dma_head {
> > > +   struct virtnet_sq_dma *free;
> > > +   struct virtnet_sq_dma *head;
> >
> > Any reason the head must be a pointer instead of a simple index?
>
>
> The head is used for kfree.
> Maybe I need to rename it.
>
> About the index(next) of the virtnet_sq_dma.
> If we use the index, the struct will be:
>
> struct virtnet_sq_dma {
>dma_addr_t addr;
>u32 len;
>
>u32 next;
>void *data
> };
>
> The size of virtnet_sq_dma is same.

Ok.

>
>
> >
> > > +};
> > > +
> > >  /* Internal representation of a send virtqueue */
> > >  struct send_queue {
> > > /* Virtqueue associated with this send _queue */
> > > @@ -159,6 +175,8 @@ struct send_queue {
> > >
> > > /* Record whether sq is in reset state. */
> > > bool reset;
> > > +
> > > +   struct virtnet_sq_dma_head dmainfo;
> > >  };
> > >
>
> 
>
> > > +
> > > +static int virtnet_sq_init_dma_mate(struct send_queue *sq)
> > > +{
> > > +   struct virtnet_sq_dma *d;
> > > +   int size, i;
> > > +
> > > +   size = virtqueue_get_vring_size(sq->vq);
> > > +
> > > +   size += MAX_SKB_FRAGS + 2;
> >
> > Is this enough for the case where an indirect descriptor is used?
>
>
> This is for the case, when the ring is full, the xmit_skb is called.
>
> I will add comment.

Just to make sure we are at the same page.

I meant, we could have more pending #sg than allocated here.

For example, we can have up to (vring_size - 2 - MAX_SKB_FRAGS) *
MAX_SKB_FRAGS number of pending sgs?

Thanks

>
> Thanks.
>
>
> >
> > Thanks
> >
>




Re: [PATCH vhost 04/17] virtio_ring: split: remove double check of the unmap ops

2024-01-31 Thread Jason Wang
On Wed, Jan 31, 2024 at 5:43 PM Michael S. Tsirkin  wrote:
>
> On Wed, Jan 31, 2024 at 05:12:22PM +0800, Jason Wang wrote:
> > I post a patch to store flags unconditionally at:
> >
> > https://lore.kernel.org/all/20220224122655-mutt-send-email-...@kernel.org/
>
> what happened to it btw?

Haven't got time for a benchmark. We can evaluate whether we still
need it here and do the benchmark if yes.

Thanks

>
> --
> MST
>




Re: [PATCH vhost 06/17] virtio_ring: no store dma info when unmap is not needed

2024-02-01 Thread Jason Wang
On Thu, Feb 1, 2024 at 2:05 PM Xuan Zhuo  wrote:
>
> On Wed, 31 Jan 2024 17:12:29 +0800, Jason Wang  wrote:
> > On Tue, Jan 30, 2024 at 7:42 PM Xuan Zhuo  
> > wrote:
> > >
> > > As discussed:
> > > http://lore.kernel.org/all/CACGkMEug-=C+VQhkMYSgUKMC==04m7-uem_yc21bggkkzh8...@mail.gmail.com
> > >
> > > When the vq is premapped mode, the driver manages the dma
> > > info is a good way.
> > >
> > > So this commit make the virtio core not to store the dma
> > > info and release the memory which is used to store the dma
> > > info.
> > >
> > > If the use_dma_api is false, the memory is also not allocated.
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > ---

[...]

> > >
> > > @@ -1245,14 +1269,16 @@ static u16 packed_last_used(u16 last_used_idx)
> > >
> > >  /* caller must check vring_need_unmap_buffer() */
> > >  static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
> > > -const struct vring_desc_extra *extra)
> > > +unsigned int i)
> > >  {
> > > +   const struct vring_desc_extra *extra = &vq->packed.desc_extra[i];
> > > +   const struct vring_desc_dma *dma = &vq->packed.desc_dma[i];
> > > u16 flags;
> > >
> > > flags = extra->flags;
> >
> > I don't think this can be compiled.
>
> I do not find any error.
> Could you say more?

Sorry, I misread the code.

It should be fine.

Thanks

>
> Thanks.
>
>
> >
> > Thanks
> >
>




Re: [PATCH vhost 17/17] virtio_net: sq support premapped mode

2024-02-01 Thread Jason Wang
On Thu, Feb 1, 2024 at 2:01 PM Xuan Zhuo  wrote:
>
> On Thu, 1 Feb 2024 13:36:46 +0800, Jason Wang  wrote:
> > On Thu, Feb 1, 2024 at 11:28 AM Xuan Zhuo  
> > wrote:
> > >
> > > On Wed, 31 Jan 2024 17:12:47 +0800, Jason Wang  
> > > wrote:
> > > > On Tue, Jan 30, 2024 at 7:43 PM Xuan Zhuo  
> > > > wrote:
> > > > >
> > > > > If the xsk is enabling, the xsk tx will share the send queue.
> > > > > But the xsk requires that the send queue use the premapped mode.
> > > > > So the send queue must support premapped mode.
> > > > >
> > > > > Signed-off-by: Xuan Zhuo 
> > > > > ---
> > > > >  drivers/net/virtio_net.c | 167 
> > > > > ++-
> > > > >  1 file changed, 163 insertions(+), 4 deletions(-)
> > > > >
> > > > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > > > > index 226ab830870e..cf0c67380b07 100644
> > > > > --- a/drivers/net/virtio_net.c
> > > > > +++ b/drivers/net/virtio_net.c
> > > > > @@ -46,6 +46,7 @@ module_param(napi_tx, bool, 0644);
> > > > >  #define VIRTIO_XDP_REDIR   BIT(1)
> > > > >
> > > > >  #define VIRTIO_XDP_FLAGBIT(0)
> > > > > +#define VIRTIO_DMA_FLAGBIT(1)
> > > > >
> > > > >  /* RX packet size EWMA. The average packet size is used to determine 
> > > > > the packet
> > > > >   * buffer size when refilling RX rings. As the entire RX ring may be 
> > > > > refilled
> > > > > @@ -140,6 +141,21 @@ struct virtnet_rq_dma {
> > > > > u16 need_sync;
> > > > >  };
> > > > >
> > > > > +struct virtnet_sq_dma {
> > > > > +   union {
> > > > > +   struct virtnet_sq_dma *next;
> > > > > +   void *data;
> > > > > +   };
> > > > > +   dma_addr_t addr;
> > > > > +   u32 len;
> > > > > +   bool is_tail;
> > > > > +};
> > > > > +
> > > > > +struct virtnet_sq_dma_head {
> > > > > +   struct virtnet_sq_dma *free;
> > > > > +   struct virtnet_sq_dma *head;
> > > >
> > > > Any reason the head must be a pointer instead of a simple index?
> > >
> > >
> > > The head is used for kfree.
> > > Maybe I need to rename it.
> > >
> > > About the index(next) of the virtnet_sq_dma.
> > > If we use the index, the struct will be:
> > >
> > > struct virtnet_sq_dma {
> > >dma_addr_t addr;
> > >u32 len;
> > >
> > >u32 next;
> > >void *data
> > > };
> > >
> > > The size of virtnet_sq_dma is same.
> >
> > Ok.
> >
> > >
> > >
> > > >
> > > > > +};
> > > > > +
> > > > >  /* Internal representation of a send virtqueue */
> > > > >  struct send_queue {
> > > > > /* Virtqueue associated with this send _queue */
> > > > > @@ -159,6 +175,8 @@ struct send_queue {
> > > > >
> > > > > /* Record whether sq is in reset state. */
> > > > > bool reset;
> > > > > +
> > > > > +   struct virtnet_sq_dma_head dmainfo;
> > > > >  };
> > > > >
> > >
> > > 
> > >
> > > > > +
> > > > > +static int virtnet_sq_init_dma_mate(struct send_queue *sq)
> > > > > +{
> > > > > +   struct virtnet_sq_dma *d;
> > > > > +   int size, i;
> > > > > +
> > > > > +   size = virtqueue_get_vring_size(sq->vq);
> > > > > +
> > > > > +   size += MAX_SKB_FRAGS + 2;
> > > >
> > > > Is this enough for the case where an indirect descriptor is used?
> > >
> > >
> > > This is for the case, when the ring is full, the xmit_skb is called.
> > >
> > > I will add comment.
> >
> > Just to make sure we are at the same page.
> >
> > I meant, we could have more pending #sg than allocated here.
> >
> > For example, we can have up to (vring_size - 2 - MAX_SKB_FRAGS) *
> > MAX_SKB_FRAGS number of pending sgs?
> >
>
> Oh, my was wrong.
>
> But the max value a
> But shouldn't the maximum value be vring_size * (2 + MAX_SKB_FRAGS)?

This seems to be safer, yes.

>
> And for the reason above, we should allocate (vring_size + 1) * (2 + 
> MAX_SKB_FRAGS);

Then we need to benchmark to see if it has an impact on the performance.

Thanks

>
> Thanks.
>
>
> > Thanks
> >
> > >
> > > Thanks.
> > >
> > >
> > > >
> > > > Thanks
> > > >
> > >
> >
>




Re: [PATCH vhost v3 00/19] virtio: drivers maintain dma info for premapped vq

2024-03-06 Thread Jason Wang
On Wed, Mar 6, 2024 at 6:01 PM Xuan Zhuo  wrote:
>
> On Thu, 29 Feb 2024 04:34:20 -0500, "Michael S. Tsirkin"  
> wrote:
> > On Thu, Feb 29, 2024 at 05:02:37PM +0800, Xuan Zhuo wrote:
> > > On Thu, 29 Feb 2024 03:21:14 -0500, "Michael S. Tsirkin" 
> > >  wrote:
> > > > On Thu, Feb 29, 2024 at 03:20:25PM +0800, Xuan Zhuo wrote:
> > > > > As discussed:
> > > > > http://lore.kernel.org/all/cacgkmevq0no8qgc46u4mgsmtud44fd_cflcpavmj3rhyqrz...@mail.gmail.com
> > > > >
> > > > > If the virtio is premapped mode, the driver should manage the dma 
> > > > > info by self.
> > > > > So the virtio core should not store the dma info.
> > > > > So we can release the memory used to store the dma info.
> > > > >
> > > > > But if the desc_extra has not dma info, we face a new question,
> > > > > it is hard to get the dma info of the desc with indirect flag.
> > > > > For split mode, that is easy from desc, but for the packed mode,
> > > > > it is hard to get the dma info from the desc. And for hardening
> > > > > the dma unmap is saft, we should store the dma info of indirect
> > > > > descs.
> > > > >
> > > > > So I introduce the "structure the indirect desc table" to
> > > > > allocate space to store dma info with the desc table.
> > > > >
> > > > > On the other side, we mix the descs with indirect flag
> > > > > with other descs together to share the unmap api. That
> > > > > is complex. I found if we we distinguish the descs with
> > > > > VRING_DESC_F_INDIRECT before unmap, thing will be clearer.
> > > > >
> > > > > Because of the dma array is allocated in the find_vqs(),
> > > > > so I introduce a new parameter to find_vqs().
> > > > >
> > > > > Note:
> > > > > this is on the top of
> > > > > [PATCH vhost v1] virtio: packed: fix unmap leak for indirect 
> > > > > desc table
> > > > > 
> > > > > http://lore.kernel.org/all/20240223071833.26095-1-xuanz...@linux.alibaba.com
> > > > >
> > > > > Please review.
> > > > >
> > > > > Thanks
> > > > >
> > > > > v3:
> > > > > 1. fix the conflict with the vp_modern_create_avq().
> > > >
> > > > Okay but are you going to address huge memory waste all this is causing 
> > > > for
> > > > - people who never do zero copy
> > > > - systems where dma unmap is a nop
> > > >
> > > > ?
> > > >
> > > > You should address all comments when you post a new version, not just
> > > > what was expedient, or alternatively tag patch as RFC and explain
> > > > in commit log that you plan to do it later.
> > >
> > >
> > > Do you miss this one?
> > > http://lore.kernel.org/all/1708997579.5613105-1-xuanz...@linux.alibaba.com
> >
> >
> > I did. The answer is that no, you don't get to regress memory usage
> > for lots of people then fix it up.
> > So the patchset is big, I guess it will take a couple of cycles to
> > merge gradually.
>
> Hi @Michael
>
> So, how about this patch set?
>
> I do not think they (dma maintainers) will agree the API dma_can_skip_unmap().
>
> If you think sq wastes too much memory using pre-mapped dma mode, how about
> we only enable it when xsk is bond?
>
> Could you give me some advice?

I think we have some discussion, one possible solution is:

when pre mapping is enabled, virtio core won't store dma metadatas.

Then it makes virtio-net align with other NIC.

Thanks

>
> Thanks.
>
>
> >
> > > I asked you. But I didnot recv your answer.
> > >
> > > Thanks.
> > >
> > >
> > > >
> > > > > v2:
> > > > > 1. change the dma item of virtio-net, every item have 
> > > > > MAX_SKB_FRAGS + 2
> > > > > addr + len pairs.
> > > > > 2. introduce virtnet_sq_free_stats for __free_old_xmit
> > > > >
> > > > > v1:
> > > > > 1. rename transport_vq_config to vq_transport_config
> > > > > 2. virtio-net set dma meta number to (ring-size + 
> > > > > 1)(MAX_SKB_FRGAS +2)
> > > > > 3. introduce virtqueue_dma_map_sg_attrs
> > > > > 4. separate vring_create_virtqueue to an independent commit
> > > > >
> > > > >
> > > > >
> > > > > Xuan Zhuo (19):
> > > > >   virtio_ring: introduce vring_need_unmap_buffer
> > > > >   virtio_ring: packed: remove double check of the unmap ops
> > > > >   virtio_ring: packed: structure the indirect desc table
> > > > >   virtio_ring: split: remove double check of the unmap ops
> > > > >   virtio_ring: split: structure the indirect desc table
> > > > >   virtio_ring: no store dma info when unmap is not needed
> > > > >   virtio: find_vqs: pass struct instead of multi parameters
> > > > >   virtio: vring_create_virtqueue: pass struct instead of multi
> > > > > parameters
> > > > >   virtio: vring_new_virtqueue(): pass struct instead of multi 
> > > > > parameters
> > > > >   virtio_ring: simplify the parameters of the funcs related to
> > > > > vring_create/new_virtqueue()
> > > > >   virtio: find_vqs: add new parameter premapped
> > > > >   virtio_ring: export premapped to driver by struct virtqueue
> > > > >   virtio_net: set premapped mode by find_vqs()
> > > > >   virtio_ring: remove api of setting vq premap

Re: [PATCH vhost v3 00/19] virtio: drivers maintain dma info for premapped vq

2024-03-07 Thread Jason Wang
On Thu, Mar 7, 2024 at 4:15 PM Xuan Zhuo  wrote:
>
> On Thu, 7 Mar 2024 13:28:27 +0800, Jason Wang  wrote:
> > On Wed, Mar 6, 2024 at 6:01 PM Xuan Zhuo  wrote:
> > >
> > > On Thu, 29 Feb 2024 04:34:20 -0500, "Michael S. Tsirkin" 
> > >  wrote:
> > > > On Thu, Feb 29, 2024 at 05:02:37PM +0800, Xuan Zhuo wrote:
> > > > > On Thu, 29 Feb 2024 03:21:14 -0500, "Michael S. Tsirkin" 
> > > > >  wrote:
> > > > > > On Thu, Feb 29, 2024 at 03:20:25PM +0800, Xuan Zhuo wrote:
> > > > > > > As discussed:
> > > > > > > http://lore.kernel.org/all/cacgkmevq0no8qgc46u4mgsmtud44fd_cflcpavmj3rhyqrz...@mail.gmail.com
> > > > > > >
> > > > > > > If the virtio is premapped mode, the driver should manage the dma 
> > > > > > > info by self.
> > > > > > > So the virtio core should not store the dma info.
> > > > > > > So we can release the memory used to store the dma info.
> > > > > > >
> > > > > > > But if the desc_extra has not dma info, we face a new question,
> > > > > > > it is hard to get the dma info of the desc with indirect flag.
> > > > > > > For split mode, that is easy from desc, but for the packed mode,
> > > > > > > it is hard to get the dma info from the desc. And for hardening
> > > > > > > the dma unmap is saft, we should store the dma info of indirect
> > > > > > > descs.
> > > > > > >
> > > > > > > So I introduce the "structure the indirect desc table" to
> > > > > > > allocate space to store dma info with the desc table.
> > > > > > >
> > > > > > > On the other side, we mix the descs with indirect flag
> > > > > > > with other descs together to share the unmap api. That
> > > > > > > is complex. I found if we we distinguish the descs with
> > > > > > > VRING_DESC_F_INDIRECT before unmap, thing will be clearer.
> > > > > > >
> > > > > > > Because of the dma array is allocated in the find_vqs(),
> > > > > > > so I introduce a new parameter to find_vqs().
> > > > > > >
> > > > > > > Note:
> > > > > > > this is on the top of
> > > > > > > [PATCH vhost v1] virtio: packed: fix unmap leak for 
> > > > > > > indirect desc table
> > > > > > > 
> > > > > > > http://lore.kernel.org/all/20240223071833.26095-1-xuanz...@linux.alibaba.com
> > > > > > >
> > > > > > > Please review.
> > > > > > >
> > > > > > > Thanks
> > > > > > >
> > > > > > > v3:
> > > > > > > 1. fix the conflict with the vp_modern_create_avq().
> > > > > >
> > > > > > Okay but are you going to address huge memory waste all this is 
> > > > > > causing for
> > > > > > - people who never do zero copy
> > > > > > - systems where dma unmap is a nop
> > > > > >
> > > > > > ?
> > > > > >
> > > > > > You should address all comments when you post a new version, not 
> > > > > > just
> > > > > > what was expedient, or alternatively tag patch as RFC and explain
> > > > > > in commit log that you plan to do it later.
> > > > >
> > > > >
> > > > > Do you miss this one?
> > > > > http://lore.kernel.org/all/1708997579.5613105-1-xuanz...@linux.alibaba.com
> > > >
> > > >
> > > > I did. The answer is that no, you don't get to regress memory usage
> > > > for lots of people then fix it up.
> > > > So the patchset is big, I guess it will take a couple of cycles to
> > > > merge gradually.
> > >
> > > Hi @Michael
> > >
> > > So, how about this patch set?
> > >
> > > I do not think they (dma maintainers) will agree the API 
> > > dma_can_skip_unmap().
> > >
> > > If you think sq wastes too much memory using pre-mapped dma mode, how 
> > > about
> > > we only enable it when xsk is bond?
> > >
> > > Could you give me some advice?
> >
> > I think w

Re: [PATCH vhost v3 1/4] virtio: find_vqs: pass struct instead of multi parameters

2024-03-13 Thread Jason Wang
On Tue, Mar 12, 2024 at 10:10 AM Xuan Zhuo  wrote:
>
> Now, we pass multi parameters to find_vqs. These parameters
> may work for transport or work for vring.
>
> And find_vqs has multi implements in many places:
>
>  arch/um/drivers/virtio_uml.c
>  drivers/platform/mellanox/mlxbf-tmfifo.c
>  drivers/remoteproc/remoteproc_virtio.c
>  drivers/s390/virtio/virtio_ccw.c
>  drivers/virtio/virtio_mmio.c
>  drivers/virtio/virtio_pci_legacy.c
>  drivers/virtio/virtio_pci_modern.c
>  drivers/virtio/virtio_vdpa.c
>
> Every time, we try to add a new parameter, that is difficult.
> We must change every find_vqs implement.
>
> One the other side, if we want to pass a parameter to vring,
> we must change the call path from transport to vring.
> Too many functions need to be changed.
>
> So it is time to refactor the find_vqs. We pass a structure
> cfg to find_vqs(), that will be passed to vring by transport.
>
> Because the vp_modern_create_avq() use the "const char *names[]",
> and the virtio_uml.c changes the name in the subsequent commit, so
> change the "names" inside the virtio_vq_config from "const char *const
> *names" to "const char **names".
>
> Signed-off-by: Xuan Zhuo 
> Acked-by: Johannes Berg 
> Reviewed-by: Ilpo J=E4rvinen 

The name seems broken here.

[...]

>
>  typedef void vq_callback_t(struct virtqueue *);
>
> +/**
> + * struct virtio_vq_config - configure for find_vqs()
> + * @cfg_idx: Used by virtio core. The drivers should set this to 0.
> + * During the initialization of each vq(vring setup), we need to know 
> which
> + * item in the array should be used at that time. But since the item in
> + * names can be null, which causes some item of array to be skipped, we
> + * cannot use vq.index as the current id. So add a cfg_idx to let vring
> + * know how to get the current configuration from the array when
> + * initializing vq.

So this design is not good. If it is not something that the driver
needs to care about, the core needs to hide it from the API.

Thanks




Re: [PATCH vhost v3 1/4] virtio: find_vqs: pass struct instead of multi parameters

2024-03-14 Thread Jason Wang
On Thu, Mar 14, 2024 at 2:00 PM Xuan Zhuo  wrote:
>
> On Thu, 14 Mar 2024 11:12:24 +0800, Jason Wang  wrote:
> > On Tue, Mar 12, 2024 at 10:10 AM Xuan Zhuo  
> > wrote:
> > >
> > > Now, we pass multi parameters to find_vqs. These parameters
> > > may work for transport or work for vring.
> > >
> > > And find_vqs has multi implements in many places:
> > >
> > >  arch/um/drivers/virtio_uml.c
> > >  drivers/platform/mellanox/mlxbf-tmfifo.c
> > >  drivers/remoteproc/remoteproc_virtio.c
> > >  drivers/s390/virtio/virtio_ccw.c
> > >  drivers/virtio/virtio_mmio.c
> > >  drivers/virtio/virtio_pci_legacy.c
> > >  drivers/virtio/virtio_pci_modern.c
> > >  drivers/virtio/virtio_vdpa.c
> > >
> > > Every time, we try to add a new parameter, that is difficult.
> > > We must change every find_vqs implement.
> > >
> > > One the other side, if we want to pass a parameter to vring,
> > > we must change the call path from transport to vring.
> > > Too many functions need to be changed.
> > >
> > > So it is time to refactor the find_vqs. We pass a structure
> > > cfg to find_vqs(), that will be passed to vring by transport.
> > >
> > > Because the vp_modern_create_avq() use the "const char *names[]",
> > > and the virtio_uml.c changes the name in the subsequent commit, so
> > > change the "names" inside the virtio_vq_config from "const char *const
> > > *names" to "const char **names".
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > Acked-by: Johannes Berg 
> > > Reviewed-by: Ilpo J=E4rvinen 
> >
> > The name seems broken here.
>
> Email APP bug.
>
> I will fix.
>
>
> >
> > [...]
> >
> > >
> > >  typedef void vq_callback_t(struct virtqueue *);
> > >
> > > +/**
> > > + * struct virtio_vq_config - configure for find_vqs()
> > > + * @cfg_idx: Used by virtio core. The drivers should set this to 0.
> > > + * During the initialization of each vq(vring setup), we need to 
> > > know which
> > > + * item in the array should be used at that time. But since the item 
> > > in
> > > + * names can be null, which causes some item of array to be skipped, 
> > > we
> > > + * cannot use vq.index as the current id. So add a cfg_idx to let 
> > > vring
> > > + * know how to get the current configuration from the array when
> > > + * initializing vq.
> >
> > So this design is not good. If it is not something that the driver
> > needs to care about, the core needs to hide it from the API.
>
> The driver just ignore it. That will be beneficial to the virtio core.
> Otherwise, we must pass one more parameter everywhere.

I don't get here, it's an internal logic and we've already done that.

Thanks

>
> Thanks.
>
> >
> > Thanks
> >
>




Re: [PATCH vhost v3 1/4] virtio: find_vqs: pass struct instead of multi parameters

2024-03-17 Thread Jason Wang
On Fri, Mar 15, 2024 at 3:26 PM Xuan Zhuo  wrote:
>
> On Fri, 15 Mar 2024 11:51:48 +0800, Jason Wang  wrote:
> > On Thu, Mar 14, 2024 at 2:00 PM Xuan Zhuo  
> > wrote:
> > >
> > > On Thu, 14 Mar 2024 11:12:24 +0800, Jason Wang  
> > > wrote:
> > > > On Tue, Mar 12, 2024 at 10:10 AM Xuan Zhuo  
> > > > wrote:
> > > > >
> > > > > Now, we pass multi parameters to find_vqs. These parameters
> > > > > may work for transport or work for vring.
> > > > >
> > > > > And find_vqs has multi implements in many places:
> > > > >
> > > > >  arch/um/drivers/virtio_uml.c
> > > > >  drivers/platform/mellanox/mlxbf-tmfifo.c
> > > > >  drivers/remoteproc/remoteproc_virtio.c
> > > > >  drivers/s390/virtio/virtio_ccw.c
> > > > >  drivers/virtio/virtio_mmio.c
> > > > >  drivers/virtio/virtio_pci_legacy.c
> > > > >  drivers/virtio/virtio_pci_modern.c
> > > > >  drivers/virtio/virtio_vdpa.c
> > > > >
> > > > > Every time, we try to add a new parameter, that is difficult.
> > > > > We must change every find_vqs implement.
> > > > >
> > > > > One the other side, if we want to pass a parameter to vring,
> > > > > we must change the call path from transport to vring.
> > > > > Too many functions need to be changed.
> > > > >
> > > > > So it is time to refactor the find_vqs. We pass a structure
> > > > > cfg to find_vqs(), that will be passed to vring by transport.
> > > > >
> > > > > Because the vp_modern_create_avq() use the "const char *names[]",
> > > > > and the virtio_uml.c changes the name in the subsequent commit, so
> > > > > change the "names" inside the virtio_vq_config from "const char *const
> > > > > *names" to "const char **names".
> > > > >
> > > > > Signed-off-by: Xuan Zhuo 
> > > > > Acked-by: Johannes Berg 
> > > > > Reviewed-by: Ilpo J=E4rvinen 
> > > >
> > > > The name seems broken here.
> > >
> > > Email APP bug.
> > >
> > > I will fix.
> > >
> > >
> > > >
> > > > [...]
> > > >
> > > > >
> > > > >  typedef void vq_callback_t(struct virtqueue *);
> > > > >
> > > > > +/**
> > > > > + * struct virtio_vq_config - configure for find_vqs()
> > > > > + * @cfg_idx: Used by virtio core. The drivers should set this to 0.
> > > > > + * During the initialization of each vq(vring setup), we need to 
> > > > > know which
> > > > > + * item in the array should be used at that time. But since the 
> > > > > item in
> > > > > + * names can be null, which causes some item of array to be 
> > > > > skipped, we
> > > > > + * cannot use vq.index as the current id. So add a cfg_idx to 
> > > > > let vring
> > > > > + * know how to get the current configuration from the array when
> > > > > + * initializing vq.
> > > >
> > > > So this design is not good. If it is not something that the driver
> > > > needs to care about, the core needs to hide it from the API.
> > >
> > > The driver just ignore it. That will be beneficial to the virtio core.
> > > Otherwise, we must pass one more parameter everywhere.
> >
> > I don't get here, it's an internal logic and we've already done that.
>
>
> ## Then these must add one param "cfg_idx";
>
>  struct virtqueue *vring_create_virtqueue(struct virtio_device *vdev,
>  unsigned int index,
>  struct vq_transport_config *tp_cfg,
>  struct virtio_vq_config *cfg,
> -->  uint cfg_idx);
>
>  struct virtqueue *vring_new_virtqueue(struct virtio_device *vdev,
>   unsigned int index,
>   void *pages,
>   struct vq_transport_config *tp_cfg,
>   struct virtio_vq_config *cfg,
> -->  uint cfg_idx);
>
>
> ## The functions inside virtio_ring also need to add a new param, such as:
>
>  static struct virtqueue *vring_create_virtqueue_split(struct virtio_device 
> *vdev,
>   unsigned int index,
>   struct 
> vq_transport_config *tp_cfg,
>   struct virtio_vq_config,
> -->   uint cfg_idx);
>
>
>

I guess what I'm missing is when could the index differ from cfg_idx?

Thanks

> Thanks.
>
>
>
>
> >
> > Thanks
> >
> > >
> > > Thanks.
> > >
> > > >
> > > > Thanks
> > > >
> > >
> >
>




Re: [PATCH vhost v3 1/4] virtio: find_vqs: pass struct instead of multi parameters

2024-03-20 Thread Jason Wang
On Tue, Mar 19, 2024 at 2:58 PM Michael S. Tsirkin  wrote:
>
> On Mon, Mar 18, 2024 at 01:59:52PM +0800, Xuan Zhuo wrote:
> > On Mon, 18 Mar 2024 12:18:23 +0800, Jason Wang  wrote:
> > > On Fri, Mar 15, 2024 at 3:26 PM Xuan Zhuo  
> > > wrote:
> > > >
> > > > On Fri, 15 Mar 2024 11:51:48 +0800, Jason Wang  
> > > > wrote:
> > > > > On Thu, Mar 14, 2024 at 2:00 PM Xuan Zhuo 
> > > > >  wrote:
> > > > > >
> > > > > > On Thu, 14 Mar 2024 11:12:24 +0800, Jason Wang 
> > > > > >  wrote:
> > > > > > > On Tue, Mar 12, 2024 at 10:10 AM Xuan Zhuo 
> > > > > > >  wrote:
> > > > > > > >
> > > > > > > > Now, we pass multi parameters to find_vqs. These parameters
> > > > > > > > may work for transport or work for vring.
> > > > > > > >
> > > > > > > > And find_vqs has multi implements in many places:
> > > > > > > >
> > > > > > > >  arch/um/drivers/virtio_uml.c
> > > > > > > >  drivers/platform/mellanox/mlxbf-tmfifo.c
> > > > > > > >  drivers/remoteproc/remoteproc_virtio.c
> > > > > > > >  drivers/s390/virtio/virtio_ccw.c
> > > > > > > >  drivers/virtio/virtio_mmio.c
> > > > > > > >  drivers/virtio/virtio_pci_legacy.c
> > > > > > > >  drivers/virtio/virtio_pci_modern.c
> > > > > > > >  drivers/virtio/virtio_vdpa.c
> > > > > > > >
> > > > > > > > Every time, we try to add a new parameter, that is difficult.
> > > > > > > > We must change every find_vqs implement.
> > > > > > > >
> > > > > > > > One the other side, if we want to pass a parameter to vring,
> > > > > > > > we must change the call path from transport to vring.
> > > > > > > > Too many functions need to be changed.
> > > > > > > >
> > > > > > > > So it is time to refactor the find_vqs. We pass a structure
> > > > > > > > cfg to find_vqs(), that will be passed to vring by transport.
> > > > > > > >
> > > > > > > > Because the vp_modern_create_avq() use the "const char 
> > > > > > > > *names[]",
> > > > > > > > and the virtio_uml.c changes the name in the subsequent commit, 
> > > > > > > > so
> > > > > > > > change the "names" inside the virtio_vq_config from "const char 
> > > > > > > > *const
> > > > > > > > *names" to "const char **names".
> > > > > > > >
> > > > > > > > Signed-off-by: Xuan Zhuo 
> > > > > > > > Acked-by: Johannes Berg 
> > > > > > > > Reviewed-by: Ilpo J=E4rvinen 
> > > > > > >
> > > > > > > The name seems broken here.
> > > > > >
> > > > > > Email APP bug.
> > > > > >
> > > > > > I will fix.
> > > > > >
> > > > > >
> > > > > > >
> > > > > > > [...]
> > > > > > >
> > > > > > > >
> > > > > > > >  typedef void vq_callback_t(struct virtqueue *);
> > > > > > > >
> > > > > > > > +/**
> > > > > > > > + * struct virtio_vq_config - configure for find_vqs()
> > > > > > > > + * @cfg_idx: Used by virtio core. The drivers should set this 
> > > > > > > > to 0.
> > > > > > > > + * During the initialization of each vq(vring setup), we 
> > > > > > > > need to know which
> > > > > > > > + * item in the array should be used at that time. But 
> > > > > > > > since the item in
> > > > > > > > + * names can be null, which causes some item of array to 
> > > > > > > > be skipped, we
> > > > > > > > + * cannot use vq.index as the current id. So add a cfg_idx 
> > > > > > > > to let vring
> > > > > > > > + * know how to get the current configuration from the 
> > >

Re: [PATCH vhost v3 1/4] virtio: find_vqs: pass struct instead of multi parameters

2024-03-20 Thread Jason Wang
On Wed, Mar 20, 2024 at 5:22 PM Jason Wang  wrote:
>
> On Tue, Mar 19, 2024 at 2:58 PM Michael S. Tsirkin  wrote:
> >
> > On Mon, Mar 18, 2024 at 01:59:52PM +0800, Xuan Zhuo wrote:
> > > On Mon, 18 Mar 2024 12:18:23 +0800, Jason Wang  
> > > wrote:
> > > > On Fri, Mar 15, 2024 at 3:26 PM Xuan Zhuo  
> > > > wrote:
> > > > >
> > > > > On Fri, 15 Mar 2024 11:51:48 +0800, Jason Wang  
> > > > > wrote:
> > > > > > On Thu, Mar 14, 2024 at 2:00 PM Xuan Zhuo 
> > > > > >  wrote:
> > > > > > >
> > > > > > > On Thu, 14 Mar 2024 11:12:24 +0800, Jason Wang 
> > > > > > >  wrote:
> > > > > > > > On Tue, Mar 12, 2024 at 10:10 AM Xuan Zhuo 
> > > > > > > >  wrote:
> > > > > > > > >
> > > > > > > > > Now, we pass multi parameters to find_vqs. These parameters
> > > > > > > > > may work for transport or work for vring.
> > > > > > > > >
> > > > > > > > > And find_vqs has multi implements in many places:
> > > > > > > > >
> > > > > > > > >  arch/um/drivers/virtio_uml.c
> > > > > > > > >  drivers/platform/mellanox/mlxbf-tmfifo.c
> > > > > > > > >  drivers/remoteproc/remoteproc_virtio.c
> > > > > > > > >  drivers/s390/virtio/virtio_ccw.c
> > > > > > > > >  drivers/virtio/virtio_mmio.c
> > > > > > > > >  drivers/virtio/virtio_pci_legacy.c
> > > > > > > > >  drivers/virtio/virtio_pci_modern.c
> > > > > > > > >  drivers/virtio/virtio_vdpa.c
> > > > > > > > >
> > > > > > > > > Every time, we try to add a new parameter, that is difficult.
> > > > > > > > > We must change every find_vqs implement.
> > > > > > > > >
> > > > > > > > > One the other side, if we want to pass a parameter to vring,
> > > > > > > > > we must change the call path from transport to vring.
> > > > > > > > > Too many functions need to be changed.
> > > > > > > > >
> > > > > > > > > So it is time to refactor the find_vqs. We pass a structure
> > > > > > > > > cfg to find_vqs(), that will be passed to vring by transport.
> > > > > > > > >
> > > > > > > > > Because the vp_modern_create_avq() use the "const char 
> > > > > > > > > *names[]",
> > > > > > > > > and the virtio_uml.c changes the name in the subsequent 
> > > > > > > > > commit, so
> > > > > > > > > change the "names" inside the virtio_vq_config from "const 
> > > > > > > > > char *const
> > > > > > > > > *names" to "const char **names".
> > > > > > > > >
> > > > > > > > > Signed-off-by: Xuan Zhuo 
> > > > > > > > > Acked-by: Johannes Berg 
> > > > > > > > > Reviewed-by: Ilpo J=E4rvinen 
> > > > > > > >
> > > > > > > > The name seems broken here.
> > > > > > >
> > > > > > > Email APP bug.
> > > > > > >
> > > > > > > I will fix.
> > > > > > >
> > > > > > >
> > > > > > > >
> > > > > > > > [...]
> > > > > > > >
> > > > > > > > >
> > > > > > > > >  typedef void vq_callback_t(struct virtqueue *);
> > > > > > > > >
> > > > > > > > > +/**
> > > > > > > > > + * struct virtio_vq_config - configure for find_vqs()
> > > > > > > > > + * @cfg_idx: Used by virtio core. The drivers should set 
> > > > > > > > > this to 0.
> > > > > > > > > + * During the initialization of each vq(vring setup), we 
> > > > > > > > > need to know which
> > > > > > > > > + * item in the array should be used at that time. But 
> > > > > > > > > sinc

Re: [PATCH vhost v3 1/4] virtio: find_vqs: pass struct instead of multi parameters

2024-03-20 Thread Jason Wang
On Wed, Mar 20, 2024 at 6:07 PM Xuan Zhuo  wrote:
>
> On Wed, 20 Mar 2024 17:39:29 +0800, Xuan Zhuo  
> wrote:
> > On Wed, 20 Mar 2024 17:22:50 +0800, Jason Wang  wrote:
> > > On Tue, Mar 19, 2024 at 2:58 PM Michael S. Tsirkin  
> > > wrote:
> > > >
> > > > On Mon, Mar 18, 2024 at 01:59:52PM +0800, Xuan Zhuo wrote:
> > > > > On Mon, 18 Mar 2024 12:18:23 +0800, Jason Wang  
> > > > > wrote:
> > > > > > On Fri, Mar 15, 2024 at 3:26 PM Xuan Zhuo 
> > > > > >  wrote:
> > > > > > >
> > > > > > > On Fri, 15 Mar 2024 11:51:48 +0800, Jason Wang 
> > > > > > >  wrote:
> > > > > > > > On Thu, Mar 14, 2024 at 2:00 PM Xuan Zhuo 
> > > > > > > >  wrote:
> > > > > > > > >
> > > > > > > > > On Thu, 14 Mar 2024 11:12:24 +0800, Jason Wang 
> > > > > > > > >  wrote:
> > > > > > > > > > On Tue, Mar 12, 2024 at 10:10 AM Xuan Zhuo 
> > > > > > > > > >  wrote:
> > > > > > > > > > >
> > > > > > > > > > > Now, we pass multi parameters to find_vqs. These 
> > > > > > > > > > > parameters
> > > > > > > > > > > may work for transport or work for vring.
> > > > > > > > > > >
> > > > > > > > > > > And find_vqs has multi implements in many places:
> > > > > > > > > > >
> > > > > > > > > > >  arch/um/drivers/virtio_uml.c
> > > > > > > > > > >  drivers/platform/mellanox/mlxbf-tmfifo.c
> > > > > > > > > > >  drivers/remoteproc/remoteproc_virtio.c
> > > > > > > > > > >  drivers/s390/virtio/virtio_ccw.c
> > > > > > > > > > >  drivers/virtio/virtio_mmio.c
> > > > > > > > > > >  drivers/virtio/virtio_pci_legacy.c
> > > > > > > > > > >  drivers/virtio/virtio_pci_modern.c
> > > > > > > > > > >  drivers/virtio/virtio_vdpa.c
> > > > > > > > > > >
> > > > > > > > > > > Every time, we try to add a new parameter, that is 
> > > > > > > > > > > difficult.
> > > > > > > > > > > We must change every find_vqs implement.
> > > > > > > > > > >
> > > > > > > > > > > One the other side, if we want to pass a parameter to 
> > > > > > > > > > > vring,
> > > > > > > > > > > we must change the call path from transport to vring.
> > > > > > > > > > > Too many functions need to be changed.
> > > > > > > > > > >
> > > > > > > > > > > So it is time to refactor the find_vqs. We pass a 
> > > > > > > > > > > structure
> > > > > > > > > > > cfg to find_vqs(), that will be passed to vring by 
> > > > > > > > > > > transport.
> > > > > > > > > > >
> > > > > > > > > > > Because the vp_modern_create_avq() use the "const char 
> > > > > > > > > > > *names[]",
> > > > > > > > > > > and the virtio_uml.c changes the name in the subsequent 
> > > > > > > > > > > commit, so
> > > > > > > > > > > change the "names" inside the virtio_vq_config from 
> > > > > > > > > > > "const char *const
> > > > > > > > > > > *names" to "const char **names".
> > > > > > > > > > >
> > > > > > > > > > > Signed-off-by: Xuan Zhuo 
> > > > > > > > > > > Acked-by: Johannes Berg 
> > > > > > > > > > > Reviewed-by: Ilpo J=E4rvinen 
> > > > > > > > > > > 
> > > > > > > > > >
> > > > > > > > > > The name seems broken here.
> > > > > > > > >
> > > > > > > > > Email APP bug.
> > > > &

Re: [PATCH vhost v3 1/4] virtio: find_vqs: pass struct instead of multi parameters

2024-03-20 Thread Jason Wang
On Wed, Mar 20, 2024 at 5:41 PM Xuan Zhuo  wrote:
>
> On Wed, 20 Mar 2024 17:22:50 +0800, Jason Wang  wrote:
> > On Tue, Mar 19, 2024 at 2:58 PM Michael S. Tsirkin  wrote:
> > >
> > > On Mon, Mar 18, 2024 at 01:59:52PM +0800, Xuan Zhuo wrote:
> > > > On Mon, 18 Mar 2024 12:18:23 +0800, Jason Wang  
> > > > wrote:
> > > > > On Fri, Mar 15, 2024 at 3:26 PM Xuan Zhuo 
> > > > >  wrote:
> > > > > >
> > > > > > On Fri, 15 Mar 2024 11:51:48 +0800, Jason Wang 
> > > > > >  wrote:
> > > > > > > On Thu, Mar 14, 2024 at 2:00 PM Xuan Zhuo 
> > > > > > >  wrote:
> > > > > > > >
> > > > > > > > On Thu, 14 Mar 2024 11:12:24 +0800, Jason Wang 
> > > > > > > >  wrote:
> > > > > > > > > On Tue, Mar 12, 2024 at 10:10 AM Xuan Zhuo 
> > > > > > > > >  wrote:
> > > > > > > > > >
> > > > > > > > > > Now, we pass multi parameters to find_vqs. These parameters
> > > > > > > > > > may work for transport or work for vring.
> > > > > > > > > >
> > > > > > > > > > And find_vqs has multi implements in many places:
> > > > > > > > > >
> > > > > > > > > >  arch/um/drivers/virtio_uml.c
> > > > > > > > > >  drivers/platform/mellanox/mlxbf-tmfifo.c
> > > > > > > > > >  drivers/remoteproc/remoteproc_virtio.c
> > > > > > > > > >  drivers/s390/virtio/virtio_ccw.c
> > > > > > > > > >  drivers/virtio/virtio_mmio.c
> > > > > > > > > >  drivers/virtio/virtio_pci_legacy.c
> > > > > > > > > >  drivers/virtio/virtio_pci_modern.c
> > > > > > > > > >  drivers/virtio/virtio_vdpa.c
> > > > > > > > > >
> > > > > > > > > > Every time, we try to add a new parameter, that is 
> > > > > > > > > > difficult.
> > > > > > > > > > We must change every find_vqs implement.
> > > > > > > > > >
> > > > > > > > > > One the other side, if we want to pass a parameter to vring,
> > > > > > > > > > we must change the call path from transport to vring.
> > > > > > > > > > Too many functions need to be changed.
> > > > > > > > > >
> > > > > > > > > > So it is time to refactor the find_vqs. We pass a structure
> > > > > > > > > > cfg to find_vqs(), that will be passed to vring by 
> > > > > > > > > > transport.
> > > > > > > > > >
> > > > > > > > > > Because the vp_modern_create_avq() use the "const char 
> > > > > > > > > > *names[]",
> > > > > > > > > > and the virtio_uml.c changes the name in the subsequent 
> > > > > > > > > > commit, so
> > > > > > > > > > change the "names" inside the virtio_vq_config from "const 
> > > > > > > > > > char *const
> > > > > > > > > > *names" to "const char **names".
> > > > > > > > > >
> > > > > > > > > > Signed-off-by: Xuan Zhuo 
> > > > > > > > > > Acked-by: Johannes Berg 
> > > > > > > > > > Reviewed-by: Ilpo J=E4rvinen 
> > > > > > > > >
> > > > > > > > > The name seems broken here.
> > > > > > > >
> > > > > > > > Email APP bug.
> > > > > > > >
> > > > > > > > I will fix.
> > > > > > > >
> > > > > > > >
> > > > > > > > >
> > > > > > > > > [...]
> > > > > > > > >
> > > > > > > > > >
> > > > > > > > > >  typedef void vq_callback_t(struct virtqueue *);
> > > > > > > > > >
> > > > > > > > > > +/**
> > > > > > > > > > + 

Re: [PATCH vhost v4 1/6] virtio_balloon: remove the dependence where names[] is null

2024-03-25 Thread Jason Wang
On Mon, Mar 25, 2024 at 5:44 PM Cornelia Huck  wrote:
>
> On Mon, Mar 25 2024, Xuan Zhuo  wrote:
>
> > On Fri, 22 Mar 2024 22:02:27 +0100, David Hildenbrand  
> > wrote:
> >> On 22.03.24 20:16, Daniel Verkamp wrote:
> >> > On Thu, Mar 21, 2024 at 3:16 AM Xuan Zhuo  
> >> > wrote:
> >> >>
> >> >> Currently, the init_vqs function within the virtio_balloon driver relies
> >> >> on the condition that certain names array entries are null in order to
> >> >> skip the initialization of some virtual queues (vqs). This behavior is
> >> >> unique to this part of the codebase. In an upcoming commit, we plan to
> >> >> eliminate this dependency by removing the function entirely. Therefore,
> >> >> with this change, we are ensuring that the virtio_balloon no longer
> >> >> depends on the aforementioned function.
> >> >
> >> > This is a behavior change, and I believe means that the driver no
> >> > longer follows the spec [1].
> >> >
> >> > For example, the spec says that virtqueue 4 is reporting_vq, and
> >> > reporting_vq only exists if VIRTIO_BALLOON_F_PAGE_REPORTING is set,
> >> > but there is no mention of its virtqueue number changing if other
> >> > features are not set. If a device/driver combination negotiates
> >> > VIRTIO_BALLOON_F_PAGE_REPORTING but not VIRTIO_BALLOON_F_STATS_VQ or
> >> > VIRTIO_BALLOON_F_FREE_PAGE_HINT, my reading of the specification is
> >> > that reporting_vq should still be vq number 4, and vq 2 and 3 should
> >> > be unused. This patch would make the reporting_vq use vq 2 instead in
> >> > this case.
> >> >
> >> > If the new behavior is truly intended, then the spec does not match
> >> > reality, and it would need to be changed first (IMO); however,
> >> > changing the spec would mean that any devices implemented correctly
> >> > per the previous spec would now be wrong, so some kind of mechanism
> >> > for detecting the new behavior would be warranted, e.g. a new
> >> > non-device-specific virtio feature flag.
> >> >
> >> > I have brought this up previously on the virtio-comment list [2], but
> >> > it did not receive any satisfying answers at that time.
>
> I had missed it back then, but now that I read it, I realize that we
> really have a bit of a mess here :/
>
> >>
> >> Rings a bell, but staring at this patch, I thought that there would be
> >> no behavioral change. Maybe I missed it :/
> >>
> >> I stared at virtio_ccw_find_vqs(), and it contains:
> >>
> >>  for (i = 0; i < nvqs; ++i) {
> >>  if (!names[i]) {
> >>  vqs[i] = NULL;
> >>  continue;
> >>  }
> >>
> >>  vqs[i] = virtio_ccw_setup_vq(vdev, queue_idx++, callbacks[i],
> >>   names[i], ctx ? ctx[i] : false,
> >>   ccw);
> >>  if (IS_ERR(vqs[i])) {
> >>  ret = PTR_ERR(vqs[i]);
> >>  vqs[i] = NULL;
> >>  goto out;
> >>  }
> >>  }
> >>
> >> We increment queue_idx only if an entry was not NULL. SO I thought no
> >> behavioral change? (at least on s390x :) )
>
> The code for pci behaves in the same way.
>
> >>
> >> It's late here in Germany, so maybe I'm missing something.
> >
> > I think we've encountered a tricky issue. Currently, all transports handle 
> > queue
> > id by incrementing them in order, without skipping any queue id. So, I'm 
> > quite
> > surprised that my changes would affect the spec. The fact that the
> > 'names' value is null is just a small trick in the Linux kernel 
> > implementation
> > and should not have an impact on the queue id.
> >
> > I believe that my recent modification will not affect the spec. So, let's
> > consider the issues with this patch set separately for now. Regarding the 
> > Memory
> > Balloon Device, it has been operational for many years, and perhaps we 
> > should
> > add to the spec that if a certain vq does not exist, then subsequent vqs 
> > will
> > take over its id.
>
> The changes here do not really seem to affect the spec issue that Daniel
> had noted, unless I'm reading the code wrong.

Spec seems to be wrong here:

5.5.2 Virtqueues

0 inflateq 1 deflateq 2 statsq 3 free_page_vq4 r eporting_vq

And this is the Qemu implementation:

5.5.2 Virtqueues

s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats);

if (virtio_has_feature(s->host_features, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
s->free_page_vq = virtio_add_queue(vdev, VIRTQUEUE_MAX_SIZE,
   virtio_balloon_handle_free_page_vq);
precopy_add_notifier(&s->free_page_hint_notify);

object_ref(OBJECT(s->iothread));
s->free_page_bh =
aio_bh_new_guarded(iothread_get_aio_context(s->iothread),

virtio_ballloon_get_free_page_hints, s,
   

Re: [PATCH vhost v5 1/6] virtio_balloon: remove the dependence where names[] is null

2024-03-25 Thread Jason Wang
On Mon, Mar 25, 2024 at 5:04 PM Xuan Zhuo  wrote:
>
> Currently, the init_vqs function within the virtio_balloon driver relies
> on the condition that certain names array entries are null in order to
> skip the initialization of some virtual queues (vqs).

If there's a respin I would add something like:

1) the virtqueue index is contiguous for all the existing devices.
2) the current behaviour of virtio-balloon device is different from
what is described in the spec 1.0-1.2
3) there's no functional changes and explain why

> This behavior is
> unique to this part of the codebase. In an upcoming commit, we plan to
> eliminate this dependency by removing the function entirely. Therefore,
> with this change, we are ensuring that the virtio_balloon no longer
> depends on the aforementioned function.
>
> Signed-off-by: Xuan Zhuo 

With the above tweak.

Acked-by: Jason Wang 

Thanks




Re: [PATCH vhost v4 1/6] virtio_balloon: remove the dependence where names[] is null

2024-03-25 Thread Jason Wang
On Tue, Mar 26, 2024 at 12:11 PM Jason Wang  wrote:
>
> On Mon, Mar 25, 2024 at 5:44 PM Cornelia Huck  wrote:
> >
> > On Mon, Mar 25 2024, Xuan Zhuo  wrote:
> >
> > > On Fri, 22 Mar 2024 22:02:27 +0100, David Hildenbrand  
> > > wrote:
> > >> On 22.03.24 20:16, Daniel Verkamp wrote:
> > >> > On Thu, Mar 21, 2024 at 3:16 AM Xuan Zhuo  
> > >> > wrote:
> > >> >>
> > >> >> Currently, the init_vqs function within the virtio_balloon driver 
> > >> >> relies
> > >> >> on the condition that certain names array entries are null in order to
> > >> >> skip the initialization of some virtual queues (vqs). This behavior is
> > >> >> unique to this part of the codebase. In an upcoming commit, we plan to
> > >> >> eliminate this dependency by removing the function entirely. 
> > >> >> Therefore,
> > >> >> with this change, we are ensuring that the virtio_balloon no longer
> > >> >> depends on the aforementioned function.
> > >> >
> > >> > This is a behavior change, and I believe means that the driver no
> > >> > longer follows the spec [1].
> > >> >
> > >> > For example, the spec says that virtqueue 4 is reporting_vq, and
> > >> > reporting_vq only exists if VIRTIO_BALLOON_F_PAGE_REPORTING is set,
> > >> > but there is no mention of its virtqueue number changing if other
> > >> > features are not set. If a device/driver combination negotiates
> > >> > VIRTIO_BALLOON_F_PAGE_REPORTING but not VIRTIO_BALLOON_F_STATS_VQ or
> > >> > VIRTIO_BALLOON_F_FREE_PAGE_HINT, my reading of the specification is
> > >> > that reporting_vq should still be vq number 4, and vq 2 and 3 should
> > >> > be unused. This patch would make the reporting_vq use vq 2 instead in
> > >> > this case.
> > >> >
> > >> > If the new behavior is truly intended, then the spec does not match
> > >> > reality, and it would need to be changed first (IMO); however,
> > >> > changing the spec would mean that any devices implemented correctly
> > >> > per the previous spec would now be wrong, so some kind of mechanism
> > >> > for detecting the new behavior would be warranted, e.g. a new
> > >> > non-device-specific virtio feature flag.
> > >> >
> > >> > I have brought this up previously on the virtio-comment list [2], but
> > >> > it did not receive any satisfying answers at that time.
> >
> > I had missed it back then, but now that I read it, I realize that we
> > really have a bit of a mess here :/
> >
> > >>
> > >> Rings a bell, but staring at this patch, I thought that there would be
> > >> no behavioral change. Maybe I missed it :/
> > >>
> > >> I stared at virtio_ccw_find_vqs(), and it contains:
> > >>
> > >>  for (i = 0; i < nvqs; ++i) {
> > >>  if (!names[i]) {
> > >>  vqs[i] = NULL;
> > >>  continue;
> > >>  }
> > >>
> > >>  vqs[i] = virtio_ccw_setup_vq(vdev, queue_idx++, 
> > >> callbacks[i],
> > >>   names[i], ctx ? ctx[i] : false,
> > >>   ccw);
> > >>  if (IS_ERR(vqs[i])) {
> > >>  ret = PTR_ERR(vqs[i]);
> > >>  vqs[i] = NULL;
> > >>  goto out;
> > >>  }
> > >>  }
> > >>
> > >> We increment queue_idx only if an entry was not NULL. SO I thought no
> > >> behavioral change? (at least on s390x :) )
> >
> > The code for pci behaves in the same way.
> >
> > >>
> > >> It's late here in Germany, so maybe I'm missing something.
> > >
> > > I think we've encountered a tricky issue. Currently, all transports 
> > > handle queue
> > > id by incrementing them in order, without skipping any queue id. So, I'm 
> > > quite
> > > surprised that my changes would affect the spec. The fact that the
> > > 'names' value is null is just a small trick in the Linux kernel 
> > > implementation
> > > and should not have an impact on the 

Re: [PATCH vhost v5 2/6] virtio: remove support for names array entries being null.

2024-03-25 Thread Jason Wang
On Mon, Mar 25, 2024 at 5:04 PM Xuan Zhuo  wrote:
>
> commit 6457f126c888 ("virtio: support reserved vqs") introduced this
> support. Multiqueue virtio-net use 2N as ctrl vq finally, so the logic
> doesn't apply. And not one uses this.
>
> On the other side, that makes some trouble for us to refactor the
> find_vqs() params.
>
> So I remove this support.
>
> Signed-off-by: Xuan Zhuo 
> ---
>  arch/um/drivers/virtio_uml.c | 5 -
>  drivers/platform/mellanox/mlxbf-tmfifo.c | 4 
>  drivers/remoteproc/remoteproc_virtio.c   | 5 -
>  drivers/s390/virtio/virtio_ccw.c | 5 -
>  drivers/virtio/virtio_mmio.c | 5 -
>  drivers/virtio/virtio_pci_common.c   | 9 -
>  drivers/virtio/virtio_vdpa.c | 5 -
>  include/linux/virtio_config.h| 1 -
>  8 files changed, 39 deletions(-)
>
> diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
> index 8adca2000e51..1d1e8654b7fc 100644
> --- a/arch/um/drivers/virtio_uml.c
> +++ b/arch/um/drivers/virtio_uml.c
> @@ -1031,11 +1031,6 @@ static int vu_find_vqs(struct virtio_device *vdev, 
> unsigned nvqs,
> return rc;
>
> for (i = 0; i < nvqs; ++i) {
> -   if (!names[i]) {
> -   vqs[i] = NULL;
> -   continue;
> -   }

Does this mean names[i] must not be NULL? If yes, should we fail or
not? If not, do we need to change the doc?

[...]

> --- a/include/linux/virtio_config.h
> +++ b/include/linux/virtio_config.h
> @@ -56,7 +56,6 @@ typedef void vq_callback_t(struct virtqueue *);
>   * callbacks: array of callbacks, for each virtqueue
>   * include a NULL entry for vqs that do not need a callback
>   * names: array of virtqueue names (mainly for debugging)
> - * include a NULL entry for vqs unused by driver
>   * Returns 0 on success or error status
>   * @del_vqs: free virtqueues found by find_vqs().
>   * @synchronize_cbs: synchronize with the virtqueue callbacks (optional)


Since we had other check for names[i] like:

if (per_vq_vectors) {
/* Best option: one for change interrupt, one per vq. */
nvectors = 1;
for (i = 0; i < nvqs; ++i)
if (names[i] && callbacks[i])
++nvectors;

in vp_find_vqs_msix() and maybe other places.

> --
> 2.32.0.3.g01195cf9f
>




Re: [PATCH vhost v6 2/6] virtio: remove support for names array entries being null.

2024-03-27 Thread Jason Wang
   ctx ? ctx[i] : false,
>  VIRTIO_MSI_NO_VECTOR);
> if (IS_ERR(vqs[i])) {
> diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
> index e803db0da307..e82cca24d6e6 100644
> --- a/drivers/virtio/virtio_vdpa.c
> +++ b/drivers/virtio/virtio_vdpa.c
> @@ -161,9 +161,6 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned 
> int index,
> bool may_reduce_num = true;
> int err;
>
> -   if (!name)
> -   return NULL;
> -
> if (index >= vdpa->nvqs)
> return ERR_PTR(-ENOENT);
>
> @@ -370,7 +367,7 @@ static int virtio_vdpa_find_vqs(struct virtio_device 
> *vdev, unsigned int nvqs,
>     struct cpumask *masks;
> struct vdpa_callback cb;
> bool has_affinity = desc && ops->set_vq_affinity;
> -   int i, err, queue_idx = 0;
> +   int i, err;
>
> if (has_affinity) {
> masks = create_affinity_masks(nvqs, desc ? desc : 
> &default_affd);
> @@ -380,11 +377,11 @@ static int virtio_vdpa_find_vqs(struct virtio_device 
> *vdev, unsigned int nvqs,
>
> for (i = 0; i < nvqs; ++i) {
> if (!names[i]) {
> -   vqs[i] = NULL;
> -   continue;
> +   err = -EINVAL;
> +   goto err_setup_vq;
> }
>
> -   vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx++,
> +   vqs[i] = virtio_vdpa_setup_vq(vdev, i,

And here.

With those fixed.

Acked-by: Jason Wang 

Thanks

>   callbacks[i], names[i], ctx ?
>   ctx[i] : false);
> if (IS_ERR(vqs[i])) {
> diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
> index da9b271b54db..1c79cec258f4 100644
> --- a/include/linux/virtio_config.h
> +++ b/include/linux/virtio_config.h
> @@ -56,7 +56,7 @@ typedef void vq_callback_t(struct virtqueue *);
>   * callbacks: array of callbacks, for each virtqueue
>   * include a NULL entry for vqs that do not need a callback
>   * names: array of virtqueue names (mainly for debugging)
> - * include a NULL entry for vqs unused by driver
> + * MUST NOT be NULL
>   * Returns 0 on success or error status
>   * @del_vqs: free virtqueues found by find_vqs().
>   * @synchronize_cbs: synchronize with the virtqueue callbacks (optional)
> --
> 2.32.0.3.g01195cf9f
>
>




Re: [PATCH vhost v6 4/6] virtio: vring_create_virtqueue: pass struct instead of multi parameters

2024-03-27 Thread Jason Wang
On Wed, Mar 27, 2024 at 5:58 PM Xuan Zhuo  wrote:
>
> Now, we pass multi parameters to vring_create_virtqueue. These parameters
> may from transport or from driver.
>
> vring_create_virtqueue is called by many places.
> Every time, we try to add a new parameter, that is difficult.
>
> If parameters from the driver, that should directly be passed to vring.
> Then the vring can access the config from driver directly.
>
> If parameters from the transport, we squish the parameters to a
> structure. That will be helpful to add new parameter.
>
> Signed-off-by: Xuan Zhuo 
> Acked-by: Johannes Berg 
> Reviewed-by: Ilpo Järvinen 

Acked-by: Jason Wang 

Thanks




Re: [PATCH vhost v6 5/6] virtio: vring_new_virtqueue(): pass struct instead of multi parameters

2024-03-27 Thread Jason Wang
On Wed, Mar 27, 2024 at 5:58 PM Xuan Zhuo  wrote:
>
> Now, we pass multi parameters to vring_new_virtqueue. These parameters
> may from transport or from driver.
>
> vring_new_virtqueue is called by many places.
> Every time, we try to add a new parameter, that is difficult.
>
> If parameters from the driver, that should directly be passed to vring.
> Then the vring can access the config from driver directly.
>
> If parameters from the transport, we squish the parameters to a
> structure. That will be helpful to add new parameter.
>
> Signed-off-by: Xuan Zhuo 
> Reviewed-by: Ilpo Järvinen 
> ---
>  drivers/platform/mellanox/mlxbf-tmfifo.c | 12 ---
>  drivers/remoteproc/remoteproc_virtio.c   | 11 ---
>  drivers/virtio/virtio_ring.c | 29 +++-
>  include/linux/virtio_ring.h  | 42 +++-
>  tools/virtio/virtio_test.c   |  4 +--
>  tools/virtio/vringh_test.c   | 28 
>  6 files changed, 84 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c 
> b/drivers/platform/mellanox/mlxbf-tmfifo.c
> index 4252388f52a2..d2e871fad8b4 100644
> --- a/drivers/platform/mellanox/mlxbf-tmfifo.c
> +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
> @@ -1059,6 +1059,7 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct 
> virtio_device *vdev,
> struct virtio_vq_config *cfg)
>  {
> struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
> +   struct vq_transport_config tp_cfg = {};
> struct virtqueue **vqs = cfg->vqs;
> struct mlxbf_tmfifo_vring *vring;
> unsigned int nvqs = cfg->nvqs;
> @@ -1078,10 +1079,13 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct 
> virtio_device *vdev,
> /* zero vring */
> size = vring_size(vring->num, vring->align);
> memset(vring->va, 0, size);
> -   vq = vring_new_virtqueue(i, vring->num, vring->align, vdev,
> -false, false, vring->va,
> -mlxbf_tmfifo_virtio_notify,
> -cfg->callbacks[i], cfg->names[i]);
> +
> +   tp_cfg.num = vring->num;
> +   tp_cfg.vring_align = vring->align;
> +   tp_cfg.weak_barriers = false;
> +   tp_cfg.notify = mlxbf_tmfifo_virtio_notify;
> +
> +   vq = vring_new_virtqueue(vdev, i, vring->va, &tp_cfg, cfg);
> if (!vq) {
> dev_err(&vdev->dev, "vring_new_virtqueue failed\n");
> ret = -ENOMEM;
> diff --git a/drivers/remoteproc/remoteproc_virtio.c 
> b/drivers/remoteproc/remoteproc_virtio.c
> index 489fea1d41c0..2319c2007833 100644
> --- a/drivers/remoteproc/remoteproc_virtio.c
> +++ b/drivers/remoteproc/remoteproc_virtio.c
> @@ -106,6 +106,7 @@ static struct virtqueue *rp_find_vq(struct virtio_device 
> *vdev,
>  {
> struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
> struct rproc *rproc = vdev_to_rproc(vdev);
> +   struct vq_transport_config tp_cfg;

Should we zero this structure?

Thanks




Re: [PATCH vhost v6 6/6] virtio_ring: simplify the parameters of the funcs related to vring_create/new_virtqueue()

2024-03-27 Thread Jason Wang
On Wed, Mar 27, 2024 at 5:58 PM Xuan Zhuo  wrote:
>
> As the refactor of find_vqs()/vring_new_virtqueue()/vring_create_virtqueue
> the struct cfg/tp_cfg are passed to vring.
>
> This patch refactors the vring by these structures. This can simplify
> the code.
>
> Signed-off-by: Xuan Zhuo 
> Reviewed-by: Ilpo Järvinen 
> ---

Acked-by: Jason Wang 

Thanks




Re: [PATCH vhost v6 3/6] virtio: find_vqs: pass struct instead of multi parameters

2024-03-27 Thread Jason Wang
  struct irq_affinity *desc)
> +static int rproc_virtio_find_vqs(struct virtio_device *vdev, struct 
> virtio_vq_config *cfg)
>  {
> +   struct virtqueue **vqs = cfg->vqs;
> +   unsigned int nvqs = cfg->nvqs;
> int i, ret;
>
> for (i = 0; i < nvqs; ++i) {
> -   if (!names[i]) {
> +   if (!cfg->names[i]) {
> ret = -EINVAL;
> goto error;
> }
>
> -   vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i],
> -   ctx ? ctx[i] : false);
> +   vqs[i] = rp_find_vq(vdev, i, cfg);
> if (IS_ERR(vqs[i])) {
> ret = PTR_ERR(vqs[i]);
> goto error;
> diff --git a/drivers/s390/virtio/virtio_ccw.c 
> b/drivers/s390/virtio/virtio_ccw.c
> index 508154705554..3c78122f00f5 100644
> --- a/drivers/s390/virtio/virtio_ccw.c
> +++ b/drivers/s390/virtio/virtio_ccw.c
> @@ -499,9 +499,8 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev)
>  }
>
>  static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
> -int i, vq_callback_t *callback,
> -const char *name, bool ctx,
> -struct ccw1 *ccw)
> +int i, struct ccw1 *ccw,
> +struct virtio_vq_config *cfg)
>  {
> struct virtio_ccw_device *vcdev = to_vc_device(vdev);
> bool (*notify)(struct virtqueue *vq);
> @@ -538,8 +537,11 @@ static struct virtqueue *virtio_ccw_setup_vq(struct 
> virtio_device *vdev,
> }
> may_reduce = vcdev->revision > 0;
> vq = vring_create_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN,
> -   vdev, true, may_reduce, ctx,
> -   notify, callback, name);
> +   vdev, true, may_reduce,
> +   cfg->ctx ? cfg->ctx[i] : false,
> +   notify,
> +   cfg->callbacks[i],
> +   cfg->names[i]);
>
> if (!vq) {
> /* For now, we fail if we can't get the requested size. */
> @@ -650,15 +652,13 @@ static int virtio_ccw_register_adapter_ind(struct 
> virtio_ccw_device *vcdev,
> return ret;
>  }
>
> -static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
> -  struct virtqueue *vqs[],
> -  vq_callback_t *callbacks[],
> -  const char * const names[],
> -  const bool *ctx,
> -  struct irq_affinity *desc)
> +static int virtio_ccw_find_vqs(struct virtio_device *vdev,
> +  struct virtio_vq_config *cfg)
>  {
> struct virtio_ccw_device *vcdev = to_vc_device(vdev);
> +   struct virtqueue **vqs = cfg->vqs;
> unsigned long *indicatorp = NULL;
> +   unsigned int nvqs = cfg->nvqs;
> int ret, i;
> struct ccw1 *ccw;
>
> @@ -667,14 +667,12 @@ static int virtio_ccw_find_vqs(struct virtio_device 
> *vdev, unsigned nvqs,
> return -ENOMEM;
>
> for (i = 0; i < nvqs; ++i) {
> -   if (!names[i]) {
> +   if (!cfg->names[i]) {
> ret = -EINVAL;
> goto out;
> }
>
> -   vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i],
> -names[i], ctx ? ctx[i] : false,
> -ccw);
> +   vqs[i] = virtio_ccw_setup_vq(vdev, i, ccw, cfg);
> if (IS_ERR(vqs[i])) {
> ret = PTR_ERR(vqs[i]);
> vqs[i] = NULL;
> diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
> index 82ee4a288728..7f0fdc3f51cb 100644
> --- a/drivers/virtio/virtio_mmio.c
> +++ b/drivers/virtio/virtio_mmio.c
> @@ -370,8 +370,7 @@ static void vm_synchronize_cbs(struct virtio_device *vdev)
>  }
>
>  static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned 
> int index,
> - void (*callback)(struct virtqueue *vq),
> - const char *name, bool ctx)
> +struct virtio_vq_config *cfg)
>  {
> struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
> bool (*notify)(struct virtqueue *vq);
> @@ -386,9 +385,6 @@ static struct virtqueue *vm_setup_vq(struct virtio_device 
> *vdev, unsigned int in
> else
> notify = vm_notify;
>
> -   if (!name)
> -   return NULL;

Nit: This seems to belong to patch 2.

Acked-by: Jason Wang 

Thanks




Re: [PATCH vhost v7 5/6] virtio: vring_new_virtqueue(): pass struct instead of multi parameters

2024-03-28 Thread Jason Wang
On Thu, Mar 28, 2024 at 4:04 PM Xuan Zhuo  wrote:
>
> Now, we pass multi parameters to vring_new_virtqueue. These parameters
> may from transport or from driver.
>
> vring_new_virtqueue is called by many places.
> Every time, we try to add a new parameter, that is difficult.
>
> If parameters from the driver, that should directly be passed to vring.
> Then the vring can access the config from driver directly.
>
> If parameters from the transport, we squish the parameters to a
> structure. That will be helpful to add new parameter.
>
> Signed-off-by: Xuan Zhuo 
> Reviewed-by: Ilpo Järvinen 

Acked-by: Jason Wang 

Thanks




Re: [PATCH vhost v9 1/6] virtio_balloon: remove the dependence where names[] is null

2024-06-20 Thread Jason Wang
On Thu, Jun 20, 2024 at 4:08 PM Michael S. Tsirkin  wrote:
>
> On Wed, Apr 24, 2024 at 05:15:28PM +0800, Xuan Zhuo wrote:
> > Currently, the init_vqs function within the virtio_balloon driver relies
> > on the condition that certain names array entries are null in order to
> > skip the initialization of some virtual queues (vqs). This behavior is
> > unique to this part of the codebase. In an upcoming commit, we plan to
> > eliminate this dependency by removing the function entirely. Therefore,
> > with this change, we are ensuring that the virtio_balloon no longer
> > depends on the aforementioned function.
> >
> > As specification 1.0-1.2, vq indexes should not be contiguous if some
> > vq does not exist. But currently the virtqueue index is contiguous for
> > all existing devices. The Linux kernel does not implement functionality
> > to allow vq indexes to be discontinuous. So the current behavior of the
> > virtio-balloon device is different for the spec. But this commit has no
> > functional changes.
> >
> > Signed-off-by: Xuan Zhuo 
> > Acked-by: David Hildenbrand 
> > Acked-by: Jason Wang 
>
> I can't make heads of tails of this.
>
> David you acked so maybe you can help rewrite the commit log here?
>
> I don't understand what this says.
> What in the balloon driver is out of spec?

The problem is the spec has bug, see this:

https://www.mail-archive.com/linux-um@lists.infradead.org/msg04359.html

Thanks


> NULL in names *exactly* allows skipping init for some vqs.
> How is that "does not implement"?
>
> And so on.
>
>
> > ---
> >  drivers/virtio/virtio_balloon.c | 48 ++---
> >  1 file changed, 20 insertions(+), 28 deletions(-)
> >
> > diff --git a/drivers/virtio/virtio_balloon.c 
> > b/drivers/virtio/virtio_balloon.c
> > index c0a63638f95e..ccda6d08493f 100644
> > --- a/drivers/virtio/virtio_balloon.c
> > +++ b/drivers/virtio/virtio_balloon.c
> > @@ -548,49 +548,41 @@ static int init_vqs(struct virtio_balloon *vb)
> >   struct virtqueue *vqs[VIRTIO_BALLOON_VQ_MAX];
> >   vq_callback_t *callbacks[VIRTIO_BALLOON_VQ_MAX];
> >   const char *names[VIRTIO_BALLOON_VQ_MAX];
> > - int err;
> > + int err, idx = 0;
> >
> > - /*
> > -  * Inflateq and deflateq are used unconditionally. The names[]
> > -  * will be NULL if the related feature is not enabled, which will
> > -  * cause no allocation for the corresponding virtqueue in find_vqs.
> > -  */
> > - callbacks[VIRTIO_BALLOON_VQ_INFLATE] = balloon_ack;
> > - names[VIRTIO_BALLOON_VQ_INFLATE] = "inflate";
> > - callbacks[VIRTIO_BALLOON_VQ_DEFLATE] = balloon_ack;
> > - names[VIRTIO_BALLOON_VQ_DEFLATE] = "deflate";
> > - callbacks[VIRTIO_BALLOON_VQ_STATS] = NULL;
> > - names[VIRTIO_BALLOON_VQ_STATS] = NULL;
> > - callbacks[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL;
> > - names[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL;
> > - names[VIRTIO_BALLOON_VQ_REPORTING] = NULL;
> > + callbacks[idx] = balloon_ack;
> > + names[idx++] = "inflate";
> > + callbacks[idx] = balloon_ack;
> > + names[idx++] = "deflate";
> >
> >   if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
> > - names[VIRTIO_BALLOON_VQ_STATS] = "stats";
> > - callbacks[VIRTIO_BALLOON_VQ_STATS] = stats_request;
> > + names[idx] = "stats";
> > + callbacks[idx++] = stats_request;
> >   }
> >
> >   if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
> > - names[VIRTIO_BALLOON_VQ_FREE_PAGE] = "free_page_vq";
> > - callbacks[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL;
> > + names[idx] = "free_page_vq";
> > + callbacks[idx++] = NULL;
> >   }
> >
> >   if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING)) {
> > - names[VIRTIO_BALLOON_VQ_REPORTING] = "reporting_vq";
> > - callbacks[VIRTIO_BALLOON_VQ_REPORTING] = balloon_ack;
> > + names[idx] = "reporting_vq";
> > + callbacks[idx++] = balloon_ack;
> >   }
> >
> > - err = virtio_find_vqs(vb->vdev, VIRTIO_BALLOON_VQ_MAX, vqs,
> > -   callbacks, names, NULL);
> > + err = virtio_find_vqs(vb->vdev, idx, vqs, callbacks, names, NULL);
> >   if (err)
> >   return err;
> >
>

Re: [PATCH 2/2] virtio: fix vq # when vq skipped

2024-07-09 Thread Jason Wang
On Fri, Jul 5, 2024 at 6:09 PM Michael S. Tsirkin  wrote:
>
> virtio balloon communicates to the core that in some
> configurations vq #s are non-contiguous by setting name
> pointer to NULL.
>
> Unfortunately, core then turned around and just made them
> contiguous again. Result is that driver is out of spec.
>
> Implement what the API was supposed to do
> in the 1st place. Compatibility with buggy hypervisors
> is handled inside virtio-balloon, which is the only driver
> making use of this facility, so far.
>
> Signed-off-by: Michael S. Tsirkin 

Acked-by: Jason Wang 

Thanks




Re: [PATCH v6 06/26] virtio_ring: packed: extrace the logic of creating vring

2022-03-07 Thread Jason Wang


在 2022/3/8 下午3:01, Xuan Zhuo 写道:

On Mon, 7 Mar 2022 17:17:51 -0500, "Michael S. Tsirkin"  wrote:

On Thu, Feb 24, 2022 at 04:10:42PM +0800, Xuan Zhuo wrote:

Separate the logic of packed to create vring queue.

For the convenience of passing parameters, add a structure
vring_packed.

This feature is required for subsequent virtuqueue reset vring.

Signed-off-by: Xuan Zhuo 

Subject has a typo.

I will fix it.


Besides:


---
  drivers/virtio/virtio_ring.c | 121 ++-
  1 file changed, 92 insertions(+), 29 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index dc6313b79305..41864c5e665f 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -92,6 +92,18 @@ struct vring_split {
struct vring vring;
  };

+struct vring_packed {
+   u32 num;
+   struct vring_packed_desc *ring;
+   struct vring_packed_desc_event *driver;
+   struct vring_packed_desc_event *device;
+   dma_addr_t ring_dma_addr;
+   dma_addr_t driver_event_dma_addr;
+   dma_addr_t device_event_dma_addr;
+   size_t ring_size_in_bytes;
+   size_t event_size_in_bytes;
+};
+
  struct vring_virtqueue {
struct virtqueue vq;

@@ -1683,45 +1695,101 @@ static struct vring_desc_extra 
*vring_alloc_desc_extra(struct vring_virtqueue *v
return desc_extra;
  }

-static struct virtqueue *vring_create_virtqueue_packed(
-   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 void vring_free_vring_packed(struct vring_packed *vring,
+   struct virtio_device *vdev)
+{
+   dma_addr_t ring_dma_addr, driver_event_dma_addr, device_event_dma_addr;
+   struct vring_packed_desc_event *driver, *device;
+   size_t ring_size_in_bytes, event_size_in_bytes;
+   struct vring_packed_desc *ring;
+
+   ring  = vring->ring;
+   driver= vring->driver;
+   device= vring->device;
+   ring_dma_addr = vring->ring_size_in_bytes;
+   event_size_in_bytes   = vring->event_size_in_bytes;
+   ring_dma_addr = vring->ring_dma_addr;
+   driver_event_dma_addr = vring->driver_event_dma_addr;
+   device_event_dma_addr = vring->device_event_dma_addr;
+
+   if (device)
+   vring_free_queue(vdev, event_size_in_bytes, device, 
device_event_dma_addr);
+
+   if (driver)
+   vring_free_queue(vdev, event_size_in_bytes, driver, 
driver_event_dma_addr);
+
+   if (ring)
+   vring_free_queue(vdev, ring_size_in_bytes, ring, ring_dma_addr);

ring_size_in_bytes is uninitialized here.

Which begs the question how was this tested patchset generally and
this patch in particular.
Please add note on tested configurations and tests run to the patchset.

Sorry, my environment is running in split mode. I did not retest the packed mode
before sending patches. Because my dpdk vhost-user is not easy to use, I
need to change the kernel of the host.

I would like to ask if there are other lightweight environments that can be used
to test packed mode.



You can use Qemu's dataplane. It has support for packed virtqueue.

Thanks





Thanks.



+}
+
+static int vring_create_vring_packed(struct vring_packed *vring,
+   struct virtio_device *vdev,
+   u32 num)
  {
-   struct vring_virtqueue *vq;
struct vring_packed_desc *ring;
struct vring_packed_desc_event *driver, *device;
dma_addr_t ring_dma_addr, driver_event_dma_addr, device_event_dma_addr;
size_t ring_size_in_bytes, event_size_in_bytes;

+   memset(vring, 0, sizeof(*vring));
+
ring_size_in_bytes = num * sizeof(struct vring_packed_desc);

ring = vring_alloc_queue(vdev, ring_size_in_bytes,
 &ring_dma_addr,
 GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO);
if (!ring)
-   goto err_ring;
+   goto err;
+
+   vring->num = num;
+   vring->ring = ring;
+   vring->ring_size_in_bytes = ring_size_in_bytes;
+   vring->ring_dma_addr = ring_dma_addr;

event_size_in_bytes = sizeof(struct vring_packed_desc_event);
+   vring->event_size_in_bytes = event_size_in_bytes;

driver = vring_alloc_queue(vdev, event_size_in_bytes,
   &driver_event_dma_addr,
   GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO);
if (!driver)
-   goto err_driver;
+   goto err;
+
+   vring->driver = driver;
+   vring->driver_event_dma_addr = driver_event_dma_addr;

device = vring_all

Re: [PATCH v7 00/26] virtio pci support VIRTIO_F_RING_RESET

2022-03-08 Thread Jason Wang


在 2022/3/8 下午8:34, Xuan Zhuo 写道:

The virtio spec already supports the virtio queue reset function. This patch set
is to add this function to the kernel. The relevant virtio spec information is
here:

 https://github.com/oasis-tcs/virtio-spec/issues/124

Also regarding MMIO support for queue reset, I plan to support it after this
patch is passed.

Performing reset on a queue is divided into four steps:
  1. virtio_reset_vq()  - notify the device to reset the queue
  2. virtqueue_detach_unused_buf()  - recycle the buffer submitted
  3. virtqueue_reset_vring()- reset the vring (may re-alloc)
  4. virtio_enable_resetq() - mmap vring to device, and enable the 
queue

The first part 1-17 of this patch set implements virtio pci's support and API
for queue reset. The latter part is to make virtio-net support set_ringparam. Do
these things for this feature:

   1. virtio-net support rx,tx reset
   2. find_vqs() support to special the max size of each vq
   3. virtio-net support set_ringparam

#1 -#3 :   prepare
#4 -#12:   virtio ring support reset vring of the vq
#13-#14:   add helper
#15-#17:   virtio pci support reset queue and re-enable
#18-#21:   find_vqs() support sizes to special the max size of each vq
#23-#24:   virtio-net support rx, tx reset
#22, #25, #26: virtio-net support set ringparam

Test environment:
 Host: 4.19.91
 Qemu: QEMU emulator version 6.2.50 (with vq reset support)
 Test Cmd:  ethtool -G eth1 rx $1 tx $2; ethtool -g eth1

 The default is split mode, modify Qemu virtio-net to add PACKED feature to 
test
 packed mode.


Please review. Thanks.

v7:
   1. fix #6 subject typo
   2. fix #6 ring_size_in_bytes is uninitialized
   3. check by: make W=12

v6:
   1. virtio_pci: use synchronize_irq(irq) to sync the irq callbacks
   2. Introduce virtqueue_reset_vring() to implement the reset of vring during
  the reset process. May use the old vring if num of the vq not change.
   3. find_vqs() support sizes to special the max size of each vq

v5:
   1. add virtio-net support set_ringparam

v4:
   1. just the code of virtio, without virtio-net
   2. Performing reset on a queue is divided into these steps:
 1. reset_vq: reset one vq
 2. recycle the buffer from vq by virtqueue_detach_unused_buf()
 3. release the ring of the vq by vring_release_virtqueue()
 4. enable_reset_vq: re-enable the reset queue
   3. Simplify the parameters of enable_reset_vq()
   4. add container structures for virtio_pci_common_cfg

v3:
   1. keep vq, irq unreleased



The series became kind of huge.

I'd suggest to split it into two series.

1) refactoring of the virtio_ring to prepare for the resize
2) the reset support + virtio-net support

Thanks




*** BLURB HERE ***

Xuan Zhuo (26):
   virtio_pci: struct virtio_pci_common_cfg add queue_notify_data
   virtio: queue_reset: add VIRTIO_F_RING_RESET
   virtio: add helper virtqueue_get_vring_max_size()
   virtio_ring: split: extract the logic of creating vring
   virtio_ring: split: extract the logic of init vq and attach vring
   virtio_ring: packed: extract the logic of creating vring
   virtio_ring: packed: extract the logic of init vq and attach vring
   virtio_ring: extract the logic of freeing vring
   virtio_ring: split: implement virtqueue_reset_vring_split()
   virtio_ring: packed: implement virtqueue_reset_vring_packed()
   virtio_ring: introduce virtqueue_reset_vring()
   virtio_ring: update the document of the virtqueue_detach_unused_buf
 for queue reset
   virtio: queue_reset: struct virtio_config_ops add callbacks for
 queue_reset
   virtio: add helper for queue reset
   virtio_pci: queue_reset: update struct virtio_pci_common_cfg and
 option functions
   virtio_pci: queue_reset: extract the logic of active vq for modern pci
   virtio_pci: queue_reset: support VIRTIO_F_RING_RESET
   virtio: find_vqs() add arg sizes
   virtio_pci: support the arg sizes of find_vqs()
   virtio_mmio: support the arg sizes of find_vqs()
   virtio: add helper virtio_find_vqs_ctx_size()
   virtio_net: get ringparam by virtqueue_get_vring_max_size()
   virtio_net: split free_unused_bufs()
   virtio_net: support rx/tx queue reset
   virtio_net: set the default max ring size by find_vqs()
   virtio_net: support set_ringparam

  arch/um/drivers/virtio_uml.c |   2 +-
  drivers/net/virtio_net.c | 257 --
  drivers/platform/mellanox/mlxbf-tmfifo.c |   3 +-
  drivers/remoteproc/remoteproc_virtio.c   |   2 +-
  drivers/s390/virtio/virtio_ccw.c |   2 +-
  drivers/virtio/virtio_mmio.c |  12 +-
  drivers/virtio/virtio_pci_common.c   |  28 +-
  drivers/virtio/virtio_pci_common.h   |   3 +-
  drivers/virtio/virtio_pci_legacy.c   |   8 +-
  drivers/virtio/virtio_pci_modern.c   | 146 +-
  drivers/virtio/virtio_pci_modern_dev.c   |  36 ++
  drivers/virtio/virtio_ring.c | 584 ++

Re: [PATCH v7 01/26] virtio_pci: struct virtio_pci_common_cfg add queue_notify_data

2022-03-08 Thread Jason Wang


在 2022/3/8 下午8:34, Xuan Zhuo 写道:

Add queue_notify_data in struct virtio_pci_common_cfg, which comes from
here https://github.com/oasis-tcs/virtio-spec/issues/89

For not breaks uABI, add a new struct virtio_pci_common_cfg_notify.

Since I want to add queue_reset after queue_notify_data, I submitted
this patch first.

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 



---
  include/uapi/linux/virtio_pci.h | 7 +++
  1 file changed, 7 insertions(+)

diff --git a/include/uapi/linux/virtio_pci.h b/include/uapi/linux/virtio_pci.h
index 3a86f36d7e3d..22bec9bd0dfc 100644
--- a/include/uapi/linux/virtio_pci.h
+++ b/include/uapi/linux/virtio_pci.h
@@ -166,6 +166,13 @@ struct virtio_pci_common_cfg {
__le32 queue_used_hi;   /* read-write */
  };
  
+struct virtio_pci_common_cfg_notify {

+   struct virtio_pci_common_cfg cfg;
+
+   __le16 queue_notify_data;   /* read-write */
+   __le16 padding;
+};
+
  /* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
  struct virtio_pci_cfg_cap {
struct virtio_pci_cap cap;



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 02/26] virtio: queue_reset: add VIRTIO_F_RING_RESET

2022-03-08 Thread Jason Wang


在 2022/3/8 下午8:34, Xuan Zhuo 写道:

Added VIRTIO_F_RING_RESET, it came from here
https://github.com/oasis-tcs/virtio-spec/issues/124



Nit: it's better to explain VIRTIO_F_RING_RESET a little bit here.

Other than this.

Acked-by: Jason Wang 




Signed-off-by: Xuan Zhuo 
---
  include/uapi/linux/virtio_config.h | 7 ++-
  1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/virtio_config.h 
b/include/uapi/linux/virtio_config.h
index b5eda06f0d57..0862be802ff8 100644
--- a/include/uapi/linux/virtio_config.h
+++ b/include/uapi/linux/virtio_config.h
@@ -52,7 +52,7 @@
   * rest are per-device feature bits.
   */
  #define VIRTIO_TRANSPORT_F_START  28
-#define VIRTIO_TRANSPORT_F_END 38
+#define VIRTIO_TRANSPORT_F_END 41
  
  #ifndef VIRTIO_CONFIG_NO_LEGACY

  /* Do we get callbacks when the ring is completely used, even if we've
@@ -92,4 +92,9 @@
   * Does the device support Single Root I/O Virtualization?
   */
  #define VIRTIO_F_SR_IOV   37
+
+/*
+ * This feature indicates that the driver can reset a queue individually.
+ */
+#define VIRTIO_F_RING_RESET40
  #endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 03/26] virtio: add helper virtqueue_get_vring_max_size()

2022-03-08 Thread Jason Wang


在 2022/3/8 下午8:34, Xuan Zhuo 写道:

Record the maximum queue num supported by the device.

virtio-net can display the maximum (supported by hardware) ring size in
ethtool -g eth0.

When the subsequent patch implements vring reset, it can judge whether
the ring size passed by the driver is legal based on this.

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 



---
  drivers/virtio/virtio_mmio.c   |  2 ++
  drivers/virtio/virtio_pci_legacy.c |  2 ++
  drivers/virtio/virtio_pci_modern.c |  2 ++
  drivers/virtio/virtio_ring.c   | 14 ++
  include/linux/virtio.h |  2 ++
  5 files changed, 22 insertions(+)

diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index 56128b9c46eb..a41abc8051b9 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -390,6 +390,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device 
*vdev, unsigned index,
goto error_new_virtqueue;
}
  
+	vq->num_max = num;

+
/* Activate the queue */
writel(virtqueue_get_vring_size(vq), vm_dev->base + 
VIRTIO_MMIO_QUEUE_NUM);
if (vm_dev->version == 1) {
diff --git a/drivers/virtio/virtio_pci_legacy.c 
b/drivers/virtio/virtio_pci_legacy.c
index 34141b9abe27..b68934fe6b5d 100644
--- a/drivers/virtio/virtio_pci_legacy.c
+++ b/drivers/virtio/virtio_pci_legacy.c
@@ -135,6 +135,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device 
*vp_dev,
if (!vq)
return ERR_PTR(-ENOMEM);
  
+	vq->num_max = num;

+
q_pfn = virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
if (q_pfn >> 32) {
dev_err(&vp_dev->pci_dev->dev,
diff --git a/drivers/virtio/virtio_pci_modern.c 
b/drivers/virtio/virtio_pci_modern.c
index 5455bc041fb6..86d301f272b8 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -218,6 +218,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device 
*vp_dev,
if (!vq)
return ERR_PTR(-ENOMEM);
  
+	vq->num_max = num;

+
/* activate the queue */
vp_modern_set_queue_size(mdev, index, virtqueue_get_vring_size(vq));
vp_modern_queue_address(mdev, index, virtqueue_get_desc_addr(vq),
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 962f1477b1fa..b87130c8f312 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -2371,6 +2371,20 @@ void vring_transport_features(struct virtio_device *vdev)
  }
  EXPORT_SYMBOL_GPL(vring_transport_features);
  
+/**

+ * virtqueue_get_vring_max_size - return the max size of the virtqueue's vring
+ * @_vq: the struct virtqueue containing the vring of interest.
+ *
+ * Returns the max size of the vring.
+ *
+ * Unlike other operations, this need not be serialized.
+ */
+unsigned int virtqueue_get_vring_max_size(struct virtqueue *_vq)
+{
+   return _vq->num_max;
+}
+EXPORT_SYMBOL_GPL(virtqueue_get_vring_max_size);
+
  /**
   * virtqueue_get_vring_size - return the size of the virtqueue's vring
   * @_vq: the struct virtqueue containing the vring of interest.
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 72292a62cd90..d59adc4be068 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -31,6 +31,7 @@ struct virtqueue {
struct virtio_device *vdev;
unsigned int index;
unsigned int num_free;
+   unsigned int num_max;
void *priv;
  };
  
@@ -80,6 +81,7 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *vq);
  
  void *virtqueue_detach_unused_buf(struct virtqueue *vq);
  
+unsigned int virtqueue_get_vring_max_size(struct virtqueue *vq);

  unsigned int virtqueue_get_vring_size(struct virtqueue *vq);
  
  bool virtqueue_is_broken(struct virtqueue *vq);



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 04/26] virtio_ring: split: extract the logic of creating vring

2022-03-08 Thread Jason Wang


在 2022/3/8 下午8:34, Xuan Zhuo 写道:

Separate the logic of split to create vring queue.

For the convenience of passing parameters, add a structure
vring_split.

This feature is required for subsequent virtuqueue reset vring.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 74 +---
  1 file changed, 51 insertions(+), 23 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index b87130c8f312..d32793615451 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -85,6 +85,13 @@ struct vring_desc_extra {
u16 next;   /* The next desc state in a list. */
  };
  
+struct vring_split {

+   void *queue;
+   dma_addr_t dma_addr;
+   size_t queue_size_in_bytes;
+   struct vring vring;
+};



So this structure will be only used in vring_create_vring_split() which 
seems not that useful.


More see below.



+
  struct vring_virtqueue {
struct virtqueue vq;
  
@@ -915,28 +922,21 @@ static void *virtqueue_detach_unused_buf_split(struct virtqueue *_vq)

return NULL;
  }
  
-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_create_vring_split(struct vring_split *vring,
+   struct virtio_device *vdev,
+   unsigned int vring_align,
+   bool weak_barriers,
+   bool may_reduce_num,
+   u32 num)



I'd rename this as vring_alloc_queue_split() and let it simply return 
the address of queue like vring_alloc_queue().


And let it simple accept dma_addr_t *dma_adder instead of vring_split.



  {
-   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 */

@@ -947,11 +947,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! */
@@ -959,21 +959,49 @@ static struct virtqueue *vring_create_virtqueue_split(
  &dma_addr, GFP_KERNEL|__GFP_ZERO);
}
if (!queue)
-   return NULL;
+   return -ENOMEM;
  
  	queue_size_in_bytes = vring_size(num, vring_align);

-   vring_init(&vring, num, queue, vring_align);
+   vring_init(&vring->vring, num, queue, vring_align);



It's better to move this to its caller (vring_create_virtqueue_split), 
so we have rather simple logic below:





+
+   vring->dma_addr = dma_addr;
+   vring->queue = queue;
+   vring->queue_size_in_bytes = queue_size_in_bytes;
+
+   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_split vring;
+   struct virtqueue *vq;
+   int err;
+
+   err = vring_create_vring_split(&vring, vdev, vring_align, weak_barriers,
+  may_reduce_num, num);
+   if (err)
+   return NULL;



queue = vring_alloc_queue_split(vdev, &dma_addr, ...);

if (!queue)

    return -ENOMEM;

vring_init();

...

Thanks


  
-	vq = __vring_new_virtqueue(index, vring, vdev, weak_barriers, context,

+   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_queue(vdev, vring.queue_size_in_bytes, vring.queue,
+vring.dma_addr);
return NULL;
}
  
-	to_vvq(vq)->split.queue_dma_addr = dma_addr;

-   to_vvq(vq)->split.queue_size_in_bytes = queu

Re: [PATCH v7 05/26] virtio_ring: split: extract the logic of init vq and attach vring

2022-03-08 Thread Jason Wang


在 2022/3/8 下午8:34, Xuan Zhuo 写道:

Split the logic of split assignment vq into three parts.

1. The assignment passed from the function parameter
2. The part that attaches vring to vq. -- __vring_virtqueue_attach_split()
3. The part that initializes vq to a fixed value --
__vring_virtqueue_init_split()

This feature is required for subsequent virtuqueue reset vring

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 111 +--
  1 file changed, 67 insertions(+), 44 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index d32793615451..dc6313b79305 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -2196,34 +2196,40 @@ irqreturn_t vring_interrupt(int irq, void *_vq)
  }
  EXPORT_SYMBOL_GPL(vring_interrupt);
  
-/* Only available for split ring */

-struct virtqueue *__vring_new_virtqueue(unsigned int index,
-   struct vring vring,
-   struct virtio_device *vdev,
-   bool weak_barriers,
-   bool context,
-   bool (*notify)(struct virtqueue *),
-   void (*callback)(struct virtqueue *),
-   const char *name)
+static int __vring_virtqueue_attach_split(struct vring_virtqueue *vq,
+ struct virtio_device *vdev,
+ struct vring vring)
  {
-   struct vring_virtqueue *vq;
+   vq->vq.num_free = vring.num;
  
-	if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))

-   return NULL;
+   vq->split.vring = vring;
+   vq->split.queue_dma_addr = 0;
+   vq->split.queue_size_in_bytes = 0;
  
-	vq = kmalloc(sizeof(*vq), GFP_KERNEL);

-   if (!vq)
-   return NULL;
+   vq->split.desc_state = kmalloc_array(vring.num,
+sizeof(struct 
vring_desc_state_split), GFP_KERNEL);
+   if (!vq->split.desc_state)
+   goto err_state;
  
+	vq->split.desc_extra = vring_alloc_desc_extra(vq, vring.num);

+   if (!vq->split.desc_extra)
+   goto err_extra;



So this contains stuffs more than just attach. I wonder if it's better 
to split the allocation out to an dedicated helper (we have dedicated 
helper to allocate vring).


Thanks



+
+   memset(vq->split.desc_state, 0, vring.num *
+  sizeof(struct vring_desc_state_split));
+   return 0;
+
+err_extra:
+   kfree(vq->split.desc_state);
+err_state:
+   return -ENOMEM;
+}
+
+static void __vring_virtqueue_init_split(struct vring_virtqueue *vq,
+struct virtio_device *vdev)
+{
vq->packed_ring = false;
-   vq->vq.callback = callback;
-   vq->vq.vdev = vdev;
-   vq->vq.name = name;
-   vq->vq.num_free = vring.num;
-   vq->vq.index = index;
vq->we_own_ring = false;
-   vq->notify = notify;
-   vq->weak_barriers = weak_barriers;
vq->broken = false;
vq->last_used_idx = 0;
vq->event_triggered = false;
@@ -2234,50 +2240,67 @@ struct virtqueue *__vring_new_virtqueue(unsigned int 
index,
vq->last_add_time_valid = false;
  #endif
  
-	vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&

-   !context;
vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
  
  	if (virtio_has_feature(vdev, VIRTIO_F_ORDER_PLATFORM))

vq->weak_barriers = false;
  
-	vq->split.queue_dma_addr = 0;

-   vq->split.queue_size_in_bytes = 0;
-
-   vq->split.vring = vring;
vq->split.avail_flags_shadow = 0;
vq->split.avail_idx_shadow = 0;
  
  	/* No callback?  Tell other side not to bother us. */

-   if (!callback) {
+   if (!vq->vq.callback) {
vq->split.avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
if (!vq->event)
vq->split.vring.avail->flags = cpu_to_virtio16(vdev,
vq->split.avail_flags_shadow);
}
  
-	vq->split.desc_state = kmalloc_array(vring.num,

-   sizeof(struct vring_desc_state_split), GFP_KERNEL);
-   if (!vq->split.desc_state)
-   goto err_state;
-
-   vq->split.desc_extra = vring_alloc_desc_extra(vq, vring.num);
-   if (!vq->split.desc_extra)
-   goto err_extra;
-
/* Put everything in free lists. */
vq->free_head = 0;
-   memset(vq->split.desc_state, 0, vring.num *
-   sizeof(struct vring_desc_state_split));
+}
+
+/* Only available for split ring */
+struct virtqueue *__vring_new_virtqueue(unsigned int index,
+   struct vring vring,
+   struct virtio_device *vdev

Re: [PATCH v7 08/26] virtio_ring: extract the logic of freeing vring

2022-03-08 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

Introduce vring_free() to free the vring of vq.

Prevent double free by setting vq->reset.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 25 -
  include/linux/virtio.h   |  8 
  2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index b5a9bf4f45b3..e0422c04c903 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -2442,14 +2442,10 @@ struct virtqueue *vring_new_virtqueue(unsigned int 
index,
  }
  EXPORT_SYMBOL_GPL(vring_new_virtqueue);
  
-void vring_del_virtqueue(struct virtqueue *_vq)

+static void __vring_free(struct virtqueue *_vq)
  {
struct vring_virtqueue *vq = to_vvq(_vq);
  
-	spin_lock(&vq->vq.vdev->vqs_list_lock);

-   list_del(&_vq->list);
-   spin_unlock(&vq->vq.vdev->vqs_list_lock);
-
if (vq->we_own_ring) {
if (vq->packed_ring) {
vring_free_queue(vq->vq.vdev,
@@ -2480,6 +2476,25 @@ void vring_del_virtqueue(struct virtqueue *_vq)
kfree(vq->split.desc_state);
kfree(vq->split.desc_extra);
}
+}
+
+static void vring_free(struct virtqueue *vq)
+{
+   __vring_free(vq);
+   vq->reset = VIRTIO_VQ_RESET_STEP_VRING_RELEASE;
+}
+
+void vring_del_virtqueue(struct virtqueue *_vq)
+{
+   struct vring_virtqueue *vq = to_vvq(_vq);
+
+   spin_lock(&vq->vq.vdev->vqs_list_lock);
+   list_del(&_vq->list);
+   spin_unlock(&vq->vq.vdev->vqs_list_lock);
+
+   if (_vq->reset != VIRTIO_VQ_RESET_STEP_VRING_RELEASE)
+   __vring_free(_vq);
+
kfree(vq);
  }
  EXPORT_SYMBOL_GPL(vring_del_virtqueue);
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index d59adc4be068..e3714e6db330 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -10,6 +10,13 @@
  #include 
  #include 
  
+enum virtio_vq_reset_step {

+   VIRTIO_VQ_RESET_STEP_NONE,
+   VIRTIO_VQ_RESET_STEP_DEVICE,
+   VIRTIO_VQ_RESET_STEP_VRING_RELEASE,
+   VIRTIO_VQ_RESET_STEP_VRING_ATTACH,
+};



This part looks not related to the subject.

And it needs detail documentation on this.

But I wonder how useful it is, anyway we can check the reset status via 
transport specific way and in the future we may want to do more than 
just resizing (e.g PASID).


Thanks



+
  /**
   * virtqueue - a queue to register buffers for sending or receiving.
   * @list: the chain of virtqueues for this device
@@ -33,6 +40,7 @@ struct virtqueue {
unsigned int num_free;
unsigned int num_max;
void *priv;
+   enum virtio_vq_reset_step reset;
  };
  
  int virtqueue_add_outbuf(struct virtqueue *vq,



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 09/26] virtio_ring: split: implement virtqueue_reset_vring_split()

2022-03-08 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

virtio ring supports reset.

Queue reset is divided into several stages.

1. notify device queue reset
2. vring release
3. attach new vring
4. notify device queue re-enable

After the first step is completed, the vring reset operation can be
performed. If the newly set vring num does not change, then just reset
the vq related value.

Otherwise, the vring will be released and the vring will be reallocated.
And the vring will be attached to the vq. If this process fails, the
function will exit, and the state of the vq will be the vring release
state. You can call this function again to reallocate the vring.

In addition, vring_align, may_reduce_num are necessary for reallocating
vring, so they are retained when creating vq.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 69 
  1 file changed, 69 insertions(+)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index e0422c04c903..148fb1fd3d5a 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -158,6 +158,12 @@ struct vring_virtqueue {
/* 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 vrings when enabling reset queue.
+*/
+   u32 vring_align;
+   bool may_reduce_num;
} split;
  
  		/* Available for packed ring */

@@ -217,6 +223,12 @@ struct vring_virtqueue {
  #endif
  };
  
+static void vring_free(struct virtqueue *vq);

+static void __vring_virtqueue_init_split(struct vring_virtqueue *vq,
+struct virtio_device *vdev);
+static int __vring_virtqueue_attach_split(struct vring_virtqueue *vq,
+ struct virtio_device *vdev,
+ struct vring vring);
  
  /*

   * Helpers.
@@ -1012,6 +1024,8 @@ static struct virtqueue *vring_create_virtqueue_split(
return NULL;
}
  
+	to_vvq(vq)->split.vring_align = vring_align;

+   to_vvq(vq)->split.may_reduce_num = may_reduce_num;
to_vvq(vq)->split.queue_dma_addr = vring.dma_addr;
to_vvq(vq)->split.queue_size_in_bytes = vring.queue_size_in_bytes;
to_vvq(vq)->we_own_ring = true;
@@ -1019,6 +1033,59 @@ static struct virtqueue *vring_create_virtqueue_split(
return vq;
  }
  
+static int virtqueue_reset_vring_split(struct virtqueue *_vq, u32 num)

+{



So what this function does is to resize the virtqueue actually, I 
suggest to rename it as virtqueue_resize_split().




+   struct vring_virtqueue *vq = to_vvq(_vq);
+   struct virtio_device *vdev = _vq->vdev;
+   struct vring_split vring;
+   int err;
+
+   if (num > _vq->num_max)
+   return -E2BIG;
+
+   switch (vq->vq.reset) {
+   case VIRTIO_VQ_RESET_STEP_NONE:
+   return -ENOENT;
+
+   case VIRTIO_VQ_RESET_STEP_VRING_ATTACH:
+   case VIRTIO_VQ_RESET_STEP_DEVICE:
+   if (vq->split.vring.num == num || !num)
+   break;
+
+   vring_free(_vq);
+
+   fallthrough;
+
+   case VIRTIO_VQ_RESET_STEP_VRING_RELEASE:
+   if (!num)
+   num = vq->split.vring.num;
+
+   err = vring_create_vring_split(&vring, vdev,
+  vq->split.vring_align,
+  vq->weak_barriers,
+  vq->split.may_reduce_num, num);
+   if (err)
+   return -ENOMEM;



We'd better need a safe fallback here like:

If we can't allocate new memory, we can keep using the current one. 
Otherwise an ethtool -G fail may make the device not usable.


This could be done by not freeing the old vring and virtqueue states 
until new is allocated.




+
+   err = __vring_virtqueue_attach_split(vq, vdev, vring.vring);
+   if (err) {
+   vring_free_queue(vdev, vring.queue_size_in_bytes,
+vring.queue,
+vring.dma_addr);
+   return -ENOMEM;
+   }
+
+   vq->split.queue_dma_addr = vring.dma_addr;
+   vq->split.queue_size_in_bytes = vring.queue_size_in_bytes;
+   }
+
+   __vring_virtqueue_init_split(vq, vdev);
+   vq->we_own_ring = true;



This seems wrong, we have the transport (rproc/mlxtbf) that allocate the 
vring by themselves. I think we need to fail the resize for we_own_ring 
== false.


Thanks




+   vq->vq.reset = VIRTIO_VQ_RESET_STEP_VRING_ATTACH;
+
+   return 0;
+}
+
  
  /*

   * Packed ring specif

Re: [PATCH v7 13/26] virtio: queue_reset: struct virtio_config_ops add callbacks for queue_reset

2022-03-09 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

Performing reset on a queue is divided into four steps:

  1. reset_vq() - notify the device to reset the queue
  2. virtqueue_detach_unused_buf()  - recycle the buffer submitted
  3. virtqueue_reset_vring()- reset the vring (may re-alloc)
  4. enable_reset_vq()  - mmap vring to device, and enable the queue

So add two callbacks reset_vq, enable_reset_vq to struct
virtio_config_ops.

Signed-off-by: Xuan Zhuo 
---
  include/linux/virtio_config.h | 11 +++
  1 file changed, 11 insertions(+)

diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 4d107ad31149..d51906b1389f 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -74,6 +74,15 @@ struct virtio_shm_region {
   * @set_vq_affinity: set the affinity for a virtqueue (optional).
   * @get_vq_affinity: get the affinity for a virtqueue (optional).
   * @get_shm_region: get a shared memory region based on the index.
+ * @reset_vq: reset a queue individually (optional).
+ * vq: the virtqueue
+ * Returns 0 on success or error status
+ * Caller should guarantee that the vring is not accessed by any functions
+ * of virtqueue.



We probably need to be more accurate here:

1) reset_vq will guarantee that the callbacks are disabled or synchronized
2) except for the callback, the caller should guarantee ...

Thanks



+ * @enable_reset_vq: enable a reset queue
+ * vq: the virtqueue
+ * Returns 0 on success or error status
+ * If reset_vq is set, then enable_reset_vq must also be set.
   */
  typedef void vq_callback_t(struct virtqueue *);
  struct virtio_config_ops {
@@ -100,6 +109,8 @@ struct virtio_config_ops {
int index);
bool (*get_shm_region)(struct virtio_device *vdev,
   struct virtio_shm_region *region, u8 id);
+   int (*reset_vq)(struct virtqueue *vq);
+   int (*enable_reset_vq)(struct virtqueue *vq);
  };
  
  /* If driver didn't advertise the feature, it will never appear. */



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 14/26] virtio: add helper for queue reset

2022-03-09 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

Add helper for virtio queue reset.

* virtio_reset_vq(): reset a queue individually
* virtio_enable_resetq(): enable a reset queue

Signed-off-by: Xuan Zhuo 
---
  include/linux/virtio_config.h | 40 +++
  1 file changed, 40 insertions(+)

diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index d51906b1389f..0b81fbe17c85 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -230,6 +230,46 @@ int virtio_find_vqs_ctx(struct virtio_device *vdev, 
unsigned nvqs,
  desc);
  }
  
+/**

+ * virtio_reset_vq - reset a queue individually
+ * @vq: the virtqueue
+ *
+ * returns 0 on success or error status
+ *
+ * The api process of reset under normal circumstances:
+ * 1. virtio_reset_vq()  - notify the device to reset the queue
+ * 2. virtqueue_detach_unused_buf()  - recycle the buffer submitted
+ * 3. virtqueue_reset_vring()- reset the vring (may re-alloc)
+ * 4. virtio_enable_resetq() - mmap vring to device, and enable 
the queue
+ *
+ * Caller should guarantee that the vring is not accessed by any functions
+ * of virtqueue.
+ */
+static inline
+int virtio_reset_vq(struct virtqueue *vq)
+{



It looks to me the prefix "virtio" is used for the device specific 
operations.


I wonder if it's better to rename this as virtqueue_reste() and move it 
to virtio_ring.c?


Thanks



+   if (!vq->vdev->config->reset_vq)
+   return -ENOENT;
+
+   return vq->vdev->config->reset_vq(vq);
+}
+
+/**
+ * virtio_enable_resetq - enable a reset queue
+ * @vq: the virtqueue
+ *
+ * returns 0 on success or error status
+ *
+ */
+static inline
+int virtio_enable_resetq(struct virtqueue *vq)
+{
+   if (!vq->vdev->config->enable_reset_vq)
+   return -ENOENT;
+
+   return vq->vdev->config->enable_reset_vq(vq);
+}
+
  /**
   * virtio_device_ready - enable vq use in probe function
   * @vdev: the device



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 17/26] virtio_pci: queue_reset: support VIRTIO_F_RING_RESET

2022-03-09 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

This patch implements virtio pci support for QUEUE RESET.

Performing reset on a queue is divided into these steps:

  1. virtio_reset_vq()  - notify the device to reset the queue
  2. virtqueue_detach_unused_buf()  - recycle the buffer submitted
  3. virtqueue_reset_vring()- reset the vring (may re-alloc)
  4. virtio_enable_resetq() - mmap vring to device, and enable the queue

This patch implements virtio_reset_vq(), virtio_enable_resetq() in the
pci scenario.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_pci_common.c |  8 +--
  drivers/virtio/virtio_pci_modern.c | 83 ++
  2 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/drivers/virtio/virtio_pci_common.c 
b/drivers/virtio/virtio_pci_common.c
index fdbde1db5ec5..863d3a8a0956 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -248,9 +248,11 @@ static void vp_del_vq(struct virtqueue *vq)
struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
unsigned long flags;
  
-	spin_lock_irqsave(&vp_dev->lock, flags);

-   list_del(&info->node);
-   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   if (!vq->reset) {
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_del(&info->node);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   }
  
  	vp_dev->del_vq(info);

kfree(info);
diff --git a/drivers/virtio/virtio_pci_modern.c 
b/drivers/virtio/virtio_pci_modern.c
index 49a4493732cf..3c67d3607802 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -34,6 +34,9 @@ static void vp_transport_features(struct virtio_device *vdev, 
u64 features)
if ((features & BIT_ULL(VIRTIO_F_SR_IOV)) &&
pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV))
__virtio_set_bit(vdev, VIRTIO_F_SR_IOV);
+
+   if (features & BIT_ULL(VIRTIO_F_RING_RESET))
+   __virtio_set_bit(vdev, VIRTIO_F_RING_RESET);
  }
  
  /* virtio config->finalize_features() implementation */

@@ -199,6 +202,82 @@ static int vp_active_vq(struct virtqueue *vq, u16 msix_vec)
return 0;
  }
  
+static int vp_modern_reset_vq(struct virtqueue *vq)

+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+   struct virtio_pci_vq_info *info;
+   unsigned long flags;
+   unsigned int irq;
+
+   if (!virtio_has_feature(vq->vdev, VIRTIO_F_RING_RESET))
+   return -ENOENT;
+
+   vp_modern_set_queue_reset(mdev, vq->index);
+
+   info = vp_dev->vqs[vq->index];
+
+   /* delete vq from irq handler */
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_del(&info->node);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+
+   INIT_LIST_HEAD(&info->node);
+
+   vq->reset = VIRTIO_VQ_RESET_STEP_DEVICE;
+
+   /* sync irq callback. */
+   if (vp_dev->intx_enabled) {
+   irq = vp_dev->pci_dev->irq;
+
+   } else {
+   if (info->msix_vector == VIRTIO_MSI_NO_VECTOR)
+   return 0;
+
+   irq = pci_irq_vector(vp_dev->pci_dev, info->msix_vector);
+   }
+
+   synchronize_irq(irq);



Synchronize_irq() is not sufficient here since it breaks the effort of 
the interrupt hardening which is done by commits:


080cd7c3ac87 virtio-pci: harden INTX interrupts
9e35276a5344 virtio_pci: harden MSI-X interrupts

Unfortunately  080cd7c3ac87 introduces an issue that disable_irq() were 
used for the affinity managed irq but we're discussing a fix.




+
+   return 0;
+}
+
+static int vp_modern_enable_reset_vq(struct virtqueue *vq)
+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+   struct virtio_pci_vq_info *info;
+   unsigned long flags, index;
+   int err;
+
+   if (vq->reset != VIRTIO_VQ_RESET_STEP_VRING_ATTACH)
+   return -EBUSY;
+
+   index = vq->index;
+   info = vp_dev->vqs[index];
+
+   /* check queue reset status */
+   if (vp_modern_get_queue_reset(mdev, index) != 1)
+   return -EBUSY;
+
+   err = vp_active_vq(vq, info->msix_vector);
+   if (err)
+   return err;
+
+   if (vq->callback) {
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_add(&info->node, &vp_dev->virtqueues);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   } else {
+   INIT_LIST_HEAD(&info->node);
+   }
+
+   vp_modern_set_queue_enable(&vp_dev->mdev, index, true);



Any reason we need to check queue_enable() here?

Thanks



+   vq->reset = VIRTIO_VQ_RESET_STEP_NONE;
+
+   return 0;
+}
+
  static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector)
  {
return vp_modern_c

Re: [PATCH v7 18/26] virtio: find_vqs() add arg sizes

2022-03-09 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

find_vqs() adds a new parameter sizes to specify the size of each vq
vring.

0 means use the maximum size supported by the backend.

In the split scenario, the meaning of size is the largest size, because
it may be limited by memory, the virtio core will try a smaller size.
And the size is power of 2.

Signed-off-by: Xuan Zhuo 
---
  arch/um/drivers/virtio_uml.c |  2 +-
  drivers/platform/mellanox/mlxbf-tmfifo.c |  3 ++-
  drivers/remoteproc/remoteproc_virtio.c   |  2 +-
  drivers/s390/virtio/virtio_ccw.c |  2 +-
  drivers/virtio/virtio_mmio.c |  2 +-
  drivers/virtio/virtio_pci_common.c   |  2 +-
  drivers/virtio/virtio_pci_common.h   |  2 +-
  drivers/virtio/virtio_pci_modern.c   |  5 +++--
  drivers/virtio/virtio_vdpa.c |  2 +-
  include/linux/virtio_config.h| 11 +++
  10 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
index ba562d68dc04..055b91ccbe8a 100644
--- a/arch/um/drivers/virtio_uml.c
+++ b/arch/um/drivers/virtio_uml.c
@@ -998,7 +998,7 @@ static struct virtqueue *vu_setup_vq(struct virtio_device 
*vdev,
  static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
   struct virtqueue *vqs[], vq_callback_t *callbacks[],
   const char * const names[], const bool *ctx,
-  struct irq_affinity *desc)
+  struct irq_affinity *desc, u32 sizes[])
  {
struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
int i, queue_idx = 0, rc;
diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c 
b/drivers/platform/mellanox/mlxbf-tmfifo.c
index 38800e86ed8a..aea7aa218b22 100644
--- a/drivers/platform/mellanox/mlxbf-tmfifo.c
+++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
@@ -929,7 +929,8 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct 
virtio_device *vdev,
vq_callback_t *callbacks[],
const char * const names[],



Nit: Let's be consistent here, e.g move sizes before ctx (this is what 
next patch did and seems cleaner).


Thanks



const bool *ctx,
-   struct irq_affinity *desc)
+   struct irq_affinity *desc,
+   u32 sizes[])
  {
struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
struct mlxbf_tmfifo_vring *vring;
diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index 70ab496d0431..3a167bec5b09 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -157,7 +157,7 @@ static int rproc_virtio_find_vqs(struct virtio_device 
*vdev, unsigned int nvqs,
 vq_callback_t *callbacks[],
 const char * const names[],
 const bool * ctx,
-struct irq_affinity *desc)
+struct irq_affinity *desc, u32 sizes[])
  {
int i, ret, queue_idx = 0;
  
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c

index d35e7a3f7067..b74e08c71534 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -632,7 +632,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, 
unsigned nvqs,
   vq_callback_t *callbacks[],
   const char * const names[],
   const bool *ctx,
-  struct irq_affinity *desc)
+  struct irq_affinity *desc, u32 sizes[])
  {
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
unsigned long *indicatorp = NULL;
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index a41abc8051b9..55d575f6ef2d 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -462,7 +462,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned 
nvqs,
   vq_callback_t *callbacks[],
   const char * const names[],
   const bool *ctx,
-  struct irq_affinity *desc)
+  struct irq_affinity *desc, u32 sizes[])
  {
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
int irq = platform_get_irq(vm_dev->pdev, 0);
diff --git a/drivers/virtio/virtio_pci_common.c 
b/drivers/virtio/virtio_pci_common.c
index 863d3a8a0956..8e8fa7e5ad80 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -428,7 +428,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, 
unsigned nvqs,
  int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
stru

Re: [PATCH v7 21/26] virtio: add helper virtio_find_vqs_ctx_size()

2022-03-09 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

Introduce helper virtio_find_vqs_ctx_size() to call find_vqs and specify
the maximum size of each vq ring.

Signed-off-by: Xuan Zhuo 
---
  include/linux/virtio_config.h | 12 
  1 file changed, 12 insertions(+)

diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 5157524d8036..921d8610db0c 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -233,6 +233,18 @@ int virtio_find_vqs_ctx(struct virtio_device *vdev, 
unsigned nvqs,
  desc, NULL);
  }
  
+static inline

+int virtio_find_vqs_ctx_size(struct virtio_device *vdev, u32 nvqs,
+struct virtqueue *vqs[],
+vq_callback_t *callbacks[],
+const char * const names[],
+const bool *ctx, struct irq_affinity *desc,
+u32 sizes[])
+{
+   return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, ctx,
+ desc, sizes);
+}



Do we need to convert all the open coded direct call to find_vqs() other 
than net?


Thanks



+
  /**
   * virtio_reset_vq - reset a queue individually
   * @vq: the virtqueue



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 23/26] virtio_net: split free_unused_bufs()

2022-03-09 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

This patch separates two functions for freeing sq buf and rq buf from
free_unused_bufs().

When supporting the enable/disable tx/rq queue in the future, it is
necessary to support separate recovery of a sq buf or a rq buf.

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 



---
  drivers/net/virtio_net.c | 53 +++-
  1 file changed, 31 insertions(+), 22 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 59b1ea82f5f0..409a8e180918 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2804,36 +2804,45 @@ static void free_receive_page_frags(struct virtnet_info 
*vi)
put_page(vi->rq[i].alloc_frag.page);
  }
  
-static void free_unused_bufs(struct virtnet_info *vi)

+static void virtnet_sq_free_unused_bufs(struct virtnet_info *vi,
+   struct send_queue *sq)
  {
void *buf;
-   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) {
-   if (!is_xdp_frame(buf))
-   dev_kfree_skb(buf);
-   else
-   xdp_return_frame(ptr_to_xdp(buf));
-   }
+   while ((buf = virtqueue_detach_unused_buf(sq->vq)) != NULL) {
+   if (!is_xdp_frame(buf))
+   dev_kfree_skb(buf);
+   else
+   xdp_return_frame(ptr_to_xdp(buf));
}
+}
  
-	for (i = 0; i < vi->max_queue_pairs; i++) {

-   struct virtqueue *vq = vi->rq[i].vq;
-
-   while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
-   if (vi->mergeable_rx_bufs) {
-   put_page(virt_to_head_page(buf));
-   } else if (vi->big_packets) {
-   give_pages(&vi->rq[i], buf);
-   } else {
-   put_page(virt_to_head_page(buf));
-   }
-   }
+static void virtnet_rq_free_unused_bufs(struct virtnet_info *vi,
+   struct receive_queue *rq)
+{
+   void *buf;
+
+   while ((buf = virtqueue_detach_unused_buf(rq->vq)) != NULL) {
+   if (vi->mergeable_rx_bufs)
+   put_page(virt_to_head_page(buf));
+   else if (vi->big_packets)
+   give_pages(rq, buf);
+   else
+   put_page(virt_to_head_page(buf));
}
  }
  
+static void free_unused_bufs(struct virtnet_info *vi)

+{
+   int i;
+
+   for (i = 0; i < vi->max_queue_pairs; i++)
+   virtnet_sq_free_unused_bufs(vi, vi->sq + i);
+
+   for (i = 0; i < vi->max_queue_pairs; i++)
+   virtnet_rq_free_unused_bufs(vi, vi->rq + i);
+}
+
  static void virtnet_del_vqs(struct virtnet_info *vi)
  {
struct virtio_device *vdev = vi->vdev;



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 24/26] virtio_net: support rx/tx queue reset

2022-03-09 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

This patch implements the reset function of the rx, tx queues.

Based on this function, it is possible to modify the ring num of the
queue. And quickly recycle the buffer in the queue.

In the process of the queue disable, in theory, as long as virtio
supports queue reset, there will be no exceptions.

However, in the process of the queue enable, there may be exceptions due to
memory allocation.  In this case, vq is not available, but we still have
to execute napi_enable(). Because napi_disable is similar to a lock,
napi_enable must be called after calling napi_disable.

Signed-off-by: Xuan Zhuo 
---
  drivers/net/virtio_net.c | 107 +++
  1 file changed, 107 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 409a8e180918..323dcef0 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -251,6 +251,11 @@ struct padded_vnet_hdr {
char padding[4];
  };
  
+static void virtnet_sq_free_unused_bufs(struct virtnet_info *vi,

+   struct send_queue *sq);
+static void virtnet_rq_free_unused_bufs(struct virtnet_info *vi,
+   struct receive_queue *rq);
+
  static bool is_xdp_frame(void *ptr)
  {
return (unsigned long)ptr & VIRTIO_XDP_FLAG;
@@ -1369,6 +1374,9 @@ static void virtnet_napi_enable(struct virtqueue *vq, 
struct napi_struct *napi)
  {
napi_enable(napi);
  
+	if (vq->reset)

+   return;
+



Let's WARN_ONCE() here?



/* If all buffers were filled by other side before we napi_enabled, we
 * won't get another interrupt, so process any outstanding packets now.
 * Call local_bh_enable after to trigger softIRQ processing.
@@ -1413,6 +1421,10 @@ static void refill_work(struct work_struct *work)
struct receive_queue *rq = &vi->rq[i];
  
  		napi_disable(&rq->napi);

+   if (rq->vq->reset) {
+   virtnet_napi_enable(rq->vq, &rq->napi);
+   continue;
+   }



This seems racy and it's a hint that we need sync with the refill work 
during reset like what we did in virtnet_close():


    /* Make sure refill_work doesn't re-enable napi! */
    cancel_delayed_work_sync(&vi->refill);



still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
virtnet_napi_enable(rq->vq, &rq->napi);
  
@@ -1523,6 +1535,9 @@ static void virtnet_poll_cleantx(struct receive_queue *rq)

if (!sq->napi.weight || is_xdp_raw_buffer_queue(vi, index))
return;
  
+	if (sq->vq->reset)

+   return;



It looks to me we'd better either WARN or just remove this. Since it 
looks like a workaround for the un-synchronized NAPI somehow.




+
if (__netif_tx_trylock(txq)) {
do {
virtqueue_disable_cb(sq->vq);
@@ -1769,6 +1784,98 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, 
struct net_device *dev)
return NETDEV_TX_OK;
  }
  
+static int virtnet_rx_vq_reset(struct virtnet_info *vi,

+  struct receive_queue *rq, u32 ring_num)



It's better to rename this as virtnet_rx_resize().



+{
+   int err;
+
+   /* stop napi */
+   napi_disable(&rq->napi);
+



Here, as discussed above, we need synchronize with the refill work.



+   /* reset the queue */
+   err = virtio_reset_vq(rq->vq);
+   if (err)
+   goto err;



Btw, most comment of this function seems useless since code already 
explain themselves.




+
+   /* free bufs */
+   virtnet_rq_free_unused_bufs(vi, rq);
+
+   /* reset vring. */
+   err = virtqueue_reset_vring(rq->vq, ring_num);
+   if (err)
+   goto err;
+
+   /* enable reset queue */
+   err = virtio_enable_resetq(rq->vq);
+   if (err)
+   goto err;
+
+   /* fill recv */
+   if (!try_fill_recv(vi, rq, GFP_KERNEL))
+   schedule_delayed_work(&vi->refill, 0);
+
+   /* enable napi */
+   virtnet_napi_enable(rq->vq, &rq->napi);
+   return 0;
+
+err:
+   netdev_err(vi->dev,
+  "reset rx reset vq fail: rx queue index: %ld err: %d\n",
+  rq - vi->rq, err);
+   virtnet_napi_enable(rq->vq, &rq->napi);
+   return err;
+}
+
+static int virtnet_tx_vq_reset(struct virtnet_info *vi,
+  struct send_queue *sq, u32 ring_num)
+{



It looks to me it's better to rename this as "virtnet_rx_resize()"



+   struct netdev_queue *txq;
+   int err, qindex;
+
+   qindex = sq - vi->sq;
+
+   txq = netdev_get_tx_queue(vi->dev, qindex);
+   __netif_tx_lock_bh(txq);
+
+   /* stop tx queue and napi */
+   netif_stop_subqueue(vi->dev, qindex);
+   virtnet_napi_tx_disable(&sq->napi);



There's no need to hold tx lock for napi disable.

Thanks



+
+   __netif_tx_un

Re: [PATCH v7 25/26] virtio_net: set the default max ring size by find_vqs()

2022-03-09 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

Use virtio_find_vqs_ctx_size() to specify the maximum ring size of tx,
rx at the same time.

  | rx/tx ring size
---
speed == UNKNOWN or < 10G| 1024
speed < 40G  | 4096
speed >= 40G | 8192

Call virtnet_update_settings() once before calling init_vqs() to update
speed.

Signed-off-by: Xuan Zhuo 
---
  drivers/net/virtio_net.c | 42 
  1 file changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 323dcef0..f1bdc6ce21c3 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2977,6 +2977,29 @@ static unsigned int mergeable_min_buf_len(struct 
virtnet_info *vi, struct virtqu
   (unsigned int)GOOD_PACKET_LEN);
  }
  
+static void virtnet_config_sizes(struct virtnet_info *vi, u32 *sizes)

+{
+   u32 i, rx_size, tx_size;
+
+   if (vi->speed == SPEED_UNKNOWN || vi->speed < SPEED_1) {
+   rx_size = 1024;
+   tx_size = 1024;
+
+   } else if (vi->speed < SPEED_4) {
+   rx_size = 1024 * 4;
+   tx_size = 1024 * 4;
+
+   } else {
+   rx_size = 1024 * 8;
+   tx_size = 1024 * 8;
+   }
+
+   for (i = 0; i < vi->max_queue_pairs; i++) {
+   sizes[rxq2vq(i)] = rx_size;
+   sizes[txq2vq(i)] = tx_size;
+   }
+}
+
  static int virtnet_find_vqs(struct virtnet_info *vi)
  {
vq_callback_t **callbacks;
@@ -2984,6 +3007,7 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
int ret = -ENOMEM;
int i, total_vqs;
const char **names;
+   u32 *sizes;
bool *ctx;
  
  	/* We expect 1 RX virtqueue followed by 1 TX virtqueue, followed by

@@ -3011,10 +3035,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
ctx = NULL;
}
  
+	sizes = kmalloc_array(total_vqs, sizeof(*sizes), GFP_KERNEL);

+   if (!sizes)
+   goto err_sizes;
+
/* Parameters for control virtqueue, if any */
if (vi->has_cvq) {
callbacks[total_vqs - 1] = NULL;
names[total_vqs - 1] = "control";
+   sizes[total_vqs - 1] = 0;



Nit: Do we need a sane value for the control vq? (e.g 64)

Thanks



}
  
  	/* Allocate/initialize parameters for send/receive virtqueues */

@@ -3029,8 +3058,10 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
ctx[rxq2vq(i)] = true;
}
  
-	ret = virtio_find_vqs_ctx(vi->vdev, total_vqs, vqs, callbacks,

- names, ctx, NULL);
+   virtnet_config_sizes(vi, sizes);
+
+   ret = virtio_find_vqs_ctx_size(vi->vdev, total_vqs, vqs, callbacks,
+  names, ctx, NULL, sizes);
if (ret)
goto err_find;
  
@@ -3050,6 +3081,8 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  
  
  err_find:

+   kfree(sizes);
+err_sizes:
kfree(ctx);
  err_ctx:
kfree(names);
@@ -3368,6 +3401,9 @@ static int virtnet_probe(struct virtio_device *vdev)
vi->curr_queue_pairs = num_online_cpus();
vi->max_queue_pairs = max_queue_pairs;
  
+	virtnet_init_settings(dev);

+   virtnet_update_settings(vi);
+
/* Allocate/initialize the rx/tx queues, and invoke find_vqs */
err = init_vqs(vi);
if (err)
@@ -3380,8 +3416,6 @@ static int virtnet_probe(struct virtio_device *vdev)
netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-	virtnet_init_settings(dev);

-
if (virtio_has_feature(vdev, VIRTIO_NET_F_STANDBY)) {
vi->failover = net_failover_create(vi->dev);
if (IS_ERR(vi->failover)) {



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 26/26] virtio_net: support set_ringparam

2022-03-09 Thread Jason Wang


在 2022/3/8 下午8:35, Xuan Zhuo 写道:

Support set_ringparam based on virtio queue reset.

The rx,tx_pending required to be passed must be power of 2.

Signed-off-by: Xuan Zhuo 
---
  drivers/net/virtio_net.c | 47 
  1 file changed, 47 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index f1bdc6ce21c3..1fa2d632a994 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2290,6 +2290,52 @@ static void virtnet_get_ringparam(struct net_device *dev,
ring->tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
  }
  
+static int virtnet_set_ringparam(struct net_device *dev,

+struct ethtool_ringparam *ring,
+struct kernel_ethtool_ringparam *kernel_ring,
+struct netlink_ext_ack *extack)
+{
+   struct virtnet_info *vi = netdev_priv(dev);
+   u32 rx_pending, tx_pending;
+   struct receive_queue *rq;
+   struct send_queue *sq;
+   int i, err;
+
+   if (ring->rx_mini_pending || ring->rx_jumbo_pending)
+   return -EINVAL;



Any chance that we may hit this EINVAL?

Thanks



+
+   rx_pending = virtqueue_get_vring_size(vi->rq[0].vq);
+   tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
+
+   if (ring->rx_pending == rx_pending &&
+   ring->tx_pending == tx_pending)
+   return 0;
+
+   if (ring->rx_pending > virtqueue_get_vring_max_size(vi->rq[0].vq))
+   return -EINVAL;
+
+   if (ring->tx_pending > virtqueue_get_vring_max_size(vi->sq[0].vq))
+   return -EINVAL;
+
+   for (i = 0; i < vi->max_queue_pairs; i++) {
+   rq = vi->rq + i;
+   sq = vi->sq + i;
+
+   if (ring->tx_pending != tx_pending) {
+   err = virtnet_tx_vq_reset(vi, sq, ring->tx_pending);
+   if (err)
+   return err;
+   }
+
+   if (ring->rx_pending != rx_pending) {
+   err = virtnet_rx_vq_reset(vi, rq, ring->rx_pending);
+   if (err)
+   return err;
+   }
+   }
+
+   return 0;
+}
  
  static void virtnet_get_drvinfo(struct net_device *dev,

struct ethtool_drvinfo *info)
@@ -2523,6 +2569,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
.get_drvinfo = virtnet_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = virtnet_get_ringparam,
+   .set_ringparam = virtnet_set_ringparam,
.get_strings = virtnet_get_strings,
.get_sset_count = virtnet_get_sset_count,
.get_ethtool_stats = virtnet_get_ethtool_stats,



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v7 17/26] virtio_pci: queue_reset: support VIRTIO_F_RING_RESET

2022-03-10 Thread Jason Wang


在 2022/3/9 下午5:32, Xuan Zhuo 写道:

On Wed, 9 Mar 2022 16:54:10 +0800, Jason Wang  wrote:

在 2022/3/8 下午8:35, Xuan Zhuo 写道:

This patch implements virtio pci support for QUEUE RESET.

Performing reset on a queue is divided into these steps:

   1. virtio_reset_vq()  - notify the device to reset the queue
   2. virtqueue_detach_unused_buf()  - recycle the buffer submitted
   3. virtqueue_reset_vring()- reset the vring (may re-alloc)
   4. virtio_enable_resetq() - mmap vring to device, and enable the 
queue

This patch implements virtio_reset_vq(), virtio_enable_resetq() in the
pci scenario.

Signed-off-by: Xuan Zhuo 
---
   drivers/virtio/virtio_pci_common.c |  8 +--
   drivers/virtio/virtio_pci_modern.c | 83 ++
   2 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/drivers/virtio/virtio_pci_common.c 
b/drivers/virtio/virtio_pci_common.c
index fdbde1db5ec5..863d3a8a0956 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -248,9 +248,11 @@ static void vp_del_vq(struct virtqueue *vq)
struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
unsigned long flags;

-   spin_lock_irqsave(&vp_dev->lock, flags);
-   list_del(&info->node);
-   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   if (!vq->reset) {
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_del(&info->node);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   }

vp_dev->del_vq(info);
kfree(info);
diff --git a/drivers/virtio/virtio_pci_modern.c 
b/drivers/virtio/virtio_pci_modern.c
index 49a4493732cf..3c67d3607802 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -34,6 +34,9 @@ static void vp_transport_features(struct virtio_device *vdev, 
u64 features)
if ((features & BIT_ULL(VIRTIO_F_SR_IOV)) &&
pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV))
__virtio_set_bit(vdev, VIRTIO_F_SR_IOV);
+
+   if (features & BIT_ULL(VIRTIO_F_RING_RESET))
+   __virtio_set_bit(vdev, VIRTIO_F_RING_RESET);
   }

   /* virtio config->finalize_features() implementation */
@@ -199,6 +202,82 @@ static int vp_active_vq(struct virtqueue *vq, u16 msix_vec)
return 0;
   }

+static int vp_modern_reset_vq(struct virtqueue *vq)
+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+   struct virtio_pci_vq_info *info;
+   unsigned long flags;
+   unsigned int irq;
+
+   if (!virtio_has_feature(vq->vdev, VIRTIO_F_RING_RESET))
+   return -ENOENT;
+
+   vp_modern_set_queue_reset(mdev, vq->index);
+
+   info = vp_dev->vqs[vq->index];
+
+   /* delete vq from irq handler */
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_del(&info->node);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+
+   INIT_LIST_HEAD(&info->node);
+
+   vq->reset = VIRTIO_VQ_RESET_STEP_DEVICE;
+
+   /* sync irq callback. */
+   if (vp_dev->intx_enabled) {
+   irq = vp_dev->pci_dev->irq;
+
+   } else {
+   if (info->msix_vector == VIRTIO_MSI_NO_VECTOR)
+   return 0;
+
+   irq = pci_irq_vector(vp_dev->pci_dev, info->msix_vector);
+   }
+
+   synchronize_irq(irq);


Synchronize_irq() is not sufficient here since it breaks the effort of
the interrupt hardening which is done by commits:

080cd7c3ac87 virtio-pci: harden INTX interrupts
9e35276a5344 virtio_pci: harden MSI-X interrupts

Unfortunately  080cd7c3ac87 introduces an issue that disable_irq() were
used for the affinity managed irq but we're discussing a fix.

I need to understand it first.




+
+   return 0;
+}
+
+static int vp_modern_enable_reset_vq(struct virtqueue *vq)
+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+   struct virtio_pci_vq_info *info;
+   unsigned long flags, index;
+   int err;
+
+   if (vq->reset != VIRTIO_VQ_RESET_STEP_VRING_ATTACH)
+   return -EBUSY;
+
+   index = vq->index;
+   info = vp_dev->vqs[index];
+
+   /* check queue reset status */
+   if (vp_modern_get_queue_reset(mdev, index) != 1)
+   return -EBUSY;
+
+   err = vp_active_vq(vq, info->msix_vector);
+   if (err)
+   return err;
+
+   if (vq->callback) {
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_add(&info->node, &vp_dev->virtqueues);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   } else {
+   INIT_LIST_HEAD(&

Re: [PATCH v7 09/26] virtio_ring: split: implement virtqueue_reset_vring_split()

2022-03-10 Thread Jason Wang


在 2022/3/10 下午12:46, Xuan Zhuo 写道:

On Wed, 9 Mar 2022 15:55:44 +0800, Jason Wang  wrote:

在 2022/3/8 下午8:35, Xuan Zhuo 写道:

virtio ring supports reset.

Queue reset is divided into several stages.

1. notify device queue reset
2. vring release
3. attach new vring
4. notify device queue re-enable

After the first step is completed, the vring reset operation can be
performed. If the newly set vring num does not change, then just reset
the vq related value.

Otherwise, the vring will be released and the vring will be reallocated.
And the vring will be attached to the vq. If this process fails, the
function will exit, and the state of the vq will be the vring release
state. You can call this function again to reallocate the vring.

In addition, vring_align, may_reduce_num are necessary for reallocating
vring, so they are retained when creating vq.

Signed-off-by: Xuan Zhuo 
---
   drivers/virtio/virtio_ring.c | 69 
   1 file changed, 69 insertions(+)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index e0422c04c903..148fb1fd3d5a 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -158,6 +158,12 @@ struct vring_virtqueue {
/* 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 vrings when enabling reset queue.
+*/
+   u32 vring_align;
+   bool may_reduce_num;
} split;

/* Available for packed ring */
@@ -217,6 +223,12 @@ struct vring_virtqueue {
   #endif
   };

+static void vring_free(struct virtqueue *vq);
+static void __vring_virtqueue_init_split(struct vring_virtqueue *vq,
+struct virtio_device *vdev);
+static int __vring_virtqueue_attach_split(struct vring_virtqueue *vq,
+ struct virtio_device *vdev,
+ struct vring vring);

   /*
* Helpers.
@@ -1012,6 +1024,8 @@ static struct virtqueue *vring_create_virtqueue_split(
return NULL;
}

+   to_vvq(vq)->split.vring_align = vring_align;
+   to_vvq(vq)->split.may_reduce_num = may_reduce_num;
to_vvq(vq)->split.queue_dma_addr = vring.dma_addr;
to_vvq(vq)->split.queue_size_in_bytes = vring.queue_size_in_bytes;
to_vvq(vq)->we_own_ring = true;
@@ -1019,6 +1033,59 @@ static struct virtqueue *vring_create_virtqueue_split(
return vq;
   }

+static int virtqueue_reset_vring_split(struct virtqueue *_vq, u32 num)
+{


So what this function does is to resize the virtqueue actually, I
suggest to rename it as virtqueue_resize_split().

In addition to resize, when num is 0, the function is to reinitialize vq ring
related variables. For example avail_idx_shadow.



We need to move those logic to virtio_reset_vq() (I think we agree to 
have a better name of it).




So I think 'reset' is more appropriate.



The name is confusing at least to me, since we've already had 
virtio_reset_vq() and most of the logic is to do the resize.


Thanks




Thanks.




+   struct vring_virtqueue *vq = to_vvq(_vq);
+   struct virtio_device *vdev = _vq->vdev;
+   struct vring_split vring;
+   int err;
+
+   if (num > _vq->num_max)
+   return -E2BIG;
+
+   switch (vq->vq.reset) {
+   case VIRTIO_VQ_RESET_STEP_NONE:
+   return -ENOENT;
+
+   case VIRTIO_VQ_RESET_STEP_VRING_ATTACH:
+   case VIRTIO_VQ_RESET_STEP_DEVICE:
+   if (vq->split.vring.num == num || !num)
+   break;
+
+   vring_free(_vq);
+
+   fallthrough;
+
+   case VIRTIO_VQ_RESET_STEP_VRING_RELEASE:
+   if (!num)
+   num = vq->split.vring.num;
+
+   err = vring_create_vring_split(&vring, vdev,
+  vq->split.vring_align,
+  vq->weak_barriers,
+  vq->split.may_reduce_num, num);
+   if (err)
+   return -ENOMEM;


We'd better need a safe fallback here like:

If we can't allocate new memory, we can keep using the current one.
Otherwise an ethtool -G fail may make the device not usable.

This could be done by not freeing the old vring and virtqueue states
until new is allocated.



+
+   err = __vring_virtqueue_attach_split(vq, vdev, vring.vring);
+   if (err) {
+   vring_free_queue(vdev, vring.queue_size_in_bytes,
+vring.queue,
+

Re: [PATCH v7 17/26] virtio_pci: queue_reset: support VIRTIO_F_RING_RESET

2022-03-10 Thread Jason Wang


在 2022/3/10 下午4:20, Xuan Zhuo 写道:

On Wed, 9 Mar 2022 16:54:10 +0800, Jason Wang  wrote:

在 2022/3/8 下午8:35, Xuan Zhuo 写道:

This patch implements virtio pci support for QUEUE RESET.

Performing reset on a queue is divided into these steps:

   1. virtio_reset_vq()  - notify the device to reset the queue
   2. virtqueue_detach_unused_buf()  - recycle the buffer submitted
   3. virtqueue_reset_vring()- reset the vring (may re-alloc)
   4. virtio_enable_resetq() - mmap vring to device, and enable the 
queue

This patch implements virtio_reset_vq(), virtio_enable_resetq() in the
pci scenario.

Signed-off-by: Xuan Zhuo 
---
   drivers/virtio/virtio_pci_common.c |  8 +--
   drivers/virtio/virtio_pci_modern.c | 83 ++
   2 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/drivers/virtio/virtio_pci_common.c 
b/drivers/virtio/virtio_pci_common.c
index fdbde1db5ec5..863d3a8a0956 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -248,9 +248,11 @@ static void vp_del_vq(struct virtqueue *vq)
struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
unsigned long flags;

-   spin_lock_irqsave(&vp_dev->lock, flags);
-   list_del(&info->node);
-   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   if (!vq->reset) {
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_del(&info->node);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   }

vp_dev->del_vq(info);
kfree(info);
diff --git a/drivers/virtio/virtio_pci_modern.c 
b/drivers/virtio/virtio_pci_modern.c
index 49a4493732cf..3c67d3607802 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -34,6 +34,9 @@ static void vp_transport_features(struct virtio_device *vdev, 
u64 features)
if ((features & BIT_ULL(VIRTIO_F_SR_IOV)) &&
pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV))
__virtio_set_bit(vdev, VIRTIO_F_SR_IOV);
+
+   if (features & BIT_ULL(VIRTIO_F_RING_RESET))
+   __virtio_set_bit(vdev, VIRTIO_F_RING_RESET);
   }

   /* virtio config->finalize_features() implementation */
@@ -199,6 +202,82 @@ static int vp_active_vq(struct virtqueue *vq, u16 msix_vec)
return 0;
   }

+static int vp_modern_reset_vq(struct virtqueue *vq)
+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+   struct virtio_pci_vq_info *info;
+   unsigned long flags;
+   unsigned int irq;
+
+   if (!virtio_has_feature(vq->vdev, VIRTIO_F_RING_RESET))
+   return -ENOENT;
+
+   vp_modern_set_queue_reset(mdev, vq->index);
+
+   info = vp_dev->vqs[vq->index];
+
+   /* delete vq from irq handler */
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_del(&info->node);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+
+   INIT_LIST_HEAD(&info->node);
+
+   vq->reset = VIRTIO_VQ_RESET_STEP_DEVICE;
+
+   /* sync irq callback. */
+   if (vp_dev->intx_enabled) {
+   irq = vp_dev->pci_dev->irq;
+
+   } else {
+   if (info->msix_vector == VIRTIO_MSI_NO_VECTOR)
+   return 0;
+
+   irq = pci_irq_vector(vp_dev->pci_dev, info->msix_vector);
+   }
+
+   synchronize_irq(irq);


Synchronize_irq() is not sufficient here since it breaks the effort of
the interrupt hardening which is done by commits:

080cd7c3ac87 virtio-pci: harden INTX interrupts
9e35276a5344 virtio_pci: harden MSI-X interrupts

Unfortunately  080cd7c3ac87 introduces an issue that disable_irq() were
used for the affinity managed irq but we're discussing a fix.



ok, I think disable_irq() is still used here.

I want to determine the solution for this detail first. So I posted the code, I
hope Jason can help confirm this point first.

There are three situations in which vq corresponds to an interrupt

1. intx
2. msix: per vq vectors
2. msix: share irq

Essentially can be divided into two categories: per vq vectors and share irq.

For share irq is based on virtqueues to find vq, so I think it is safe as long
as list_del() is executed under the protection of the lock.

In the case of per vq vectors, disable_irq() is used.



See the discussion here[1], disable_irq() could be problematic for the 
block and scsi device that using affinity managed irq. We're waiting for 
the IRQ maintainer to comment on a solution. Other looks sane.


Thanks

[1] https://lkml.org/lkml/2022/3/8/743




Thanks.

+static int vp_modern_reset_vq(struct virtqueue *vq)
+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->m

Re: [PATCH v9 01/32] virtio: add helper virtqueue_get_vring_max_size()

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Record the maximum queue num supported by the device.

virtio-net can display the maximum (supported by hardware) ring size in
ethtool -g eth0.

When the subsequent patch implements vring reset, it can judge whether
the ring size passed by the driver is legal based on this.

Signed-off-by: Xuan Zhuo 
---
  arch/um/drivers/virtio_uml.c |  1 +
  drivers/platform/mellanox/mlxbf-tmfifo.c |  2 ++
  drivers/remoteproc/remoteproc_virtio.c   |  2 ++
  drivers/s390/virtio/virtio_ccw.c |  3 +++
  drivers/virtio/virtio_mmio.c |  2 ++
  drivers/virtio/virtio_pci_legacy.c   |  2 ++
  drivers/virtio/virtio_pci_modern.c   |  2 ++
  drivers/virtio/virtio_ring.c | 14 ++
  drivers/virtio/virtio_vdpa.c |  2 ++
  include/linux/virtio.h   |  2 ++
  10 files changed, 32 insertions(+)

diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
index ba562d68dc04..904993d15a85 100644
--- a/arch/um/drivers/virtio_uml.c
+++ b/arch/um/drivers/virtio_uml.c
@@ -945,6 +945,7 @@ static struct virtqueue *vu_setup_vq(struct virtio_device 
*vdev,
goto error_create;
}
vq->priv = info;
+   vq->num_max = num;
num = virtqueue_get_vring_size(vq);
  
  	if (vu_dev->protocol_features &

diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c 
b/drivers/platform/mellanox/mlxbf-tmfifo.c
index 38800e86ed8a..1ae3c56b66b0 100644
--- a/drivers/platform/mellanox/mlxbf-tmfifo.c
+++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
@@ -959,6 +959,8 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct 
virtio_device *vdev,
goto error;
}
  
+		vq->num_max = vring->num;

+
vqs[i] = vq;
vring->vq = vq;
vq->priv = vring;
diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index 70ab496d0431..7611755d0ae2 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -125,6 +125,8 @@ static struct virtqueue *rp_find_vq(struct virtio_device 
*vdev,
return ERR_PTR(-ENOMEM);
}
  
+	vq->num_max = len;



I wonder if this is correct.

It looks to me len is counted in bytes:

/**
 * struct rproc_vring - remoteproc vring state
 * @va: virtual address
 * @len: length, in bytes
 * @da: device address
 * @align: vring alignment
 * @notifyid: rproc-specific unique vring index
 * @rvdev: remote vdev
 * @vq: the virtqueue of this vring
 */
struct rproc_vring {
    void *va;
    int len;
    u32 da;
    u32 align;
    int notifyid;
    struct rproc_vdev *rvdev;
    struct virtqueue *vq;
};


Other looks good.

Thanks



+
rvring->vq = vq;
vq->priv = rvring;
  
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c

index d35e7a3f7067..468da60b56c5 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -529,6 +529,9 @@ static struct virtqueue *virtio_ccw_setup_vq(struct 
virtio_device *vdev,
err = -ENOMEM;
goto out_err;
}
+
+   vq->num_max = info->num;
+
/* it may have been reduced */
info->num = virtqueue_get_vring_size(vq);
  
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c

index 56128b9c46eb..a41abc8051b9 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -390,6 +390,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device 
*vdev, unsigned index,
goto error_new_virtqueue;
}
  
+	vq->num_max = num;

+
/* Activate the queue */
writel(virtqueue_get_vring_size(vq), vm_dev->base + 
VIRTIO_MMIO_QUEUE_NUM);
if (vm_dev->version == 1) {
diff --git a/drivers/virtio/virtio_pci_legacy.c 
b/drivers/virtio/virtio_pci_legacy.c
index 34141b9abe27..b68934fe6b5d 100644
--- a/drivers/virtio/virtio_pci_legacy.c
+++ b/drivers/virtio/virtio_pci_legacy.c
@@ -135,6 +135,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device 
*vp_dev,
if (!vq)
return ERR_PTR(-ENOMEM);
  
+	vq->num_max = num;

+
q_pfn = virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
if (q_pfn >> 32) {
dev_err(&vp_dev->pci_dev->dev,
diff --git a/drivers/virtio/virtio_pci_modern.c 
b/drivers/virtio/virtio_pci_modern.c
index 5455bc041fb6..86d301f272b8 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -218,6 +218,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device 
*vp_dev,
if (!vq)
return ERR_PTR(-ENOMEM);
  
+	vq->num_max = num;

+
/* activate the queue */
vp_modern_set_queue_size(mdev, index, virtqueue_get_vring_size(vq));
vp_modern_queue_address(mdev, index, virtqueue_get_desc_addr(vq),
diff --git a/drivers/virtio/virtio_ring.c b

Re: [PATCH v9 02/32] virtio: struct virtio_config_ops add callbacks for queue_reset

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Performing reset on a queue is divided into four steps:

  1. transport: notify the device to reset the queue
  2. vring: recycle the buffer submitted
  3. vring: reset/resize the vring (may re-alloc)
  4. transport: mmap vring to device, and enable the queue



Nit: it looks to me we'd better say it's an example (since step 3 or 
even 2 is not a must).





In order to support queue reset, add two callbacks(reset_vq,
enable_reset_vq) in struct virtio_config_ops to implement steps 1 and 4.

Signed-off-by: Xuan Zhuo 
---
  include/linux/virtio_config.h | 12 
  1 file changed, 12 insertions(+)

diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 4d107ad31149..d4adcd0e1c57 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -74,6 +74,16 @@ struct virtio_shm_region {
   * @set_vq_affinity: set the affinity for a virtqueue (optional).
   * @get_vq_affinity: get the affinity for a virtqueue (optional).
   * @get_shm_region: get a shared memory region based on the index.
+ * @reset_vq: reset a queue individually (optional).
+ * vq: the virtqueue
+ * Returns 0 on success or error status
+ * reset_vq will guarantee that the callbacks are disabled and 
synchronized.
+ * Except for the callback, the caller should guarantee that the vring is



I wonder what's the implications for virtio hardening[1]. In that 
series, we agree to have a synchronize_vqs() config ops to make sure 
callbacks are synchronized.


It uses a global flag and a device wise synchronization mechanism. It 
looks to me we need to switch to


1) per virtqueue flag
2) per virtqueue synchronization

Thanks



+ * not accessed by any functions of virtqueue.
+ * @enable_reset_vq: enable a reset queue
+ * vq: the virtqueue
+ * Returns 0 on success or error status
+ * If reset_vq is set, then enable_reset_vq must also be set.
   */
  typedef void vq_callback_t(struct virtqueue *);
  struct virtio_config_ops {
@@ -100,6 +110,8 @@ struct virtio_config_ops {
int index);
bool (*get_shm_region)(struct virtio_device *vdev,
   struct virtio_shm_region *region, u8 id);
+   int (*reset_vq)(struct virtqueue *vq);
+   int (*enable_reset_vq)(struct virtqueue *vq);
  };
  
  /* If driver didn't advertise the feature, it will never appear. */



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 02/32] virtio: struct virtio_config_ops add callbacks for queue_reset

2022-04-11 Thread Jason Wang
On Tue, Apr 12, 2022 at 10:47 AM Jason Wang  wrote:
>
>
> 在 2022/4/6 上午11:43, Xuan Zhuo 写道:
> > Performing reset on a queue is divided into four steps:
> >
> >   1. transport: notify the device to reset the queue
> >   2. vring: recycle the buffer submitted
> >   3. vring: reset/resize the vring (may re-alloc)
> >   4. transport: mmap vring to device, and enable the queue
>
>
> Nit: it looks to me we'd better say it's an example (since step 3 or
> even 2 is not a must).
>
>
> >
> > In order to support queue reset, add two callbacks(reset_vq,
> > enable_reset_vq) in struct virtio_config_ops to implement steps 1 and 4.
> >
> > Signed-off-by: Xuan Zhuo 
> > ---
> >   include/linux/virtio_config.h | 12 
> >   1 file changed, 12 insertions(+)
> >
> > diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
> > index 4d107ad31149..d4adcd0e1c57 100644
> > --- a/include/linux/virtio_config.h
> > +++ b/include/linux/virtio_config.h
> > @@ -74,6 +74,16 @@ struct virtio_shm_region {
> >* @set_vq_affinity: set the affinity for a virtqueue (optional).
> >* @get_vq_affinity: get the affinity for a virtqueue (optional).
> >* @get_shm_region: get a shared memory region based on the index.
> > + * @reset_vq: reset a queue individually (optional).
> > + *   vq: the virtqueue
> > + *   Returns 0 on success or error status
> > + *   reset_vq will guarantee that the callbacks are disabled and 
> > synchronized.
> > + *   Except for the callback, the caller should guarantee that the vring is
>
>
> I wonder what's the implications for virtio hardening[1]. In that

For [1] I meant
https://lore.kernel.org/lkml/20220406083538.16274-1-jasow...@redhat.com/

Thanks


> series, we agree to have a synchronize_vqs() config ops to make sure
> callbacks are synchronized.
>
> It uses a global flag and a device wise synchronization mechanism. It
> looks to me we need to switch to
>
> 1) per virtqueue flag
> 2) per virtqueue synchronization
>
> Thanks
>
>
> > + *   not accessed by any functions of virtqueue.
> > + * @enable_reset_vq: enable a reset queue
> > + *   vq: the virtqueue
> > + *   Returns 0 on success or error status
> > + *   If reset_vq is set, then enable_reset_vq must also be set.
> >*/
> >   typedef void vq_callback_t(struct virtqueue *);
> >   struct virtio_config_ops {
> > @@ -100,6 +110,8 @@ struct virtio_config_ops {
> >   int index);
> >   bool (*get_shm_region)(struct virtio_device *vdev,
> >  struct virtio_shm_region *region, u8 id);
> > + int (*reset_vq)(struct virtqueue *vq);
> > + int (*enable_reset_vq)(struct virtqueue *vq);
> >   };
> >
> >   /* If driver didn't advertise the feature, it will never appear. */


___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 03/32] virtio_ring: update the document of the virtqueue_detach_unused_buf for queue reset

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Added documentation for virtqueue_detach_unused_buf, allowing it to be
called on queue reset.

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 



---
  drivers/virtio/virtio_ring.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index b87130c8f312..f1807f6b06a5 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -2127,8 +2127,8 @@ EXPORT_SYMBOL_GPL(virtqueue_enable_cb_delayed);
   * @_vq: the struct virtqueue we're talking about.
   *
   * Returns NULL or the "data" token handed to virtqueue_add_*().
- * This is not valid on an active queue; it is useful only for device
- * shutdown.
+ * This is not valid on an active queue; it is useful for device
+ * shutdown or the reset queue.
   */
  void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
  {



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 04/32] virtio_ring: remove the arg vq of vring_alloc_desc_extra()

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

The parameter vq of vring_alloc_desc_extra() is useless. This patch
removes this parameter.

Subsequent patches will call this function to avoid passing useless
arguments.

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 



---
  drivers/virtio/virtio_ring.c | 7 +++
  1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index f1807f6b06a5..cb6010750a94 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -1636,8 +1636,7 @@ static void *virtqueue_detach_unused_buf_packed(struct 
virtqueue *_vq)
return NULL;
  }
  
-static struct vring_desc_extra *vring_alloc_desc_extra(struct vring_virtqueue *vq,

-  unsigned int num)
+static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num)
  {
struct vring_desc_extra *desc_extra;
unsigned int i;
@@ -1755,7 +1754,7 @@ static struct virtqueue *vring_create_virtqueue_packed(
/* Put everything in free lists. */
vq->free_head = 0;
  
-	vq->packed.desc_extra = vring_alloc_desc_extra(vq, num);

+   vq->packed.desc_extra = vring_alloc_desc_extra(num);
if (!vq->packed.desc_extra)
goto err_desc_extra;
  
@@ -2233,7 +2232,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,

if (!vq->split.desc_state)
goto err_state;
  
-	vq->split.desc_extra = vring_alloc_desc_extra(vq, vring.num);

+   vq->split.desc_extra = vring_alloc_desc_extra(vring.num);
if (!vq->split.desc_extra)
goto err_extra;
  



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 05/32] virtio_ring: extract the logic of freeing vring

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Introduce vring_free() to free the vring of vq.

Subsequent patches will use vring_free() alone.

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 



---
  drivers/virtio/virtio_ring.c | 18 +-
  1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index cb6010750a94..33fddfb907a6 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -2301,14 +2301,10 @@ struct virtqueue *vring_new_virtqueue(unsigned int 
index,
  }
  EXPORT_SYMBOL_GPL(vring_new_virtqueue);
  
-void vring_del_virtqueue(struct virtqueue *_vq)

+static void vring_free(struct virtqueue *_vq)
  {
struct vring_virtqueue *vq = to_vvq(_vq);
  
-	spin_lock(&vq->vq.vdev->vqs_list_lock);

-   list_del(&_vq->list);
-   spin_unlock(&vq->vq.vdev->vqs_list_lock);
-
if (vq->we_own_ring) {
if (vq->packed_ring) {
vring_free_queue(vq->vq.vdev,
@@ -2339,6 +2335,18 @@ void vring_del_virtqueue(struct virtqueue *_vq)
kfree(vq->split.desc_state);
kfree(vq->split.desc_extra);
}
+}
+
+void vring_del_virtqueue(struct virtqueue *_vq)
+{
+   struct vring_virtqueue *vq = to_vvq(_vq);
+
+   spin_lock(&vq->vq.vdev->vqs_list_lock);
+   list_del(&_vq->list);
+   spin_unlock(&vq->vq.vdev->vqs_list_lock);
+
+   vring_free(_vq);
+
kfree(vq);
  }
  EXPORT_SYMBOL_GPL(vring_del_virtqueue);



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 06/32] virtio_ring: split: extract the logic of alloc queue

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, 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 
---
  drivers/virtio/virtio_ring.c | 53 
  1 file changed, 36 insertions(+), 17 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 33fddfb907a6..72d5ae063fa0 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -915,23 +915,15 @@ static void *virtqueue_detach_unused_buf_split(struct 
virtqueue *_vq)
return NULL;
  }
  
-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 void *vring_alloc_queue_split(struct virtio_device *vdev,
+dma_addr_t *dma_addr,
+u32 *n,
+unsigned int vring_align,
+bool weak_barriers,



This is not used in this function.

Thanks



+bool may_reduce_num)
  {
-   struct virtqueue *vq;
void *queue = NULL;
-   dma_addr_t dma_addr;
-   size_t queue_size_in_bytes;
-   struct vring vring;
+   u32 num = *n;
  
  	/* We assume num is a power of 2. */

if (num & (num - 1)) {
@@ -942,7 +934,7 @@ static struct virtqueue *vring_create_virtqueue_split(
/* TODO: allocate each queue chunk individually */
for (; num && vring_size(num, vring_align) > PAGE_SIZE; num /= 2) {
queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
- &dma_addr,
+ dma_addr,
  GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO);
if (queue)
break;
@@ -956,11 +948,38 @@ static struct virtqueue *vring_create_virtqueue_split(
if (!queue) {
/* Try to get a single page. You are my only hope! */
queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
- &dma_addr, GFP_KERNEL|__GFP_ZERO);
+ dma_addr, GFP_KERNEL|__GFP_ZERO);
}
if (!queue)
return NULL;
  
+	*n = num;

+   return queue;
+}
+
+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)
+{
+   size_t queue_size_in_bytes;
+   struct virtqueue *vq;
+   dma_addr_t dma_addr;
+   struct vring vring;
+   void *queue;
+
+   queue = vring_alloc_queue_split(vdev, &dma_addr, &num, vring_align,
+   weak_barriers, may_reduce_num);
+   if (!queue)
+   return NULL;
+
queue_size_in_bytes = vring_size(num, vring_align);
vring_init(&vring, num, queue, vring_align);
  



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 07/32] virtio_ring: split: extract the logic of alloc state and extra

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Separate the logic of creating desc_state, desc_extra, and subsequent
patches will call it independently.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 53 ++--
  1 file changed, 38 insertions(+), 15 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 72d5ae063fa0..6de67439cb57 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -198,6 +198,7 @@ struct vring_virtqueue {
  #endif
  };
  
+static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num);
  
  /*

   * Helpers.
@@ -915,6 +916,33 @@ static void *virtqueue_detach_unused_buf_split(struct 
virtqueue *_vq)
return NULL;
  }
  
+static int vring_alloc_state_extra_split(u32 num,

+struct vring_desc_state_split 
**desc_state,
+struct vring_desc_extra **desc_extra)
+{
+   struct vring_desc_state_split *state;
+   struct vring_desc_extra *extra;
+
+   state = kmalloc_array(num, sizeof(struct vring_desc_state_split), 
GFP_KERNEL);
+   if (!state)
+   goto err_state;
+
+   extra = vring_alloc_desc_extra(num);
+   if (!extra)
+   goto err_extra;
+
+   memset(state, 0, num * sizeof(struct vring_desc_state_split));
+
+   *desc_state = state;
+   *desc_extra = extra;
+   return 0;
+
+err_extra:
+   kfree(state);
+err_state:
+   return -ENOMEM;
+}
+
  static void *vring_alloc_queue_split(struct virtio_device *vdev,
 dma_addr_t *dma_addr,
 u32 *n,
@@ -2196,7 +2224,10 @@ struct virtqueue *__vring_new_virtqueue(unsigned int 
index,
void (*callback)(struct virtqueue *),
const char *name)
  {
+   struct vring_desc_state_split *state;
+   struct vring_desc_extra *extra;
struct vring_virtqueue *vq;
+   int err;
  
  	if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))

return NULL;
@@ -2246,30 +2277,22 @@ struct virtqueue *__vring_new_virtqueue(unsigned int 
index,
vq->split.avail_flags_shadow);
}
  
-	vq->split.desc_state = kmalloc_array(vring.num,

-   sizeof(struct vring_desc_state_split), GFP_KERNEL);
-   if (!vq->split.desc_state)
-   goto err_state;
+   err = vring_alloc_state_extra_split(vring.num, &state, &extra);



Nit: we can pass e.g &vq->split.desc_state here to avoid extra temp 
variable and assignment.


Other looks good.

Thanks



+   if (err) {
+   kfree(vq);
+   return NULL;
+   }
  
-	vq->split.desc_extra = vring_alloc_desc_extra(vring.num);

-   if (!vq->split.desc_extra)
-   goto err_extra;
+   vq->split.desc_state = state;
+   vq->split.desc_extra = extra;
  
  	/* Put everything in free lists. */

vq->free_head = 0;
-   memset(vq->split.desc_state, 0, vring.num *
-   sizeof(struct vring_desc_state_split));
  
  	spin_lock(&vdev->vqs_list_lock);

list_add_tail(&vq->vq.list, &vdev->vqs);
spin_unlock(&vdev->vqs_list_lock);
return &vq->vq;
-
-err_extra:
-   kfree(vq->split.desc_state);
-err_state:
-   kfree(vq);
-   return NULL;
  }
  EXPORT_SYMBOL_GPL(__vring_new_virtqueue);
  



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 08/32] virtio_ring: split: extract the logic of attach vring

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Separate the logic of attach vring, subsequent patches will call it
separately.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 20 ++--
  1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 6de67439cb57..083f2992ba0d 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -916,6 +916,19 @@ static void *virtqueue_detach_unused_buf_split(struct 
virtqueue *_vq)
return NULL;
  }
  
+static void vring_virtqueue_attach_split(struct vring_virtqueue *vq,

+struct vring vring,
+struct vring_desc_state_split 
*desc_state,
+struct vring_desc_extra *desc_extra)
+{
+   vq->split.vring = vring;
+   vq->split.queue_dma_addr = 0;
+   vq->split.queue_size_in_bytes = 0;



Any reason to add the above two assignment in attach? It seems belong to 
free or reset.


Thanks



+
+   vq->split.desc_state = desc_state;
+   vq->split.desc_extra = desc_extra;
+}
+
  static int vring_alloc_state_extra_split(u32 num,
 struct vring_desc_state_split 
**desc_state,
 struct vring_desc_extra **desc_extra)
@@ -2262,10 +2275,6 @@ struct virtqueue *__vring_new_virtqueue(unsigned int 
index,
if (virtio_has_feature(vdev, VIRTIO_F_ORDER_PLATFORM))
vq->weak_barriers = false;
  
-	vq->split.queue_dma_addr = 0;

-   vq->split.queue_size_in_bytes = 0;
-
-   vq->split.vring = vring;
vq->split.avail_flags_shadow = 0;
vq->split.avail_idx_shadow = 0;
  
@@ -2283,8 +2292,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,

return NULL;
}
  
-	vq->split.desc_state = state;

-   vq->split.desc_extra = extra;
+   vring_virtqueue_attach_split(vq, vring, state, extra);
  
  	/* Put everything in free lists. */

vq->free_head = 0;



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 09/32] virtio_ring: split: extract the logic of vq init

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Separate the logic of initializing vq, and subsequent patches will call
it separately.

The feature of this part is that it does not depend on the information
passed by the upper layer and can be called repeatedly.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 68 
  1 file changed, 38 insertions(+), 30 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 083f2992ba0d..874f878087a3 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -916,6 +916,43 @@ static void *virtqueue_detach_unused_buf_split(struct 
virtqueue *_vq)
return NULL;
  }
  
+static void vring_virtqueue_init_split(struct vring_virtqueue *vq,

+  struct virtio_device *vdev,
+  bool own_ring)
+{
+   vq->packed_ring = false;
+   vq->vq.num_free = vq->split.vring.num;
+   vq->we_own_ring = own_ring;
+   vq->broken = false;
+   vq->last_used_idx = 0;
+   vq->event_triggered = false;
+   vq->num_added = 0;
+   vq->use_dma_api = vring_use_dma_api(vdev);
+#ifdef DEBUG
+   vq->in_use = false;
+   vq->last_add_time_valid = false;
+#endif
+
+   vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
+
+   if (virtio_has_feature(vdev, VIRTIO_F_ORDER_PLATFORM))
+   vq->weak_barriers = false;
+
+   vq->split.avail_flags_shadow = 0;
+   vq->split.avail_idx_shadow = 0;
+
+   /* No callback?  Tell other side not to bother us. */
+   if (!vq->vq.callback) {
+   vq->split.avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
+   if (!vq->event)
+   vq->split.vring.avail->flags = cpu_to_virtio16(vdev,
+   vq->split.avail_flags_shadow);
+   }
+
+   /* Put everything in free lists. */
+   vq->free_head = 0;



It's not clear what kind of initialization that we want to do here. E.g 
it mixes split specific setups with some general setups which is kind of 
duplication of vring_virtqueue_init_packed().


I wonder if it's better to only do split specific setups here and have a 
common helper to do the setup that is irrelevant to ring layout.


Thanks



+}
+
  static void vring_virtqueue_attach_split(struct vring_virtqueue *vq,
 struct vring vring,
 struct vring_desc_state_split 
*desc_state,
@@ -2249,42 +2286,15 @@ struct virtqueue *__vring_new_virtqueue(unsigned int 
index,
if (!vq)
return NULL;
  
-	vq->packed_ring = false;

vq->vq.callback = callback;
vq->vq.vdev = vdev;
vq->vq.name = name;
-   vq->vq.num_free = vring.num;
vq->vq.index = index;
-   vq->we_own_ring = false;
vq->notify = notify;
vq->weak_barriers = weak_barriers;
-   vq->broken = false;
-   vq->last_used_idx = 0;
-   vq->event_triggered = false;
-   vq->num_added = 0;
-   vq->use_dma_api = vring_use_dma_api(vdev);
-#ifdef DEBUG
-   vq->in_use = false;
-   vq->last_add_time_valid = false;
-#endif
  
  	vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&

!context;
-   vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
-
-   if (virtio_has_feature(vdev, VIRTIO_F_ORDER_PLATFORM))
-   vq->weak_barriers = false;
-
-   vq->split.avail_flags_shadow = 0;
-   vq->split.avail_idx_shadow = 0;
-
-   /* No callback?  Tell other side not to bother us. */
-   if (!callback) {
-   vq->split.avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
-   if (!vq->event)
-   vq->split.vring.avail->flags = cpu_to_virtio16(vdev,
-   vq->split.avail_flags_shadow);
-   }
  
  	err = vring_alloc_state_extra_split(vring.num, &state, &extra);

if (err) {
@@ -2293,9 +2303,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int 
index,
}
  
  	vring_virtqueue_attach_split(vq, vring, state, extra);

-
-   /* Put everything in free lists. */
-   vq->free_head = 0;
+   vring_virtqueue_init_split(vq, vdev, false);
  
  	spin_lock(&vdev->vqs_list_lock);

list_add_tail(&vq->vq.list, &vdev->vqs);



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 10/32] virtio_ring: split: introduce virtqueue_reinit_split()

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Introduce a function to initialize vq without allocating new ring,
desc_state, desc_extra.

Subsequent patches will call this function after reset vq to
reinitialize vq.

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 



---
  drivers/virtio/virtio_ring.c | 19 +++
  1 file changed, 19 insertions(+)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 874f878087a3..3dc6ace2ba7a 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -953,6 +953,25 @@ static void vring_virtqueue_init_split(struct 
vring_virtqueue *vq,
vq->free_head = 0;
  }
  
+static void virtqueue_reinit_split(struct vring_virtqueue *vq)

+{
+   struct virtio_device *vdev = vq->vq.vdev;
+   int size, i;
+
+   memset(vq->split.vring.desc, 0, vq->split.queue_size_in_bytes);
+
+   size = sizeof(struct vring_desc_state_split) * vq->split.vring.num;
+   memset(vq->split.desc_state, 0, size);
+
+   size = sizeof(struct vring_desc_extra) * vq->split.vring.num;
+   memset(vq->split.desc_extra, 0, size);
+
+   for (i = 0; i < vq->split.vring.num - 1; i++)
+   vq->split.desc_extra[i].next = i + 1;
+
+   vring_virtqueue_init_split(vq, vdev, true);
+}
+
  static void vring_virtqueue_attach_split(struct vring_virtqueue *vq,
 struct vring vring,
 struct vring_desc_state_split 
*desc_state,



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 11/32] virtio_ring: split: introduce virtqueue_resize_split()

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

virtio ring split supports resize.

Only after the new vring is successfully allocated based on the new num,
we will release the old vring. In any case, an error is returned,
indicating that the vring still points to the old vring.

In the case of an error, the caller must
re-initialize(virtqueue_reinit_split()) the virtqueue to ensure that the
vring can be used.

In addition, vring_align, may_reduce_num are necessary for reallocating
vring, so they are retained for creating vq.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 47 
  1 file changed, 47 insertions(+)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 3dc6ace2ba7a..33864134a744 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -139,6 +139,12 @@ struct vring_virtqueue {
/* 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;
} split;
  
  		/* Available for packed ring */

@@ -199,6 +205,7 @@ struct vring_virtqueue {
  };
  
  static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num);

+static void vring_free(struct virtqueue *_vq);
  
  /*

   * Helpers.
@@ -1088,6 +1095,8 @@ static struct virtqueue *vring_create_virtqueue_split(
return NULL;
}
  
+	to_vvq(vq)->split.vring_align = vring_align;

+   to_vvq(vq)->split.may_reduce_num = may_reduce_num;



It looks to me the above should belong to patch 6.



to_vvq(vq)->split.queue_dma_addr = dma_addr;
to_vvq(vq)->split.queue_size_in_bytes = queue_size_in_bytes;
to_vvq(vq)->we_own_ring = true;
@@ -1095,6 +1104,44 @@ static struct virtqueue *vring_create_virtqueue_split(
return vq;
  }
  
+static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)

+{
+   struct vring_virtqueue *vq = to_vvq(_vq);
+   struct virtio_device *vdev = _vq->vdev;
+   struct vring_desc_state_split *state;
+   struct vring_desc_extra *extra;
+   size_t queue_size_in_bytes;
+   dma_addr_t dma_addr;
+   struct vring vring;
+   int err = -ENOMEM;
+   void *queue;
+
+   queue = vring_alloc_queue_split(vdev, &dma_addr, &num,
+   vq->split.vring_align,
+   vq->weak_barriers,
+   vq->split.may_reduce_num);
+   if (!queue)
+   return -ENOMEM;
+
+   queue_size_in_bytes = vring_size(num, vq->split.vring_align);
+
+   err = vring_alloc_state_extra_split(num, &state, &extra);
+   if (err) {
+   vring_free_queue(vdev, queue_size_in_bytes, queue, dma_addr);
+   return -ENOMEM;
+   }
+
+   vring_free(&vq->vq);
+
+   vring_init(&vring, num, queue, vq->split.vring_align);
+   vring_virtqueue_attach_split(vq, vring, state, extra);
+   vq->split.queue_dma_addr = dma_addr;
+   vq->split.queue_size_in_bytes = queue_size_in_bytes;



I wonder if it's better to move the above assignments to 
vring_virtqueue_attach_split().


Other looks good.

Thanks



+
+   vring_virtqueue_init_split(vq, vdev, true);
+   return 0;
+}
+
  
  /*

   * Packed ring specific functions - *_packed().



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 12/32] virtio_ring: packed: extract the logic of alloc queue

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Separate the logic of packed to create vring queue.

For the convenience of passing parameters, add a structure
vring_packed.

This feature is required for subsequent virtuqueue reset vring.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 70 
  1 file changed, 56 insertions(+), 14 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 33864134a744..ea451ae2aaef 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -1817,19 +1817,17 @@ static struct vring_desc_extra 
*vring_alloc_desc_extra(unsigned int num)
return desc_extra;
  }
  
-static struct virtqueue *vring_create_virtqueue_packed(

-   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_packed(struct virtio_device *vdev,
+   u32 num,
+   struct vring_packed_desc **_ring,
+   struct vring_packed_desc_event **_driver,
+   struct vring_packed_desc_event **_device,
+   dma_addr_t *_ring_dma_addr,
+   dma_addr_t *_driver_event_dma_addr,
+   dma_addr_t *_device_event_dma_addr,
+   size_t *_ring_size_in_bytes,
+   size_t *_event_size_in_bytes)
  {
-   struct vring_virtqueue *vq;
struct vring_packed_desc *ring;
struct vring_packed_desc_event *driver, *device;
dma_addr_t ring_dma_addr, driver_event_dma_addr, device_event_dma_addr;
@@ -1857,6 +1855,52 @@ static struct virtqueue *vring_create_virtqueue_packed(
if (!device)
goto err_device;
  
+	*_ring   = ring;

+   *_driver = driver;
+   *_device = device;
+   *_ring_dma_addr  = ring_dma_addr;
+   *_driver_event_dma_addr  = driver_event_dma_addr;
+   *_device_event_dma_addr  = device_event_dma_addr;
+   *_ring_size_in_bytes = ring_size_in_bytes;
+   *_event_size_in_bytes= event_size_in_bytes;



I wonder if we can simply factor out split and packed from struct 
vring_virtqueue:


struct vring_virtqueue {
    union {
        struct {} split;
        struct {} packed;
    };
};

to

struct vring_virtqueue_split {};
struct vring_virtqueue_packed {};

Then we can do things like:

vring_create_virtqueue_packed(struct virtio_device *vdev, u32 num, 
struct vring_virtqueue_packed *packed);


and

vring_vritqueue_attach_packed(struct vring_virtqueue *vq, struct 
vring_virtqueue_packed packed);


Thanks



+
+   return 0;
+
+err_device:
+   vring_free_queue(vdev, event_size_in_bytes, driver, 
driver_event_dma_addr);
+
+err_driver:
+   vring_free_queue(vdev, ring_size_in_bytes, ring, ring_dma_addr);
+
+err_ring:
+   return -ENOMEM;
+}
+
+static struct virtqueue *vring_create_virtqueue_packed(
+   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)
+{
+   dma_addr_t ring_dma_addr, driver_event_dma_addr, device_event_dma_addr;
+   struct vring_packed_desc_event *driver, *device;
+   size_t ring_size_in_bytes, event_size_in_bytes;
+   struct vring_packed_desc *ring;
+   struct vring_virtqueue *vq;
+
+   if (vring_alloc_queue_packed(vdev, num, &ring, &driver, &device,
+&ring_dma_addr, &driver_event_dma_addr,
+&device_event_dma_addr,
+&ring_size_in_bytes,
+&event_size_in_bytes))
+   goto err_ring;
+
vq = kmalloc(sizeof(*vq), GFP_KERNEL);
if (!vq)
goto err_vq;
@@ -1939,9 +1983,7 @@ static struct virtqueue *vring_create_virtqueue_packed(
kfree(vq);
  err_vq:
vring_free_queue(vdev, event_size_in_bytes, device, 
device_event_dma_addr);
-err_device:
vring_free_queue(vdev, event_size_in_bytes, driver, 
driver_event_dma_addr);
-err_driver:
vring_free_queue(vdev, ring_size_in_bytes, ring, ring_dma_addr);
  err_ring:
return NULL;



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 18/32] virtio_ring: introduce virtqueue_resize()

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Introduce virtqueue_resize() to implement the resize of vring.
Based on these, the driver can dynamically adjust the size of the vring.
For example: ethtool -G.

virtqueue_resize() implements resize based on the vq reset function. In
case of failure to allocate a new vring, it will give up resize and use
the original vring.

During this process, if the re-enable reset vq fails, the vq can no
longer be used. Although the probability of this situation is not high.

The parameter recycle is used to recycle the buffer that is no longer
used.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_ring.c | 69 
  include/linux/virtio.h   |  3 ++
  2 files changed, 72 insertions(+)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 06f66b15c86c..6250e19fc5bf 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -2554,6 +2554,75 @@ struct virtqueue *vring_create_virtqueue(
  }
  EXPORT_SYMBOL_GPL(vring_create_virtqueue);
  
+/**

+ * virtqueue_resize - resize the vring of vq
+ * @_vq: the struct virtqueue we're talking about.
+ * @num: new ring num
+ * @recycle: callback for recycle the useless buffer
+ *
+ * When it is really necessary to create a new vring, it will set the current 
vq
+ * into the reset state. Then call the passed callback to recycle the buffer
+ * that is no longer used. Only after the new vring is successfully created, 
the
+ * old vring will be released.
+ *
+ * Caller must ensure we don't call this with other virtqueue operations
+ * at the same time (except where noted).
+ *
+ * Returns zero or a negative error.



Should we document that the virtqueue is kept unchanged (still 
available) on (specific) failure?




+ */
+int virtqueue_resize(struct virtqueue *_vq, u32 num,
+void (*recycle)(struct virtqueue *vq, void *buf))
+{
+   struct vring_virtqueue *vq = to_vvq(_vq);
+   struct virtio_device *vdev = vq->vq.vdev;
+   bool packed;
+   void *buf;
+   int err;
+
+   if (!vq->we_own_ring)
+   return -EINVAL;
+
+   if (num > vq->vq.num_max)
+   return -E2BIG;
+
+   if (!num)
+   return -EINVAL;
+
+   packed = virtio_has_feature(vdev, VIRTIO_F_RING_PACKED) ? true : false;
+
+   if ((packed ? vq->packed.vring.num : vq->split.vring.num) == num)
+   return 0;
+
+   if (!vdev->config->reset_vq)
+   return -ENOENT;
+
+   if (!vdev->config->enable_reset_vq)
+   return -ENOENT;
+
+   err = vdev->config->reset_vq(_vq);
+   if (err)
+   return err;
+
+   while ((buf = virtqueue_detach_unused_buf(_vq)) != NULL)
+   recycle(_vq, buf);
+
+   if (packed) {
+   err = virtqueue_resize_packed(_vq, num);
+   if (err)
+   virtqueue_reinit_packed(vq);



Calling reinit here seems a little bit odd, it looks more like a reset 
of the virtqueue. Consider we may re-use virtqueue reset for more 
purpose, I wonder if we need a helper like:


virtqueue_resize() {
    vdev->config->reset_vq(_vq);
    if (packed)
        virtqueue_reinit_packed(_vq)
    else
    virtqueue_reinit_split(_vq)
}

Thanks



+   } else {
+   err = virtqueue_resize_split(_vq, num);
+   if (err)
+   virtqueue_reinit_split(vq);
+   }
+
+   if (vdev->config->enable_reset_vq(_vq))
+   return -EBUSY;
+
+   return err;
+}
+EXPORT_SYMBOL_GPL(virtqueue_resize);
+
  /* Only available for split ring */
  struct virtqueue *vring_new_virtqueue(unsigned int index,
  unsigned int num,
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index d59adc4be068..c86ff02e0ca0 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -91,6 +91,9 @@ dma_addr_t virtqueue_get_desc_addr(struct virtqueue *vq);
  dma_addr_t virtqueue_get_avail_addr(struct virtqueue *vq);
  dma_addr_t virtqueue_get_used_addr(struct virtqueue *vq);
  
+int virtqueue_resize(struct virtqueue *vq, u32 num,

+void (*recycle)(struct virtqueue *vq, void *buf));
+
  /**
   * virtio_device - representation of a device using virtio
   * @index: unique position on the virtio bus



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 21/32] virtio_pci: queue_reset: update struct virtio_pci_common_cfg and option functions

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Add queue_reset in virtio_pci_common_cfg, and add related operation
functions.

For not breaks uABI, add a new struct virtio_pci_common_cfg_reset.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_pci_modern_dev.c | 36 ++
  include/linux/virtio_pci_modern.h  |  2 ++
  include/uapi/linux/virtio_pci.h|  7 +
  3 files changed, 45 insertions(+)

diff --git a/drivers/virtio/virtio_pci_modern_dev.c 
b/drivers/virtio/virtio_pci_modern_dev.c
index e8b3ff2b9fbc..8c74b00bc511 100644
--- a/drivers/virtio/virtio_pci_modern_dev.c
+++ b/drivers/virtio/virtio_pci_modern_dev.c
@@ -3,6 +3,7 @@
  #include 
  #include 
  #include 
+#include 
  
  /*

   * vp_modern_map_capability - map a part of virtio pci capability
@@ -463,6 +464,41 @@ void vp_modern_set_status(struct virtio_pci_modern_device 
*mdev,
  }
  EXPORT_SYMBOL_GPL(vp_modern_set_status);
  
+/*

+ * vp_modern_get_queue_reset - get the queue reset status
+ * @mdev: the modern virtio-pci device
+ * @index: queue index
+ */
+int vp_modern_get_queue_reset(struct virtio_pci_modern_device *mdev, u16 index)
+{
+   struct virtio_pci_common_cfg_reset __iomem *cfg;
+
+   cfg = (struct virtio_pci_common_cfg_reset __iomem *)mdev->common;
+
+   vp_iowrite16(index, &cfg->cfg.queue_select);
+   return vp_ioread16(&cfg->queue_reset);
+}
+EXPORT_SYMBOL_GPL(vp_modern_get_queue_reset);
+
+/*
+ * vp_modern_set_queue_reset - reset the queue
+ * @mdev: the modern virtio-pci device
+ * @index: queue index
+ */
+void vp_modern_set_queue_reset(struct virtio_pci_modern_device *mdev, u16 
index)
+{
+   struct virtio_pci_common_cfg_reset __iomem *cfg;
+
+   cfg = (struct virtio_pci_common_cfg_reset __iomem *)mdev->common;
+
+   vp_iowrite16(index, &cfg->cfg.queue_select);
+   vp_iowrite16(1, &cfg->queue_reset);
+
+   while (vp_ioread16(&cfg->queue_reset) != 1)
+   msleep(1);
+}
+EXPORT_SYMBOL_GPL(vp_modern_set_queue_reset);
+
  /*
   * vp_modern_queue_vector - set the MSIX vector for a specific virtqueue
   * @mdev: the modern virtio-pci device
diff --git a/include/linux/virtio_pci_modern.h 
b/include/linux/virtio_pci_modern.h
index eb2bd9b4077d..cc4154dd7b28 100644
--- a/include/linux/virtio_pci_modern.h
+++ b/include/linux/virtio_pci_modern.h
@@ -106,4 +106,6 @@ void __iomem * vp_modern_map_vq_notify(struct 
virtio_pci_modern_device *mdev,
   u16 index, resource_size_t *pa);
  int vp_modern_probe(struct virtio_pci_modern_device *mdev);
  void vp_modern_remove(struct virtio_pci_modern_device *mdev);
+int vp_modern_get_queue_reset(struct virtio_pci_modern_device *mdev, u16 
index);
+void vp_modern_set_queue_reset(struct virtio_pci_modern_device *mdev, u16 
index);
  #endif
diff --git a/include/uapi/linux/virtio_pci.h b/include/uapi/linux/virtio_pci.h
index 22bec9bd0dfc..d9462efd6ce8 100644
--- a/include/uapi/linux/virtio_pci.h
+++ b/include/uapi/linux/virtio_pci.h
@@ -173,6 +173,13 @@ struct virtio_pci_common_cfg_notify {
__le16 padding;
  };
  
+struct virtio_pci_common_cfg_reset {

+   struct virtio_pci_common_cfg cfg;
+
+   __le16 queue_notify_data;   /* read-write */
+   __le16 queue_reset; /* read-write */
+};



I prefer to use a separate patch for the uAPI change.

Other looks good.

Thanks



+
  /* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
  struct virtio_pci_cfg_cap {
struct virtio_pci_cap cap;



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 22/32] virtio_pci: queue_reset: extract the logic of active vq for modern pci

2022-04-11 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Introduce vp_active_vq() to configure vring to backend after vq attach
vring. And configure vq vector if necessary.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_pci_modern.c | 46 ++
  1 file changed, 28 insertions(+), 18 deletions(-)

diff --git a/drivers/virtio/virtio_pci_modern.c 
b/drivers/virtio/virtio_pci_modern.c
index 86d301f272b8..49a4493732cf 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -176,6 +176,29 @@ static void vp_reset(struct virtio_device *vdev)
vp_disable_cbs(vdev);
  }
  
+static int vp_active_vq(struct virtqueue *vq, u16 msix_vec)

+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+   unsigned long index;
+
+   index = vq->index;
+
+   /* activate the queue */
+   vp_modern_set_queue_size(mdev, index, virtqueue_get_vring_size(vq));
+   vp_modern_queue_address(mdev, index, virtqueue_get_desc_addr(vq),
+   virtqueue_get_avail_addr(vq),
+   virtqueue_get_used_addr(vq));
+
+   if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
+   msix_vec = vp_modern_queue_vector(mdev, index, msix_vec);
+   if (msix_vec == VIRTIO_MSI_NO_VECTOR)
+   return -EBUSY;
+   }
+
+   return 0;
+}
+
  static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector)
  {
return vp_modern_config_vector(&vp_dev->mdev, vector);
@@ -220,32 +243,19 @@ static struct virtqueue *setup_vq(struct 
virtio_pci_device *vp_dev,
  
  	vq->num_max = num;
  
-	/* activate the queue */

-   vp_modern_set_queue_size(mdev, index, virtqueue_get_vring_size(vq));
-   vp_modern_queue_address(mdev, index, virtqueue_get_desc_addr(vq),
-   virtqueue_get_avail_addr(vq),
-   virtqueue_get_used_addr(vq));
+   err = vp_active_vq(vq, msix_vec);
+   if (err)
+   goto err;
  
  	vq->priv = (void __force *)vp_modern_map_vq_notify(mdev, index, NULL);

if (!vq->priv) {
err = -ENOMEM;
-   goto err_map_notify;
-   }
-
-   if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
-   msix_vec = vp_modern_queue_vector(mdev, index, msix_vec);
-   if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
-   err = -EBUSY;
-   goto err_assign_vector;
-   }
+   goto err;
}
  
  	return vq;
  
-err_assign_vector:

-   if (!mdev->notify_base)
-   pci_iounmap(mdev->pci_dev, (void __iomem __force *)vq->priv);



We need keep this or anything I missed?

Thanks



-err_map_notify:
+err:
vring_del_virtqueue(vq);
return ERR_PTR(err);
  }



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 23/32] virtio_pci: queue_reset: support VIRTIO_F_RING_RESET

2022-04-12 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

This patch implements virtio pci support for QUEUE RESET.

Performing reset on a queue is divided into these steps:

  1. notify the device to reset the queue
  2. recycle the buffer submitted
  3. reset the vring (may re-alloc)
  4. mmap vring to device, and enable the queue

This patch implements virtio_reset_vq(), virtio_enable_resetq() in the
pci scenario.

Signed-off-by: Xuan Zhuo 
---
  drivers/virtio/virtio_pci_common.c |  8 +--
  drivers/virtio/virtio_pci_modern.c | 84 ++
  drivers/virtio/virtio_ring.c   |  2 +
  include/linux/virtio.h |  1 +
  4 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/drivers/virtio/virtio_pci_common.c 
b/drivers/virtio/virtio_pci_common.c
index fdbde1db5ec5..863d3a8a0956 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -248,9 +248,11 @@ static void vp_del_vq(struct virtqueue *vq)
struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
unsigned long flags;
  
-	spin_lock_irqsave(&vp_dev->lock, flags);

-   list_del(&info->node);
-   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   if (!vq->reset) {



On which condition that we may hit this path?



+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_del(&info->node);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   }
  
  	vp_dev->del_vq(info);

kfree(info);
diff --git a/drivers/virtio/virtio_pci_modern.c 
b/drivers/virtio/virtio_pci_modern.c
index 49a4493732cf..cb5d38f1c9c8 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -34,6 +34,9 @@ static void vp_transport_features(struct virtio_device *vdev, 
u64 features)
if ((features & BIT_ULL(VIRTIO_F_SR_IOV)) &&
pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV))
__virtio_set_bit(vdev, VIRTIO_F_SR_IOV);
+
+   if (features & BIT_ULL(VIRTIO_F_RING_RESET))
+   __virtio_set_bit(vdev, VIRTIO_F_RING_RESET);
  }
  
  /* virtio config->finalize_features() implementation */

@@ -199,6 +202,83 @@ static int vp_active_vq(struct virtqueue *vq, u16 msix_vec)
return 0;
  }
  
+static int vp_modern_reset_vq(struct virtqueue *vq)

+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+   struct virtio_pci_vq_info *info;
+   unsigned long flags;
+
+   if (!virtio_has_feature(vq->vdev, VIRTIO_F_RING_RESET))
+   return -ENOENT;
+
+   vp_modern_set_queue_reset(mdev, vq->index);
+
+   info = vp_dev->vqs[vq->index];
+
+   /* delete vq from irq handler */
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_del(&info->node);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+
+   INIT_LIST_HEAD(&info->node);
+
+   /* For the case where vq has an exclusive irq, to prevent the irq from
+* being received again and the pending irq, call disable_irq().
+*
+* In the scenario based on shared interrupts, vq will be searched from
+* the queue virtqueues. Since the previous list_del() has been deleted
+* from the queue, it is impossible for vq to be called in this case.
+* There is no need to close the corresponding interrupt.
+*/
+   if (vp_dev->per_vq_vectors && info->msix_vector != VIRTIO_MSI_NO_VECTOR)
+   disable_irq(pci_irq_vector(vp_dev->pci_dev, info->msix_vector));



See the previous discussion and the revert of the first try to harden 
the interrupt. We probably can't use disable_irq() since it conflicts 
with the affinity managed IRQ that is used by some drivers.


We need to use synchonize_irq() and per virtqueue flag instead. As 
mentioned in previous patches, this could be done on top of my rework on 
the IRQ hardening .




+
+   vq->reset = true;
+
+   return 0;
+}
+
+static int vp_modern_enable_reset_vq(struct virtqueue *vq)
+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+   struct virtio_pci_vq_info *info;
+   unsigned long flags, index;
+   int err;
+
+   if (!vq->reset)
+   return -EBUSY;
+
+   index = vq->index;
+   info = vp_dev->vqs[index];
+
+   /* check queue reset status */
+   if (vp_modern_get_queue_reset(mdev, index) != 1)
+   return -EBUSY;
+
+   err = vp_active_vq(vq, info->msix_vector);
+   if (err)
+   return err;
+
+   if (vq->callback) {
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_add(&info->node, &vp_dev->virtqueues);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   } else {
+   INIT_LIST_HEAD(&info->node);
+   }
+
+   vp_modern_set_queue_enable(&vp_dev->mdev, index, true);
+
+   if (

Re: [PATCH v9 24/32] virtio: find_vqs() add arg sizes

2022-04-12 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

find_vqs() adds a new parameter sizes to specify the size of each vq
vring.

0 means use the maximum size supported by the backend.



Does this mean driver still need to prepare a array of 0 or it can 
simply pass NULL to find_vqs()?


Thanks




In the split scenario, the meaning of size is the largest size, because
it may be limited by memory, the virtio core will try a smaller size.
And the size is power of 2.

Signed-off-by: Xuan Zhuo 
Acked-by: Hans de Goede 
Reviewed-by: Mathieu Poirier 
---
  arch/um/drivers/virtio_uml.c |  2 +-
  drivers/platform/mellanox/mlxbf-tmfifo.c |  1 +
  drivers/remoteproc/remoteproc_virtio.c   |  1 +
  drivers/s390/virtio/virtio_ccw.c |  1 +
  drivers/virtio/virtio_mmio.c |  1 +
  drivers/virtio/virtio_pci_common.c   |  2 +-
  drivers/virtio/virtio_pci_common.h   |  2 +-
  drivers/virtio/virtio_pci_modern.c   |  7 +--
  drivers/virtio/virtio_vdpa.c |  1 +
  include/linux/virtio_config.h| 14 +-
  10 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
index 904993d15a85..6af98d130840 100644
--- a/arch/um/drivers/virtio_uml.c
+++ b/arch/um/drivers/virtio_uml.c
@@ -998,7 +998,7 @@ static struct virtqueue *vu_setup_vq(struct virtio_device 
*vdev,
  
  static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,

   struct virtqueue *vqs[], vq_callback_t *callbacks[],
-  const char * const names[], const bool *ctx,
+  const char * const names[], u32 sizes[], const bool *ctx,
   struct irq_affinity *desc)
  {
struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c 
b/drivers/platform/mellanox/mlxbf-tmfifo.c
index 1ae3c56b66b0..8be13d416f48 100644
--- a/drivers/platform/mellanox/mlxbf-tmfifo.c
+++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
@@ -928,6 +928,7 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct 
virtio_device *vdev,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
const char * const names[],
+   u32 sizes[],
const bool *ctx,
struct irq_affinity *desc)
  {
diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index 7611755d0ae2..baad31c9da45 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -158,6 +158,7 @@ static int rproc_virtio_find_vqs(struct virtio_device 
*vdev, unsigned int nvqs,
 struct virtqueue *vqs[],
 vq_callback_t *callbacks[],
 const char * const names[],
+u32 sizes[],
 const bool * ctx,
 struct irq_affinity *desc)
  {
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index 468da60b56c5..f0c814a54e78 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -634,6 +634,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, 
unsigned nvqs,
   struct virtqueue *vqs[],
   vq_callback_t *callbacks[],
   const char * const names[],
+  u32 sizes[],
   const bool *ctx,
   struct irq_affinity *desc)
  {
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index a41abc8051b9..9d5a674bdeec 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -461,6 +461,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned 
nvqs,
   struct virtqueue *vqs[],
   vq_callback_t *callbacks[],
   const char * const names[],
+  u32 sizes[],
   const bool *ctx,
   struct irq_affinity *desc)
  {
diff --git a/drivers/virtio/virtio_pci_common.c 
b/drivers/virtio/virtio_pci_common.c
index 863d3a8a0956..826ea2e35d54 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -427,7 +427,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, 
unsigned nvqs,
  /* the config->find_vqs() implementation */
  int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], vq_callback_t *callbacks[],
-   const char * const names[], const bool *ctx,
+   const char * const names[], u32 sizes[], const bool *ctx,
struct irq_affinity *d

Re: [PATCH v9 25/32] virtio_pci: support the arg sizes of find_vqs()

2022-04-12 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Virtio PCI supports new parameter sizes of find_vqs().

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 



---
  drivers/virtio/virtio_pci_common.c | 18 ++
  drivers/virtio/virtio_pci_common.h |  1 +
  drivers/virtio/virtio_pci_legacy.c |  6 +-
  drivers/virtio/virtio_pci_modern.c | 10 +++---
  4 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/drivers/virtio/virtio_pci_common.c 
b/drivers/virtio/virtio_pci_common.c
index 826ea2e35d54..23976c61583f 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -208,6 +208,7 @@ static int vp_request_msix_vectors(struct virtio_device 
*vdev, int nvectors,
  static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned 
index,
 void (*callback)(struct virtqueue *vq),
 const char *name,
+u32 size,
 bool ctx,
 u16 msix_vec)
  {
@@ -220,7 +221,7 @@ static struct virtqueue *vp_setup_vq(struct virtio_device 
*vdev, unsigned index,
if (!info)
return ERR_PTR(-ENOMEM);
  
-	vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, ctx,

+   vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, size, ctx,
  msix_vec);
if (IS_ERR(vq))
goto out_info;
@@ -314,7 +315,7 @@ void vp_del_vqs(struct virtio_device *vdev)
  
  static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs,

struct virtqueue *vqs[], vq_callback_t *callbacks[],
-   const char * const names[], bool per_vq_vectors,
+   const char * const names[], u32 sizes[], bool per_vq_vectors,
const bool *ctx,
struct irq_affinity *desc)
  {
@@ -357,8 +358,8 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, 
unsigned nvqs,
else
msix_vec = VP_MSIX_VQ_VECTOR;
vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
-ctx ? ctx[i] : false,
-msix_vec);
+sizes ? sizes[i] : 0,
+ctx ? ctx[i] : false, msix_vec);
if (IS_ERR(vqs[i])) {
err = PTR_ERR(vqs[i]);
goto error_find;
@@ -388,7 +389,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, 
unsigned nvqs,
  
  static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs,

struct virtqueue *vqs[], vq_callback_t *callbacks[],
-   const char * const names[], const bool *ctx)
+   const char * const names[], u32 sizes[], const bool *ctx)
  {
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
int i, err, queue_idx = 0;
@@ -410,6 +411,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, 
unsigned nvqs,
continue;
}
vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
+sizes ? sizes[i] : 0,
 ctx ? ctx[i] : false,
 VIRTIO_MSI_NO_VECTOR);
if (IS_ERR(vqs[i])) {
@@ -433,15 +435,15 @@ int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
int err;
  
  	/* Try MSI-X with one vector per queue. */

-   err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true, ctx, 
desc);
+   err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, sizes, true, 
ctx, desc);
if (!err)
return 0;
/* Fallback: MSI-X with one vector for config, one shared for queues. */
-   err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, 
desc);
+   err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, sizes, false, 
ctx, desc);
if (!err)
return 0;
/* Finally fall back to regular interrupts. */
-   return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, ctx);
+   return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, sizes, ctx);
  }
  
  const char *vp_bus_name(struct virtio_device *vdev)

diff --git a/drivers/virtio/virtio_pci_common.h 
b/drivers/virtio/virtio_pci_common.h
index 859eed559e10..fbf5a6d4b164 100644
--- a/drivers/virtio/virtio_pci_common.h
+++ b/drivers/virtio/virtio_pci_common.h
@@ -81,6 +81,7 @@ struct virtio_pci_device {
  unsigned idx,
  void (*callback)(struct virtqueue *vq),
  const char *name,
+ u32 size,
  bool ctx,
  u16 msix_vec);
void (*

Re: [PATCH v9 26/32] virtio_mmio: support the arg sizes of find_vqs()

2022-04-12 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Virtio MMIO support the new parameter sizes of find_vqs().

Signed-off-by: Xuan Zhuo 
---



Acked-by: Jason Wang 



  drivers/virtio/virtio_mmio.c | 8 ++--
  1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index 9d5a674bdeec..51cf51764a92 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -347,7 +347,7 @@ static void vm_del_vqs(struct virtio_device *vdev)
  
  static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,

  void (*callback)(struct virtqueue *vq),
- const char *name, bool ctx)
+ const char *name, u32 size, bool ctx)
  {
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
struct virtio_mmio_vq_info *info;
@@ -382,8 +382,11 @@ static struct virtqueue *vm_setup_vq(struct virtio_device 
*vdev, unsigned index,
goto error_new_virtqueue;
}
  
+	if (!size || size > num)

+   size = num;
+
/* Create the vring */
-   vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, vdev,
+   vq = vring_create_virtqueue(index, size, VIRTIO_MMIO_VRING_ALIGN, vdev,
 true, true, ctx, vm_notify, callback, name);
if (!vq) {
err = -ENOMEM;
@@ -484,6 +487,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned 
nvqs,
}
  
  		vqs[i] = vm_setup_vq(vdev, queue_idx++, callbacks[i], names[i],

+sizes ? sizes[i] : 0,
 ctx ? ctx[i] : false);
if (IS_ERR(vqs[i])) {
vm_del_vqs(vdev);



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 27/32] virtio: add helper virtio_find_vqs_ctx_size()

2022-04-12 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Introduce helper virtio_find_vqs_ctx_size() to call find_vqs and specify
the maximum size of each vq ring.

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 



---
  include/linux/virtio_config.h | 12 
  1 file changed, 12 insertions(+)

diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 0f7def7ddfd2..22e29c926946 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -235,6 +235,18 @@ int virtio_find_vqs_ctx(struct virtio_device *vdev, 
unsigned nvqs,
  ctx, desc);
  }
  
+static inline

+int virtio_find_vqs_ctx_size(struct virtio_device *vdev, u32 nvqs,
+struct virtqueue *vqs[],
+vq_callback_t *callbacks[],
+const char * const names[],
+u32 sizes[],
+const bool *ctx, struct irq_affinity *desc)
+{
+   return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, sizes,
+ ctx, desc);
+}
+
  /**
   * virtio_device_ready - enable vq use in probe function
   * @vdev: the device



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 28/32] virtio_net: set the default max ring size by find_vqs()

2022-04-12 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Use virtio_find_vqs_ctx_size() to specify the maximum ring size of tx,
rx at the same time.

  | rx/tx ring size
---
speed == UNKNOWN or < 10G| 1024
speed < 40G  | 4096
speed >= 40G | 8192

Call virtnet_update_settings() once before calling init_vqs() to update
speed.

Signed-off-by: Xuan Zhuo 
---



Acked-by: Jason Wang 



  drivers/net/virtio_net.c | 42 
  1 file changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index a801ea40908f..dad497a47b3a 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2861,6 +2861,29 @@ static unsigned int mergeable_min_buf_len(struct 
virtnet_info *vi, struct virtqu
   (unsigned int)GOOD_PACKET_LEN);
  }
  
+static void virtnet_config_sizes(struct virtnet_info *vi, u32 *sizes)

+{
+   u32 i, rx_size, tx_size;
+
+   if (vi->speed == SPEED_UNKNOWN || vi->speed < SPEED_1) {
+   rx_size = 1024;
+   tx_size = 1024;
+
+   } else if (vi->speed < SPEED_4) {
+   rx_size = 1024 * 4;
+   tx_size = 1024 * 4;
+
+   } else {
+   rx_size = 1024 * 8;
+   tx_size = 1024 * 8;
+   }
+
+   for (i = 0; i < vi->max_queue_pairs; i++) {
+   sizes[rxq2vq(i)] = rx_size;
+   sizes[txq2vq(i)] = tx_size;
+   }
+}
+
  static int virtnet_find_vqs(struct virtnet_info *vi)
  {
vq_callback_t **callbacks;
@@ -2868,6 +2891,7 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
int ret = -ENOMEM;
int i, total_vqs;
const char **names;
+   u32 *sizes;
bool *ctx;
  
  	/* We expect 1 RX virtqueue followed by 1 TX virtqueue, followed by

@@ -2895,10 +2919,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
ctx = NULL;
}
  
+	sizes = kmalloc_array(total_vqs, sizeof(*sizes), GFP_KERNEL);

+   if (!sizes)
+   goto err_sizes;
+
/* Parameters for control virtqueue, if any */
if (vi->has_cvq) {
callbacks[total_vqs - 1] = NULL;
names[total_vqs - 1] = "control";
+   sizes[total_vqs - 1] = 64;
}
  
  	/* Allocate/initialize parameters for send/receive virtqueues */

@@ -2913,8 +2942,10 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
ctx[rxq2vq(i)] = true;
}
  
-	ret = virtio_find_vqs_ctx(vi->vdev, total_vqs, vqs, callbacks,

- names, ctx, NULL);
+   virtnet_config_sizes(vi, sizes);
+
+   ret = virtio_find_vqs_ctx_size(vi->vdev, total_vqs, vqs, callbacks,
+  names, sizes, ctx, NULL);
if (ret)
goto err_find;
  
@@ -2934,6 +2965,8 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  
  
  err_find:

+   kfree(sizes);
+err_sizes:
kfree(ctx);
  err_ctx:
kfree(names);
@@ -3252,6 +3285,9 @@ static int virtnet_probe(struct virtio_device *vdev)
vi->curr_queue_pairs = num_online_cpus();
vi->max_queue_pairs = max_queue_pairs;
  
+	virtnet_init_settings(dev);

+   virtnet_update_settings(vi);
+
/* Allocate/initialize the rx/tx queues, and invoke find_vqs */
err = init_vqs(vi);
if (err)
@@ -3264,8 +3300,6 @@ static int virtnet_probe(struct virtio_device *vdev)
netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-	virtnet_init_settings(dev);

-
if (virtio_has_feature(vdev, VIRTIO_NET_F_STANDBY)) {
vi->failover = net_failover_create(vi->dev);
if (IS_ERR(vi->failover)) {



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 29/32] virtio_net: get ringparam by virtqueue_get_vring_max_size()

2022-04-12 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Use virtqueue_get_vring_max_size() in virtnet_get_ringparam() to set
tx,rx_max_pending.

Signed-off-by: Xuan Zhuo 
---



Acked-by: Jason Wang 



  drivers/net/virtio_net.c | 8 
  1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index dad497a47b3a..96d96c666c8c 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2177,10 +2177,10 @@ static void virtnet_get_ringparam(struct net_device 
*dev,
  {
struct virtnet_info *vi = netdev_priv(dev);
  
-	ring->rx_max_pending = virtqueue_get_vring_size(vi->rq[0].vq);

-   ring->tx_max_pending = virtqueue_get_vring_size(vi->sq[0].vq);
-   ring->rx_pending = ring->rx_max_pending;
-   ring->tx_pending = ring->tx_max_pending;
+   ring->rx_max_pending = virtqueue_get_vring_max_size(vi->rq[0].vq);
+   ring->tx_max_pending = virtqueue_get_vring_max_size(vi->sq[0].vq);
+   ring->rx_pending = virtqueue_get_vring_size(vi->rq[0].vq);
+   ring->tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
  }
  
  



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 31/32] virtio_net: support rx/tx queue resize

2022-04-13 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

This patch implements the resize function of the rx, tx queues.
Based on this function, it is possible to modify the ring num of the
queue.

There may be an exception during the resize process, the resize may
fail, or the vq can no longer be used. Either way, we must execute
napi_enable(). Because napi_disable is similar to a lock, napi_enable
must be called after calling napi_disable.

Signed-off-by: Xuan Zhuo 
---
  drivers/net/virtio_net.c | 81 
  1 file changed, 81 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b8bf00525177..ba6859f305f7 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -251,6 +251,9 @@ struct padded_vnet_hdr {
char padding[4];
  };
  
+static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);

+static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void *buf);
+
  static bool is_xdp_frame(void *ptr)
  {
return (unsigned long)ptr & VIRTIO_XDP_FLAG;
@@ -1369,6 +1372,15 @@ static void virtnet_napi_enable(struct virtqueue *vq, 
struct napi_struct *napi)
  {
napi_enable(napi);
  
+	/* Check if vq is in reset state. The normal reset/resize process will

+* be protected by napi. However, the protection of napi is only enabled
+* during the operation, and the protection of napi will end after the
+* operation is completed. If re-enable fails during the process, vq
+* will remain unavailable with reset state.
+*/
+   if (vq->reset)
+   return;



I don't get when could we hit this condition.



+
/* If all buffers were filled by other side before we napi_enabled, we
 * won't get another interrupt, so process any outstanding packets now.
 * Call local_bh_enable after to trigger softIRQ processing.
@@ -1413,6 +1425,15 @@ static void refill_work(struct work_struct *work)
struct receive_queue *rq = &vi->rq[i];
  
  		napi_disable(&rq->napi);

+
+   /* Check if vq is in reset state. See more in
+* virtnet_napi_enable()
+*/
+   if (rq->vq->reset) {
+   virtnet_napi_enable(rq->vq, &rq->napi);
+   continue;
+   }



Can we do something similar in virtnet_close() by canceling the work?



+
still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
virtnet_napi_enable(rq->vq, &rq->napi);
  
@@ -1523,6 +1544,10 @@ static void virtnet_poll_cleantx(struct receive_queue *rq)

if (!sq->napi.weight || is_xdp_raw_buffer_queue(vi, index))
return;
  
+	/* Check if vq is in reset state. See more in virtnet_napi_enable() */

+   if (sq->vq->reset)
+   return;



We've disabled TX napi, any chance we can still hit this?



+
if (__netif_tx_trylock(txq)) {
do {
virtqueue_disable_cb(sq->vq);
@@ -1769,6 +1794,62 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, 
struct net_device *dev)
return NETDEV_TX_OK;
  }
  
+static int virtnet_rx_resize(struct virtnet_info *vi,

+struct receive_queue *rq, u32 ring_num)
+{
+   int err;
+
+   napi_disable(&rq->napi);
+
+   err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_free_unused_buf);
+   if (err)
+   goto err;
+
+   if (!try_fill_recv(vi, rq, GFP_KERNEL))
+   schedule_delayed_work(&vi->refill, 0);
+
+   virtnet_napi_enable(rq->vq, &rq->napi);
+   return 0;
+
+err:
+   netdev_err(vi->dev,
+  "reset rx reset vq fail: rx queue index: %td err: %d\n",
+  rq - vi->rq, err);
+   virtnet_napi_enable(rq->vq, &rq->napi);
+   return err;
+}
+
+static int virtnet_tx_resize(struct virtnet_info *vi,
+struct send_queue *sq, u32 ring_num)
+{
+   struct netdev_queue *txq;
+   int err, qindex;
+
+   qindex = sq - vi->sq;
+
+   virtnet_napi_tx_disable(&sq->napi);
+
+   txq = netdev_get_tx_queue(vi->dev, qindex);
+   __netif_tx_lock_bh(txq);
+   netif_stop_subqueue(vi->dev, qindex);
+   __netif_tx_unlock_bh(txq);
+
+   err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf);
+   if (err)
+   goto err;
+
+   netif_start_subqueue(vi->dev, qindex);
+   virtnet_napi_tx_enable(vi, sq->vq, &sq->napi);
+   return 0;
+
+err:



I guess we can still start the queue in this case? (Since we don't 
change the queue if resize fails).




+   netdev_err(vi->dev,
+  "reset tx reset vq fail: tx queue index: %td err: %d\n",
+  sq - vi->sq, err);
+   virtnet_napi_tx_enable(vi, sq->vq, &sq->napi);
+   return err;
+}
+
  /*
   * Send command via the control virtqueue and check status.  Commands
   * supported by the hypervisor, as indicated by

Re: [PATCH v9 32/32] virtio_net: support set_ringparam

2022-04-13 Thread Jason Wang


在 2022/4/6 上午11:43, Xuan Zhuo 写道:

Support set_ringparam based on virtio queue reset.

Users can use ethtool -G eth0  to modify the ring size of
virtio-net.

Signed-off-by: Xuan Zhuo 



Acked-by: Jason Wang 

(One thing that I see is that, when resize fails, the param reported via 
get_ringparam might be wrong, this is a corner case but might worth to 
fix in the future).




---
  drivers/net/virtio_net.c | 47 
  1 file changed, 47 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index ba6859f305f7..37e4e27f1e4e 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2264,6 +2264,52 @@ static void virtnet_get_ringparam(struct net_device *dev,
ring->tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
  }
  
+static int virtnet_set_ringparam(struct net_device *dev,

+struct ethtool_ringparam *ring,
+struct kernel_ethtool_ringparam *kernel_ring,
+struct netlink_ext_ack *extack)
+{
+   struct virtnet_info *vi = netdev_priv(dev);
+   u32 rx_pending, tx_pending;
+   struct receive_queue *rq;
+   struct send_queue *sq;
+   int i, err;
+
+   if (ring->rx_mini_pending || ring->rx_jumbo_pending)
+   return -EINVAL;
+
+   rx_pending = virtqueue_get_vring_size(vi->rq[0].vq);
+   tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
+
+   if (ring->rx_pending == rx_pending &&
+   ring->tx_pending == tx_pending)
+   return 0;
+
+   if (ring->rx_pending > virtqueue_get_vring_max_size(vi->rq[0].vq))
+   return -EINVAL;
+
+   if (ring->tx_pending > virtqueue_get_vring_max_size(vi->sq[0].vq))
+   return -EINVAL;
+
+   for (i = 0; i < vi->max_queue_pairs; i++) {
+   rq = vi->rq + i;
+   sq = vi->sq + i;
+
+   if (ring->tx_pending != tx_pending) {
+   err = virtnet_tx_resize(vi, sq, ring->tx_pending);
+   if (err)
+   return err;
+   }
+
+   if (ring->rx_pending != rx_pending) {
+   err = virtnet_rx_resize(vi, rq, ring->rx_pending);
+   if (err)
+   return err;
+   }
+   }
+
+   return 0;
+}
  
  static void virtnet_get_drvinfo(struct net_device *dev,

struct ethtool_drvinfo *info)
@@ -2497,6 +2543,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
.get_drvinfo = virtnet_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = virtnet_get_ringparam,
+   .set_ringparam = virtnet_set_ringparam,
.get_strings = virtnet_get_strings,
.get_sset_count = virtnet_get_sset_count,
.get_ethtool_stats = virtnet_get_ethtool_stats,



___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 01/32] virtio: add helper virtqueue_get_vring_max_size()

2022-04-14 Thread Jason Wang
On Wed, Apr 13, 2022 at 10:30 AM Xuan Zhuo  wrote:
>
> On Tue, 12 Apr 2022 10:41:03 +0800, Jason Wang  wrote:
> >
> > 在 2022/4/6 上午11:43, Xuan Zhuo 写道:
> > > Record the maximum queue num supported by the device.
> > >
> > > virtio-net can display the maximum (supported by hardware) ring size in
> > > ethtool -g eth0.
> > >
> > > When the subsequent patch implements vring reset, it can judge whether
> > > the ring size passed by the driver is legal based on this.
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > ---
> > >   arch/um/drivers/virtio_uml.c |  1 +
> > >   drivers/platform/mellanox/mlxbf-tmfifo.c |  2 ++
> > >   drivers/remoteproc/remoteproc_virtio.c   |  2 ++
> > >   drivers/s390/virtio/virtio_ccw.c |  3 +++
> > >   drivers/virtio/virtio_mmio.c |  2 ++
> > >   drivers/virtio/virtio_pci_legacy.c   |  2 ++
> > >   drivers/virtio/virtio_pci_modern.c   |  2 ++
> > >   drivers/virtio/virtio_ring.c | 14 ++
> > >   drivers/virtio/virtio_vdpa.c |  2 ++
> > >   include/linux/virtio.h   |  2 ++
> > >   10 files changed, 32 insertions(+)
> > >
> > > diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
> > > index ba562d68dc04..904993d15a85 100644
> > > --- a/arch/um/drivers/virtio_uml.c
> > > +++ b/arch/um/drivers/virtio_uml.c
> > > @@ -945,6 +945,7 @@ static struct virtqueue *vu_setup_vq(struct 
> > > virtio_device *vdev,
> > > goto error_create;
> > > }
> > > vq->priv = info;
> > > +   vq->num_max = num;
> > > num = virtqueue_get_vring_size(vq);
> > >
> > > if (vu_dev->protocol_features &
> > > diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c 
> > > b/drivers/platform/mellanox/mlxbf-tmfifo.c
> > > index 38800e86ed8a..1ae3c56b66b0 100644
> > > --- a/drivers/platform/mellanox/mlxbf-tmfifo.c
> > > +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
> > > @@ -959,6 +959,8 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct 
> > > virtio_device *vdev,
> > > goto error;
> > > }
> > >
> > > +   vq->num_max = vring->num;
> > > +
> > > vqs[i] = vq;
> > > vring->vq = vq;
> > > vq->priv = vring;
> > > diff --git a/drivers/remoteproc/remoteproc_virtio.c 
> > > b/drivers/remoteproc/remoteproc_virtio.c
> > > index 70ab496d0431..7611755d0ae2 100644
> > > --- a/drivers/remoteproc/remoteproc_virtio.c
> > > +++ b/drivers/remoteproc/remoteproc_virtio.c
> > > @@ -125,6 +125,8 @@ static struct virtqueue *rp_find_vq(struct 
> > > virtio_device *vdev,
> > > return ERR_PTR(-ENOMEM);
> > > }
> > >
> > > +   vq->num_max = len;
> >
> >
> > I wonder if this is correct.
> >
> > It looks to me len is counted in bytes:
> >
> > /**
> >   * struct rproc_vring - remoteproc vring state
> >   * @va: virtual address
> >   * @len: length, in bytes
> >   * @da: device address
> >   * @align: vring alignment
> >   * @notifyid: rproc-specific unique vring index
> >   * @rvdev: remote vdev
> >   * @vq: the virtqueue of this vring
> >   */
> > struct rproc_vring {
> >  void *va;
> >  int len;
> >  u32 da;
> >  u32 align;
> >  int notifyid;
> >  struct rproc_vdev *rvdev;
> >  struct virtqueue *vq;
> > };
> >
>
> I think this comment is incorrect because here len is passed as num to
> vring_new_virtqueue().
>
> There is also this usage:
>
> /* actual size of vring (in bytes) */
> size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
>
>
> And this value comes from here:
>
> static int
> rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, 
> int i)
> {
> struct rproc *rproc = rvdev->rproc;
> struct device *dev = &rproc->dev;
> struct fw_rsc_vdev_vring *vring = &rsc->vring[i];
> struct rproc_vring *rvring = &rvdev->vring[i];
>
> dev_dbg(dev, "vdev rsc: vring%d: da 0x%x, qsz %d, align %d\n",
> i, vring->da, vring->num, vring->align);
>
> 

Re: [PATCH v9 23/32] virtio_pci: queue_reset: support VIRTIO_F_RING_RESET

2022-04-14 Thread Jason Wang
On Wed, Apr 13, 2022 at 11:23 AM Xuan Zhuo  wrote:
>
> On Tue, 12 Apr 2022 15:07:58 +0800, Jason Wang  wrote:
> >
> > 在 2022/4/6 上午11:43, Xuan Zhuo 写道:
> > > This patch implements virtio pci support for QUEUE RESET.
> > >
> > > Performing reset on a queue is divided into these steps:
> > >
> > >   1. notify the device to reset the queue
> > >   2. recycle the buffer submitted
> > >   3. reset the vring (may re-alloc)
> > >   4. mmap vring to device, and enable the queue
> > >
> > > This patch implements virtio_reset_vq(), virtio_enable_resetq() in the
> > > pci scenario.
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > ---
> > >   drivers/virtio/virtio_pci_common.c |  8 +--
> > >   drivers/virtio/virtio_pci_modern.c | 84 ++
> > >   drivers/virtio/virtio_ring.c   |  2 +
> > >   include/linux/virtio.h |  1 +
> > >   4 files changed, 92 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/drivers/virtio/virtio_pci_common.c 
> > > b/drivers/virtio/virtio_pci_common.c
> > > index fdbde1db5ec5..863d3a8a0956 100644
> > > --- a/drivers/virtio/virtio_pci_common.c
> > > +++ b/drivers/virtio/virtio_pci_common.c
> > > @@ -248,9 +248,11 @@ static void vp_del_vq(struct virtqueue *vq)
> > > struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
> > > unsigned long flags;
> > >
> > > -   spin_lock_irqsave(&vp_dev->lock, flags);
> > > -   list_del(&info->node);
> > > -   spin_unlock_irqrestore(&vp_dev->lock, flags);
> > > +   if (!vq->reset) {
> >
> >
> > On which condition that we may hit this path?
> >
> >
> > > +   spin_lock_irqsave(&vp_dev->lock, flags);
> > > +   list_del(&info->node);
> > > +   spin_unlock_irqrestore(&vp_dev->lock, flags);
> > > +   }
> > >
> > > vp_dev->del_vq(info);
> > > kfree(info);
> > > diff --git a/drivers/virtio/virtio_pci_modern.c 
> > > b/drivers/virtio/virtio_pci_modern.c
> > > index 49a4493732cf..cb5d38f1c9c8 100644
> > > --- a/drivers/virtio/virtio_pci_modern.c
> > > +++ b/drivers/virtio/virtio_pci_modern.c
> > > @@ -34,6 +34,9 @@ static void vp_transport_features(struct virtio_device 
> > > *vdev, u64 features)
> > > if ((features & BIT_ULL(VIRTIO_F_SR_IOV)) &&
> > > pci_find_ext_capability(pci_dev, 
> > > PCI_EXT_CAP_ID_SRIOV))
> > > __virtio_set_bit(vdev, VIRTIO_F_SR_IOV);
> > > +
> > > +   if (features & BIT_ULL(VIRTIO_F_RING_RESET))
> > > +   __virtio_set_bit(vdev, VIRTIO_F_RING_RESET);
> > >   }
> > >
> > >   /* virtio config->finalize_features() implementation */
> > > @@ -199,6 +202,83 @@ static int vp_active_vq(struct virtqueue *vq, u16 
> > > msix_vec)
> > > return 0;
> > >   }
> > >
> > > +static int vp_modern_reset_vq(struct virtqueue *vq)
> > > +{
> > > +   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
> > > +   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
> > > +   struct virtio_pci_vq_info *info;
> > > +   unsigned long flags;
> > > +
> > > +   if (!virtio_has_feature(vq->vdev, VIRTIO_F_RING_RESET))
> > > +   return -ENOENT;
> > > +
> > > +   vp_modern_set_queue_reset(mdev, vq->index);
> > > +
> > > +   info = vp_dev->vqs[vq->index];
> > > +
> > > +   /* delete vq from irq handler */
> > > +   spin_lock_irqsave(&vp_dev->lock, flags);
> > > +   list_del(&info->node);
> > > +   spin_unlock_irqrestore(&vp_dev->lock, flags);
> > > +
> > > +   INIT_LIST_HEAD(&info->node);
> > > +
> > > +   /* For the case where vq has an exclusive irq, to prevent the irq from
> > > +* being received again and the pending irq, call disable_irq().
> > > +*
> > > +* In the scenario based on shared interrupts, vq will be searched 
> > > from
> > > +* the queue virtqueues. Since the previous list_del() has been 
> > > deleted
> > > +* from the queue, it is impossible for vq to be called in this case.
> > > +* There is no need to close the corresponding interrupt.
> > > +*/
> > > +   if (vp_dev->p

Re: [PATCH v9 12/32] virtio_ring: packed: extract the logic of alloc queue

2022-04-14 Thread Jason Wang
On Wed, Apr 13, 2022 at 11:26 AM Xuan Zhuo  wrote:
>
> On Tue, 12 Apr 2022 14:28:24 +0800, Jason Wang  wrote:
> >
> > 在 2022/4/6 上午11:43, Xuan Zhuo 写道:
> > > Separate the logic of packed to create vring queue.
> > >
> > > For the convenience of passing parameters, add a structure
> > > vring_packed.
> > >
> > > This feature is required for subsequent virtuqueue reset vring.
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > ---
> > >   drivers/virtio/virtio_ring.c | 70 
> > >   1 file changed, 56 insertions(+), 14 deletions(-)
> > >
> > > diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> > > index 33864134a744..ea451ae2aaef 100644
> > > --- a/drivers/virtio/virtio_ring.c
> > > +++ b/drivers/virtio/virtio_ring.c
> > > @@ -1817,19 +1817,17 @@ static struct vring_desc_extra 
> > > *vring_alloc_desc_extra(unsigned int num)
> > > return desc_extra;
> > >   }
> > >
> > > -static struct virtqueue *vring_create_virtqueue_packed(
> > > -   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_packed(struct virtio_device *vdev,
> > > +   u32 num,
> > > +   struct vring_packed_desc **_ring,
> > > +   struct vring_packed_desc_event **_driver,
> > > +   struct vring_packed_desc_event **_device,
> > > +   dma_addr_t *_ring_dma_addr,
> > > +   dma_addr_t *_driver_event_dma_addr,
> > > +   dma_addr_t *_device_event_dma_addr,
> > > +   size_t *_ring_size_in_bytes,
> > > +   size_t *_event_size_in_bytes)
> > >   {
> > > -   struct vring_virtqueue *vq;
> > > struct vring_packed_desc *ring;
> > > struct vring_packed_desc_event *driver, *device;
> > > dma_addr_t ring_dma_addr, driver_event_dma_addr, 
> > > device_event_dma_addr;
> > > @@ -1857,6 +1855,52 @@ static struct virtqueue 
> > > *vring_create_virtqueue_packed(
> > > if (!device)
> > > goto err_device;
> > >
> > > +   *_ring   = ring;
> > > +   *_driver = driver;
> > > +   *_device = device;
> > > +   *_ring_dma_addr  = ring_dma_addr;
> > > +   *_driver_event_dma_addr  = driver_event_dma_addr;
> > > +   *_device_event_dma_addr  = device_event_dma_addr;
> > > +   *_ring_size_in_bytes = ring_size_in_bytes;
> > > +   *_event_size_in_bytes= event_size_in_bytes;
> >
> >
> > I wonder if we can simply factor out split and packed from struct
> > vring_virtqueue:
> >
> > struct vring_virtqueue {
> >  union {
> >  struct {} split;
> >  struct {} packed;
> >  };
> > };
> >
> > to
> >
> > struct vring_virtqueue_split {};
> > struct vring_virtqueue_packed {};
> >
> > Then we can do things like:
> >
> > vring_create_virtqueue_packed(struct virtio_device *vdev, u32 num,
> > struct vring_virtqueue_packed *packed);
> >
> > and
> >
> > vring_vritqueue_attach_packed(struct vring_virtqueue *vq, struct
> > vring_virtqueue_packed packed);
>
> This idea is very similar to my previous idea, just without introducing a new
> structure.

Yes, it's better to not introduce new structures if it's possible.

>
> I'd be more than happy to revise this.

Good to know this.

Thanks

>
> Thanks.
>
>
> >
> > Thanks
> >
> >
> > > +
> > > +   return 0;
> > > +
> > > +err_device:
> > > +   vring_free_queue(vdev, event_size_in_bytes, driver, 
> > > driver_event_dma_addr);
> > > +
> > > +err_driver:
> > > +   vring_free_queue(vdev, ring_size_in_bytes, ring, ring_dma_addr);
> > > +
> > > +err_ring:
> > > +   return -ENOMEM;
> > > +}
> > > +
> 

Re: [PATCH v9 31/32] virtio_net: support rx/tx queue resize

2022-04-14 Thread Jason Wang
On Wed, Apr 13, 2022 at 4:47 PM Xuan Zhuo  wrote:
>
> On Wed, 13 Apr 2022 16:00:18 +0800, Jason Wang  wrote:
> >
> > 在 2022/4/6 上午11:43, Xuan Zhuo 写道:
> > > This patch implements the resize function of the rx, tx queues.
> > > Based on this function, it is possible to modify the ring num of the
> > > queue.
> > >
> > > There may be an exception during the resize process, the resize may
> > > fail, or the vq can no longer be used. Either way, we must execute
> > > napi_enable(). Because napi_disable is similar to a lock, napi_enable
> > > must be called after calling napi_disable.
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > ---
> > >   drivers/net/virtio_net.c | 81 
> > >   1 file changed, 81 insertions(+)
> > >
> > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > > index b8bf00525177..ba6859f305f7 100644
> > > --- a/drivers/net/virtio_net.c
> > > +++ b/drivers/net/virtio_net.c
> > > @@ -251,6 +251,9 @@ struct padded_vnet_hdr {
> > > char padding[4];
> > >   };
> > >
> > > +static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
> > > +static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void *buf);
> > > +
> > >   static bool is_xdp_frame(void *ptr)
> > >   {
> > > return (unsigned long)ptr & VIRTIO_XDP_FLAG;
> > > @@ -1369,6 +1372,15 @@ static void virtnet_napi_enable(struct virtqueue 
> > > *vq, struct napi_struct *napi)
> > >   {
> > > napi_enable(napi);
> > >
> > > +   /* Check if vq is in reset state. The normal reset/resize process will
> > > +* be protected by napi. However, the protection of napi is only 
> > > enabled
> > > +* during the operation, and the protection of napi will end after the
> > > +* operation is completed. If re-enable fails during the process, vq
> > > +* will remain unavailable with reset state.
> > > +*/
> > > +   if (vq->reset)
> > > +   return;
> >
> >
> > I don't get when could we hit this condition.
>
>
> In patch 23, the code to implement re-enable vq is as follows:
>
> +static int vp_modern_enable_reset_vq(struct virtqueue *vq)
> +{
> +   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
> +   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
> +   struct virtio_pci_vq_info *info;
> +   unsigned long flags, index;
> +   int err;
> +
> +   if (!vq->reset)
> +   return -EBUSY;
> +
> +   index = vq->index;
> +   info = vp_dev->vqs[index];
> +
> +   /* check queue reset status */
> +   if (vp_modern_get_queue_reset(mdev, index) != 1)
> +   return -EBUSY;
> +
> +   err = vp_active_vq(vq, info->msix_vector);
> +   if (err)
> +   return err;
> +
> +   if (vq->callback) {
> +   spin_lock_irqsave(&vp_dev->lock, flags);
> +   list_add(&info->node, &vp_dev->virtqueues);
> +   spin_unlock_irqrestore(&vp_dev->lock, flags);
> +   } else {
> +   INIT_LIST_HEAD(&info->node);
> +   }
> +
> +   vp_modern_set_queue_enable(&vp_dev->mdev, index, true);
> +
> +   if (vp_dev->per_vq_vectors && info->msix_vector != 
> VIRTIO_MSI_NO_VECTOR)
> +   enable_irq(pci_irq_vector(vp_dev->pci_dev, 
> info->msix_vector));
> +
> +   vq->reset = false;
> +
> +   return 0;
> +}
>
>
> There are three situations where an error will be returned. These are the
> situations I want to handle.

Right, but it looks harmless if we just schedule the NAPI without the check.

>
> But I'm rethinking the question, and I feel like you're right, although the
> hardware setup may fail. We can no longer sync with the hardware. But using it
> as a normal vq doesn't have any problems.

Note that we should make sure the buggy(malicous) device won't crash
the codes by changing the queue_reset value at its will.

>
> >
> >
> > > +
> > > /* If all buffers were filled by other side before we napi_enabled, we
> > >  * won't get another interrupt, so process any outstanding packets 
> > > now.
> > >  * Call local_bh_enable after to trigger softIRQ processing.
> > > @@ -1413,6 +1425,15 @@ static void refill_work(struct work_struct *work)
> > > 

Re: [PATCH v9 22/32] virtio_pci: queue_reset: extract the logic of active vq for modern pci

2022-04-14 Thread Jason Wang
On Thu, Apr 14, 2022 at 2:25 PM Xuan Zhuo  wrote:
>
> On Tue, 12 Apr 2022 14:58:19 +0800, Jason Wang  wrote:
> >
> > 在 2022/4/6 上午11:43, Xuan Zhuo 写道:
> > > Introduce vp_active_vq() to configure vring to backend after vq attach
> > > vring. And configure vq vector if necessary.
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > ---
> > >   drivers/virtio/virtio_pci_modern.c | 46 ++
> > >   1 file changed, 28 insertions(+), 18 deletions(-)
> > >
> > > diff --git a/drivers/virtio/virtio_pci_modern.c 
> > > b/drivers/virtio/virtio_pci_modern.c
> > > index 86d301f272b8..49a4493732cf 100644
> > > --- a/drivers/virtio/virtio_pci_modern.c
> > > +++ b/drivers/virtio/virtio_pci_modern.c
> > > @@ -176,6 +176,29 @@ static void vp_reset(struct virtio_device *vdev)
> > > vp_disable_cbs(vdev);
> > >   }
> > >
> > > +static int vp_active_vq(struct virtqueue *vq, u16 msix_vec)
> > > +{
> > > +   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
> > > +   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
> > > +   unsigned long index;
> > > +
> > > +   index = vq->index;
> > > +
> > > +   /* activate the queue */
> > > +   vp_modern_set_queue_size(mdev, index, virtqueue_get_vring_size(vq));
> > > +   vp_modern_queue_address(mdev, index, virtqueue_get_desc_addr(vq),
> > > +   virtqueue_get_avail_addr(vq),
> > > +   virtqueue_get_used_addr(vq));
> > > +
> > > +   if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
> > > +   msix_vec = vp_modern_queue_vector(mdev, index, msix_vec);
> > > +   if (msix_vec == VIRTIO_MSI_NO_VECTOR)
> > > +   return -EBUSY;
> > > +   }
> > > +
> > > +   return 0;
> > > +}
> > > +
> > >   static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 
> > > vector)
> > >   {
> > > return vp_modern_config_vector(&vp_dev->mdev, vector);
> > > @@ -220,32 +243,19 @@ static struct virtqueue *setup_vq(struct 
> > > virtio_pci_device *vp_dev,
> > >
> > > vq->num_max = num;
> > >
> > > -   /* activate the queue */
> > > -   vp_modern_set_queue_size(mdev, index, virtqueue_get_vring_size(vq));
> > > -   vp_modern_queue_address(mdev, index, virtqueue_get_desc_addr(vq),
> > > -   virtqueue_get_avail_addr(vq),
> > > -   virtqueue_get_used_addr(vq));
> > > +   err = vp_active_vq(vq, msix_vec);
> > > +   if (err)
> > > +   goto err;
> > >
> > > vq->priv = (void __force *)vp_modern_map_vq_notify(mdev, index, NULL);
> > > if (!vq->priv) {
> > > err = -ENOMEM;
> > > -   goto err_map_notify;
> > > -   }
> > > -
> > > -   if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
> > > -   msix_vec = vp_modern_queue_vector(mdev, index, msix_vec);
> > > -   if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
> > > -       err = -EBUSY;
> > > -   goto err_assign_vector;
> > > -   }
> > > +   goto err;
> > > }
> > >
> > > return vq;
> > >
> > > -err_assign_vector:
> > > -   if (!mdev->notify_base)
> > > -   pci_iounmap(mdev->pci_dev, (void __iomem __force *)vq->priv);
> >
> >
> > We need keep this or anything I missed?
>
> I think so, after modification, vp_modern_map_vq_notify is the last step 
> before
> returning vq. If it fails, then vq->priv is equal to NULL, so there is no need
> to execute pci_iounmap.
>
> Did I miss something?

Nope I miss that the vector is configured before the mapping.

So

Acked-by: Jason Wang 

Thanks

>
> Thanks.
>
> >
> > Thanks
> >
> >
> > > -err_map_notify:
> > > +err:
> > > vring_del_virtqueue(vq);
> > > return ERR_PTR(err);
> > >   }
> >
>


___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v9 31/32] virtio_net: support rx/tx queue resize

2022-04-14 Thread Jason Wang
On Fri, Apr 15, 2022 at 10:23 AM Xuan Zhuo  wrote:
>
> On Thu, 14 Apr 2022 17:30:02 +0800, Jason Wang  wrote:
> > On Wed, Apr 13, 2022 at 4:47 PM Xuan Zhuo  
> > wrote:
> > >
> > > On Wed, 13 Apr 2022 16:00:18 +0800, Jason Wang  
> > > wrote:
> > > >
> > > > 在 2022/4/6 上午11:43, Xuan Zhuo 写道:
> > > > > This patch implements the resize function of the rx, tx queues.
> > > > > Based on this function, it is possible to modify the ring num of the
> > > > > queue.
> > > > >
> > > > > There may be an exception during the resize process, the resize may
> > > > > fail, or the vq can no longer be used. Either way, we must execute
> > > > > napi_enable(). Because napi_disable is similar to a lock, napi_enable
> > > > > must be called after calling napi_disable.
> > > > >
> > > > > Signed-off-by: Xuan Zhuo 
> > > > > ---
> > > > >   drivers/net/virtio_net.c | 81 
> > > > > 
> > > > >   1 file changed, 81 insertions(+)
> > > > >
> > > > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > > > > index b8bf00525177..ba6859f305f7 100644
> > > > > --- a/drivers/net/virtio_net.c
> > > > > +++ b/drivers/net/virtio_net.c
> > > > > @@ -251,6 +251,9 @@ struct padded_vnet_hdr {
> > > > > char padding[4];
> > > > >   };
> > > > >
> > > > > +static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void 
> > > > > *buf);
> > > > > +static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void 
> > > > > *buf);
> > > > > +
> > > > >   static bool is_xdp_frame(void *ptr)
> > > > >   {
> > > > > return (unsigned long)ptr & VIRTIO_XDP_FLAG;
> > > > > @@ -1369,6 +1372,15 @@ static void virtnet_napi_enable(struct 
> > > > > virtqueue *vq, struct napi_struct *napi)
> > > > >   {
> > > > > napi_enable(napi);
> > > > >
> > > > > +   /* Check if vq is in reset state. The normal reset/resize process 
> > > > > will
> > > > > +* be protected by napi. However, the protection of napi is only 
> > > > > enabled
> > > > > +* during the operation, and the protection of napi will end 
> > > > > after the
> > > > > +* operation is completed. If re-enable fails during the process, 
> > > > > vq
> > > > > +* will remain unavailable with reset state.
> > > > > +*/
> > > > > +   if (vq->reset)
> > > > > +   return;
> > > >
> > > >
> > > > I don't get when could we hit this condition.
> > >
> > >
> > > In patch 23, the code to implement re-enable vq is as follows:
> > >
> > > +static int vp_modern_enable_reset_vq(struct virtqueue *vq)
> > > +{
> > > +   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
> > > +   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
> > > +   struct virtio_pci_vq_info *info;
> > > +   unsigned long flags, index;
> > > +   int err;
> > > +
> > > +   if (!vq->reset)
> > > +   return -EBUSY;
> > > +
> > > +   index = vq->index;
> > > +   info = vp_dev->vqs[index];
> > > +
> > > +   /* check queue reset status */
> > > +   if (vp_modern_get_queue_reset(mdev, index) != 1)
> > > +   return -EBUSY;
> > > +
> > > +   err = vp_active_vq(vq, info->msix_vector);
> > > +   if (err)
> > > +   return err;
> > > +
> > > +   if (vq->callback) {
> > > +   spin_lock_irqsave(&vp_dev->lock, flags);
> > > +   list_add(&info->node, &vp_dev->virtqueues);
> > > +   spin_unlock_irqrestore(&vp_dev->lock, flags);
> > > +   } else {
> > > +   INIT_LIST_HEAD(&info->node);
> > > +   }
> > > +
> > > +   vp_modern_set_queue_enable(&vp_dev->mdev, index, true);
> > > +
> > > +   if (vp_dev->per_vq_vectors && info->msix_vector != 
> > > VIRTIO_MSI_NO_VECTO

Re: [PATCH v9 31/32] virtio_net: support rx/tx queue resize

2022-04-18 Thread Jason Wang
On Mon, Apr 18, 2022 at 11:24 AM Xuan Zhuo  wrote:
>
> On Wed, 13 Apr 2022 16:00:18 +0800, Jason Wang  wrote:
> >
> > 在 2022/4/6 上午11:43, Xuan Zhuo 写道:
> > > This patch implements the resize function of the rx, tx queues.
> > > Based on this function, it is possible to modify the ring num of the
> > > queue.
> > >
> > > There may be an exception during the resize process, the resize may
> > > fail, or the vq can no longer be used. Either way, we must execute
> > > napi_enable(). Because napi_disable is similar to a lock, napi_enable
> > > must be called after calling napi_disable.
> > >
> > > Signed-off-by: Xuan Zhuo 
> > > ---
> > >   drivers/net/virtio_net.c | 81 
> > >   1 file changed, 81 insertions(+)
> > >
> > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > > index b8bf00525177..ba6859f305f7 100644
> > > --- a/drivers/net/virtio_net.c
> > > +++ b/drivers/net/virtio_net.c
> > > @@ -251,6 +251,9 @@ struct padded_vnet_hdr {
> > > char padding[4];
> > >   };
> > >
> > > +static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
> > > +static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void *buf);
> > > +
> > >   static bool is_xdp_frame(void *ptr)
> > >   {
> > > return (unsigned long)ptr & VIRTIO_XDP_FLAG;
> > > @@ -1369,6 +1372,15 @@ static void virtnet_napi_enable(struct virtqueue 
> > > *vq, struct napi_struct *napi)
> > >   {
> > > napi_enable(napi);
> > >
> > > +   /* Check if vq is in reset state. The normal reset/resize process will
> > > +* be protected by napi. However, the protection of napi is only 
> > > enabled
> > > +* during the operation, and the protection of napi will end after the
> > > +* operation is completed. If re-enable fails during the process, vq
> > > +* will remain unavailable with reset state.
> > > +*/
> > > +   if (vq->reset)
> > > +   return;
> >
> >
> > I don't get when could we hit this condition.
> >
> >
> > > +
> > > /* If all buffers were filled by other side before we napi_enabled, we
> > >  * won't get another interrupt, so process any outstanding packets 
> > > now.
> > >  * Call local_bh_enable after to trigger softIRQ processing.
> > > @@ -1413,6 +1425,15 @@ static void refill_work(struct work_struct *work)
> > > struct receive_queue *rq = &vi->rq[i];
> > >
> > > napi_disable(&rq->napi);
> > > +
> > > +   /* Check if vq is in reset state. See more in
> > > +* virtnet_napi_enable()
> > > +*/
> > > +   if (rq->vq->reset) {
> > > +   virtnet_napi_enable(rq->vq, &rq->napi);
> > > +   continue;
> > > +   }
> >
> >
> > Can we do something similar in virtnet_close() by canceling the work?
> >
> >
> > > +
> > > still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
> > > virtnet_napi_enable(rq->vq, &rq->napi);
> > >
> > > @@ -1523,6 +1544,10 @@ static void virtnet_poll_cleantx(struct 
> > > receive_queue *rq)
> > > if (!sq->napi.weight || is_xdp_raw_buffer_queue(vi, index))
> > > return;
> > >
> > > +   /* Check if vq is in reset state. See more in virtnet_napi_enable() */
> > > +   if (sq->vq->reset)
> > > +   return;
> >
> >
> > We've disabled TX napi, any chance we can still hit this?
>
>
> static int virtnet_poll(struct napi_struct *napi, int budget)
> {
> struct receive_queue *rq =
> container_of(napi, struct receive_queue, napi);
> struct virtnet_info *vi = rq->vq->vdev->priv;
> struct send_queue *sq;
> unsigned int received;
> unsigned int xdp_xmit = 0;
>
> virtnet_poll_cleantx(rq);
> ...
> }
>
> This is called by rx poll. Although it is the logic of tx, it is not driven by
> tx napi, but is called in rx poll.

Ok, but we need guarantee the memory ordering in this case. Disable RX
napi could be a solution for this.

Thanks

>
> Thanks.
>
>
> >
> >
> > > +
> > > if (__netif_tx_trylock(txq)) {
> > >   

Re: [PATCH v9 31/32] virtio_net: support rx/tx queue resize

2022-04-18 Thread Jason Wang


在 2022/4/15 17:17, Xuan Zhuo 写道:

On Fri, 15 Apr 2022 13:53:54 +0800, Jason Wang  wrote:

On Fri, Apr 15, 2022 at 10:23 AM Xuan Zhuo  wrote:

On Thu, 14 Apr 2022 17:30:02 +0800, Jason Wang  wrote:

On Wed, Apr 13, 2022 at 4:47 PM Xuan Zhuo  wrote:

On Wed, 13 Apr 2022 16:00:18 +0800, Jason Wang  wrote:

在 2022/4/6 上午11:43, Xuan Zhuo 写道:

This patch implements the resize function of the rx, tx queues.
Based on this function, it is possible to modify the ring num of the
queue.

There may be an exception during the resize process, the resize may
fail, or the vq can no longer be used. Either way, we must execute
napi_enable(). Because napi_disable is similar to a lock, napi_enable
must be called after calling napi_disable.

Signed-off-by: Xuan Zhuo 
---
   drivers/net/virtio_net.c | 81 
   1 file changed, 81 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b8bf00525177..ba6859f305f7 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -251,6 +251,9 @@ struct padded_vnet_hdr {
 char padding[4];
   };

+static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
+static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void *buf);
+
   static bool is_xdp_frame(void *ptr)
   {
 return (unsigned long)ptr & VIRTIO_XDP_FLAG;
@@ -1369,6 +1372,15 @@ static void virtnet_napi_enable(struct virtqueue *vq, 
struct napi_struct *napi)
   {
 napi_enable(napi);

+   /* Check if vq is in reset state. The normal reset/resize process will
+* be protected by napi. However, the protection of napi is only enabled
+* during the operation, and the protection of napi will end after the
+* operation is completed. If re-enable fails during the process, vq
+* will remain unavailable with reset state.
+*/
+   if (vq->reset)
+   return;


I don't get when could we hit this condition.


In patch 23, the code to implement re-enable vq is as follows:

+static int vp_modern_enable_reset_vq(struct virtqueue *vq)
+{
+   struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+   struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+   struct virtio_pci_vq_info *info;
+   unsigned long flags, index;
+   int err;
+
+   if (!vq->reset)
+   return -EBUSY;
+
+   index = vq->index;
+   info = vp_dev->vqs[index];
+
+   /* check queue reset status */
+   if (vp_modern_get_queue_reset(mdev, index) != 1)
+   return -EBUSY;
+
+   err = vp_active_vq(vq, info->msix_vector);
+   if (err)
+   return err;
+
+   if (vq->callback) {
+   spin_lock_irqsave(&vp_dev->lock, flags);
+   list_add(&info->node, &vp_dev->virtqueues);
+   spin_unlock_irqrestore(&vp_dev->lock, flags);
+   } else {
+   INIT_LIST_HEAD(&info->node);
+   }
+
+   vp_modern_set_queue_enable(&vp_dev->mdev, index, true);
+
+   if (vp_dev->per_vq_vectors && info->msix_vector != VIRTIO_MSI_NO_VECTOR)
+   enable_irq(pci_irq_vector(vp_dev->pci_dev, info->msix_vector));
+
+   vq->reset = false;
+
+   return 0;
+}


There are three situations where an error will be returned. These are the
situations I want to handle.

Right, but it looks harmless if we just schedule the NAPI without the check.

Yes.


But I'm rethinking the question, and I feel like you're right, although the
hardware setup may fail. We can no longer sync with the hardware. But using it
as a normal vq doesn't have any problems.

Note that we should make sure the buggy(malicous) device won't crash
the codes by changing the queue_reset value at its will.

I will keep an eye on this situation.




+
 /* If all buffers were filled by other side before we napi_enabled, we
  * won't get another interrupt, so process any outstanding packets now.
  * Call local_bh_enable after to trigger softIRQ processing.
@@ -1413,6 +1425,15 @@ static void refill_work(struct work_struct *work)
 struct receive_queue *rq = &vi->rq[i];

 napi_disable(&rq->napi);
+
+   /* Check if vq is in reset state. See more in
+* virtnet_napi_enable()
+*/
+   if (rq->vq->reset) {
+   virtnet_napi_enable(rq->vq, &rq->napi);
+   continue;
+   }


Can we do something similar in virtnet_close() by canceling the work?

I think there is no need to cancel the work here, because napi_disable will wait
for the napi_enable of the resize. So if the re-enable failed vq is used as a 
normal
vq, this logic can be removed.

Actually I meant the part of virtnet_rx_resize().

If we don't synchronize with the refill work, it might enable NAPI unexpectedly?

I don't think this situation wil

Re: [PATCH] um: virt-pci: set device ready in probe()

2022-06-12 Thread Jason Wang
On Fri, Jun 10, 2022 at 11:12 PM Vincent Whitchurch
 wrote:
>
> Call virtio_device_ready() to make this driver work after commit
> b4ec69d7e09 ("virtio: harden vring IRQ"), since the driver uses the
> virtqueues in the probe function.  (The virtio core sets the device
> ready when probe returns.)
>
> Fixes: 8b4ec69d7e09 ("virtio: harden vring IRQ")
> Signed-off-by: Vincent Whitchurch 
> ---
>  arch/um/drivers/virt-pci.c | 7 ++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c
> index 5c092a9153ea..027847023184 100644
> --- a/arch/um/drivers/virt-pci.c
> +++ b/arch/um/drivers/virt-pci.c
> @@ -544,6 +544,8 @@ static int um_pci_init_vqs(struct um_pci_device *dev)
> dev->cmd_vq = vqs[0];
> dev->irq_vq = vqs[1];
>
> +   virtio_device_ready(dev->vdev);
> +
> for (i = 0; i < NUM_IRQ_MSGS; i++) {
> void *msg = kzalloc(MAX_IRQ_MSG_SIZE, GFP_KERNEL);
>
> @@ -587,7 +589,7 @@ static int um_pci_virtio_probe(struct virtio_device *vdev)
> dev->irq = irq_alloc_desc(numa_node_id());
> if (dev->irq < 0) {
> err = dev->irq;
> -   goto error;
> +   goto err_reset;
> }
> um_pci_devices[free].dev = dev;
> vdev->priv = dev;
> @@ -604,6 +606,9 @@ static int um_pci_virtio_probe(struct virtio_device *vdev)
>
> um_pci_rescan();
> return 0;
> +err_reset:
> +   virtio_reset_device(vdev);
> +   vdev->config->del_vqs(vdev);

This part seems to be an independent fix.

Thanks

>  error:
> mutex_unlock(&um_pci_mtx);
> kfree(dev);
> --
> 2.34.1
>


___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v10 25/41] virtio_pci: struct virtio_pci_common_cfg add queue_notify_data

2022-06-26 Thread Jason Wang
On Fri, Jun 24, 2022 at 2:59 PM Michael S. Tsirkin  wrote:
>
> On Fri, Jun 24, 2022 at 10:56:05AM +0800, Xuan Zhuo wrote:
> > Add queue_notify_data in struct virtio_pci_common_cfg, which comes from
> > here https://github.com/oasis-tcs/virtio-spec/issues/89
> >
> > For not breaks uABI, add a new struct virtio_pci_common_cfg_notify.
>
> What exactly is meant by not breaking uABI?
> Users are supposed to be prepared for struct size to change ... no?

Not sure, any doc for this?

Thanks


>
>
> > Since I want to add queue_reset after queue_notify_data, I submitted
> > this patch first.
> >
> > Signed-off-by: Xuan Zhuo 
> > Acked-by: Jason Wang 
> > ---
> >  include/uapi/linux/virtio_pci.h | 7 +++
> >  1 file changed, 7 insertions(+)
> >
> > diff --git a/include/uapi/linux/virtio_pci.h 
> > b/include/uapi/linux/virtio_pci.h
> > index 3a86f36d7e3d..22bec9bd0dfc 100644
> > --- a/include/uapi/linux/virtio_pci.h
> > +++ b/include/uapi/linux/virtio_pci.h
> > @@ -166,6 +166,13 @@ struct virtio_pci_common_cfg {
> >   __le32 queue_used_hi;   /* read-write */
> >  };
> >
> > +struct virtio_pci_common_cfg_notify {
> > + struct virtio_pci_common_cfg cfg;
> > +
> > + __le16 queue_notify_data;   /* read-write */
> > + __le16 padding;
> > +};
> > +
> >  /* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
> >  struct virtio_pci_cfg_cap {
> >   struct virtio_pci_cap cap;
> > --
> > 2.31.0
>


___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v10 25/41] virtio_pci: struct virtio_pci_common_cfg add queue_notify_data

2022-06-27 Thread Jason Wang
On Mon, Jun 27, 2022 at 2:39 PM Michael S. Tsirkin  wrote:
>
> On Mon, Jun 27, 2022 at 10:30:42AM +0800, Jason Wang wrote:
> > On Fri, Jun 24, 2022 at 2:59 PM Michael S. Tsirkin  wrote:
> > >
> > > On Fri, Jun 24, 2022 at 10:56:05AM +0800, Xuan Zhuo wrote:
> > > > Add queue_notify_data in struct virtio_pci_common_cfg, which comes from
> > > > here https://github.com/oasis-tcs/virtio-spec/issues/89
> > > >
> > > > For not breaks uABI, add a new struct virtio_pci_common_cfg_notify.
> > >
> > > What exactly is meant by not breaking uABI?
> > > Users are supposed to be prepared for struct size to change ... no?
> >
> > Not sure, any doc for this?
> >
> > Thanks
>
>
> Well we have this:
>
> The drivers SHOULD only map part of configuration structure
> large enough for device operation.  The drivers MUST handle
> an unexpectedly large \field{length}, but MAY check that 
> \field{length}
> is large enough for device operation.

Yes, but that's the device/driver interface. What's done here is the
userspace/kernel.

Userspace may break if it uses e.g sizeof(struct virtio_pci_common_cfg)?

Thanks

>
>
>
> >
> > >
> > >
> > > > Since I want to add queue_reset after queue_notify_data, I submitted
> > > > this patch first.
> > > >
> > > > Signed-off-by: Xuan Zhuo 
> > > > Acked-by: Jason Wang 
> > > > ---
> > > >  include/uapi/linux/virtio_pci.h | 7 +++
> > > >  1 file changed, 7 insertions(+)
> > > >
> > > > diff --git a/include/uapi/linux/virtio_pci.h 
> > > > b/include/uapi/linux/virtio_pci.h
> > > > index 3a86f36d7e3d..22bec9bd0dfc 100644
> > > > --- a/include/uapi/linux/virtio_pci.h
> > > > +++ b/include/uapi/linux/virtio_pci.h
> > > > @@ -166,6 +166,13 @@ struct virtio_pci_common_cfg {
> > > >   __le32 queue_used_hi;   /* read-write */
> > > >  };
> > > >
> > > > +struct virtio_pci_common_cfg_notify {
> > > > + struct virtio_pci_common_cfg cfg;
> > > > +
> > > > + __le16 queue_notify_data;   /* read-write */
> > > > + __le16 padding;
> > > > +};
> > > > +
> > > >  /* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
> > > >  struct virtio_pci_cfg_cap {
> > > >   struct virtio_pci_cap cap;
> > > > --
> > > > 2.31.0
> > >
>


___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v10 25/41] virtio_pci: struct virtio_pci_common_cfg add queue_notify_data

2022-06-27 Thread Jason Wang
On Mon, Jun 27, 2022 at 3:58 PM Michael S. Tsirkin  wrote:
>
> On Mon, Jun 27, 2022 at 03:45:30PM +0800, Jason Wang wrote:
> > On Mon, Jun 27, 2022 at 2:39 PM Michael S. Tsirkin  wrote:
> > >
> > > On Mon, Jun 27, 2022 at 10:30:42AM +0800, Jason Wang wrote:
> > > > On Fri, Jun 24, 2022 at 2:59 PM Michael S. Tsirkin  
> > > > wrote:
> > > > >
> > > > > On Fri, Jun 24, 2022 at 10:56:05AM +0800, Xuan Zhuo wrote:
> > > > > > Add queue_notify_data in struct virtio_pci_common_cfg, which comes 
> > > > > > from
> > > > > > here https://github.com/oasis-tcs/virtio-spec/issues/89
> > > > > >
> > > > > > For not breaks uABI, add a new struct virtio_pci_common_cfg_notify.
> > > > >
> > > > > What exactly is meant by not breaking uABI?
> > > > > Users are supposed to be prepared for struct size to change ... no?
> > > >
> > > > Not sure, any doc for this?
> > > >
> > > > Thanks
> > >
> > >
> > > Well we have this:
> > >
> > > The drivers SHOULD only map part of configuration structure
> > > large enough for device operation.  The drivers MUST handle
> > > an unexpectedly large \field{length}, but MAY check that 
> > > \field{length}
> > > is large enough for device operation.
> >
> > Yes, but that's the device/driver interface. What's done here is the
> > userspace/kernel.
> >
> > Userspace may break if it uses e.g sizeof(struct virtio_pci_common_cfg)?
> >
> > Thanks
>
> Hmm I guess there's risk... but then how are we going to maintain this
> going forward?  Add a new struct on any change?

This is the way we have used it for the past 5 or more years. I don't
see why this must be handled in the vq reset feature.

>Can we at least
> prevent this going forward somehow?

Like have some padding?

Thanks

>
>
> > >
> > >
> > >
> > > >
> > > > >
> > > > >
> > > > > > Since I want to add queue_reset after queue_notify_data, I submitted
> > > > > > this patch first.
> > > > > >
> > > > > > Signed-off-by: Xuan Zhuo 
> > > > > > Acked-by: Jason Wang 
> > > > > > ---
> > > > > >  include/uapi/linux/virtio_pci.h | 7 +++
> > > > > >  1 file changed, 7 insertions(+)
> > > > > >
> > > > > > diff --git a/include/uapi/linux/virtio_pci.h 
> > > > > > b/include/uapi/linux/virtio_pci.h
> > > > > > index 3a86f36d7e3d..22bec9bd0dfc 100644
> > > > > > --- a/include/uapi/linux/virtio_pci.h
> > > > > > +++ b/include/uapi/linux/virtio_pci.h
> > > > > > @@ -166,6 +166,13 @@ struct virtio_pci_common_cfg {
> > > > > >   __le32 queue_used_hi;   /* read-write */
> > > > > >  };
> > > > > >
> > > > > > +struct virtio_pci_common_cfg_notify {
> > > > > > + struct virtio_pci_common_cfg cfg;
> > > > > > +
> > > > > > + __le16 queue_notify_data;   /* read-write */
> > > > > > + __le16 padding;
> > > > > > +};
> > > > > > +
> > > > > >  /* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
> > > > > >  struct virtio_pci_cfg_cap {
> > > > > >   struct virtio_pci_cap cap;
> > > > > > --
> > > > > > 2.31.0
> > > > >
> > >
>


___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v10 25/41] virtio_pci: struct virtio_pci_common_cfg add queue_notify_data

2022-06-27 Thread Jason Wang
On Mon, Jun 27, 2022 at 7:53 PM Michael S. Tsirkin  wrote:
>
> On Mon, Jun 27, 2022 at 04:14:20PM +0800, Jason Wang wrote:
> > On Mon, Jun 27, 2022 at 3:58 PM Michael S. Tsirkin  wrote:
> > >
> > > On Mon, Jun 27, 2022 at 03:45:30PM +0800, Jason Wang wrote:
> > > > On Mon, Jun 27, 2022 at 2:39 PM Michael S. Tsirkin  
> > > > wrote:
> > > > >
> > > > > On Mon, Jun 27, 2022 at 10:30:42AM +0800, Jason Wang wrote:
> > > > > > On Fri, Jun 24, 2022 at 2:59 PM Michael S. Tsirkin 
> > > > > >  wrote:
> > > > > > >
> > > > > > > On Fri, Jun 24, 2022 at 10:56:05AM +0800, Xuan Zhuo wrote:
> > > > > > > > Add queue_notify_data in struct virtio_pci_common_cfg, which 
> > > > > > > > comes from
> > > > > > > > here https://github.com/oasis-tcs/virtio-spec/issues/89
> > > > > > > >
> > > > > > > > For not breaks uABI, add a new struct 
> > > > > > > > virtio_pci_common_cfg_notify.
> > > > > > >
> > > > > > > What exactly is meant by not breaking uABI?
> > > > > > > Users are supposed to be prepared for struct size to change ... 
> > > > > > > no?
> > > > > >
> > > > > > Not sure, any doc for this?
> > > > > >
> > > > > > Thanks
> > > > >
> > > > >
> > > > > Well we have this:
> > > > >
> > > > > The drivers SHOULD only map part of configuration structure
> > > > > large enough for device operation.  The drivers MUST handle
> > > > > an unexpectedly large \field{length}, but MAY check that 
> > > > > \field{length}
> > > > > is large enough for device operation.
> > > >
> > > > Yes, but that's the device/driver interface. What's done here is the
> > > > userspace/kernel.
> > > >
> > > > Userspace may break if it uses e.g sizeof(struct virtio_pci_common_cfg)?
> > > >
> > > > Thanks
> > >
> > > Hmm I guess there's risk... but then how are we going to maintain this
> > > going forward?  Add a new struct on any change?
> >
> > This is the way we have used it for the past 5 or more years. I don't
> > see why this must be handled in the vq reset feature.
> >
> > >Can we at least
> > > prevent this going forward somehow?
> >
> > Like have some padding?
> >
> > Thanks
>
> Maybe - this is what QEMU does ...

Do you want this to be addressed in this series (it's already very huge anyhow)?

Thanks

>
> > >
> > >
> > > > >
> > > > >
> > > > >
> > > > > >
> > > > > > >
> > > > > > >
> > > > > > > > Since I want to add queue_reset after queue_notify_data, I 
> > > > > > > > submitted
> > > > > > > > this patch first.
> > > > > > > >
> > > > > > > > Signed-off-by: Xuan Zhuo 
> > > > > > > > Acked-by: Jason Wang 
> > > > > > > > ---
> > > > > > > >  include/uapi/linux/virtio_pci.h | 7 +++
> > > > > > > >  1 file changed, 7 insertions(+)
> > > > > > > >
> > > > > > > > diff --git a/include/uapi/linux/virtio_pci.h 
> > > > > > > > b/include/uapi/linux/virtio_pci.h
> > > > > > > > index 3a86f36d7e3d..22bec9bd0dfc 100644
> > > > > > > > --- a/include/uapi/linux/virtio_pci.h
> > > > > > > > +++ b/include/uapi/linux/virtio_pci.h
> > > > > > > > @@ -166,6 +166,13 @@ struct virtio_pci_common_cfg {
> > > > > > > >   __le32 queue_used_hi;   /* read-write */
> > > > > > > >  };
> > > > > > > >
> > > > > > > > +struct virtio_pci_common_cfg_notify {
> > > > > > > > + struct virtio_pci_common_cfg cfg;
> > > > > > > > +
> > > > > > > > + __le16 queue_notify_data;   /* read-write */
> > > > > > > > + __le16 padding;
> > > > > > > > +};
> > > > > > > > +
> > > > > > > >  /* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
> > > > > > > >  struct virtio_pci_cfg_cap {
> > > > > > > >   struct virtio_pci_cap cap;
> > > > > > > > --
> > > > > > > > 2.31.0
> > > > > > >
> > > > >
> > >
>


___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v10 25/41] virtio_pci: struct virtio_pci_common_cfg add queue_notify_data

2022-06-27 Thread Jason Wang
On Tue, Jun 28, 2022 at 1:46 PM Michael S. Tsirkin  wrote:
>
> On Tue, Jun 28, 2022 at 11:50:37AM +0800, Jason Wang wrote:
> > On Mon, Jun 27, 2022 at 7:53 PM Michael S. Tsirkin  wrote:
> > >
> > > On Mon, Jun 27, 2022 at 04:14:20PM +0800, Jason Wang wrote:
> > > > On Mon, Jun 27, 2022 at 3:58 PM Michael S. Tsirkin  
> > > > wrote:
> > > > >
> > > > > On Mon, Jun 27, 2022 at 03:45:30PM +0800, Jason Wang wrote:
> > > > > > On Mon, Jun 27, 2022 at 2:39 PM Michael S. Tsirkin 
> > > > > >  wrote:
> > > > > > >
> > > > > > > On Mon, Jun 27, 2022 at 10:30:42AM +0800, Jason Wang wrote:
> > > > > > > > On Fri, Jun 24, 2022 at 2:59 PM Michael S. Tsirkin 
> > > > > > > >  wrote:
> > > > > > > > >
> > > > > > > > > On Fri, Jun 24, 2022 at 10:56:05AM +0800, Xuan Zhuo wrote:
> > > > > > > > > > Add queue_notify_data in struct virtio_pci_common_cfg, 
> > > > > > > > > > which comes from
> > > > > > > > > > here https://github.com/oasis-tcs/virtio-spec/issues/89
> > > > > > > > > >
> > > > > > > > > > For not breaks uABI, add a new struct 
> > > > > > > > > > virtio_pci_common_cfg_notify.
> > > > > > > > >
> > > > > > > > > What exactly is meant by not breaking uABI?
> > > > > > > > > Users are supposed to be prepared for struct size to change 
> > > > > > > > > ... no?
> > > > > > > >
> > > > > > > > Not sure, any doc for this?
> > > > > > > >
> > > > > > > > Thanks
> > > > > > >
> > > > > > >
> > > > > > > Well we have this:
> > > > > > >
> > > > > > > The drivers SHOULD only map part of configuration 
> > > > > > > structure
> > > > > > > large enough for device operation.  The drivers MUST 
> > > > > > > handle
> > > > > > > an unexpectedly large \field{length}, but MAY check that 
> > > > > > > \field{length}
> > > > > > > is large enough for device operation.
> > > > > >
> > > > > > Yes, but that's the device/driver interface. What's done here is the
> > > > > > userspace/kernel.
> > > > > >
> > > > > > Userspace may break if it uses e.g sizeof(struct 
> > > > > > virtio_pci_common_cfg)?
> > > > > >
> > > > > > Thanks
> > > > >
> > > > > Hmm I guess there's risk... but then how are we going to maintain this
> > > > > going forward?  Add a new struct on any change?
> > > >
> > > > This is the way we have used it for the past 5 or more years. I don't
> > > > see why this must be handled in the vq reset feature.
> > > >
> > > > >Can we at least
> > > > > prevent this going forward somehow?
> > > >
> > > > Like have some padding?
> > > >
> > > > Thanks
> > >
> > > Maybe - this is what QEMU does ...
> >
> > Do you want this to be addressed in this series (it's already very huge 
> > anyhow)?
> >
> > Thanks
>
> Let's come up with a solution at least. QEMU does not seem to need the struct.

If we want to implement it in Qemu we need that:

https://github.com/fengidri/qemu/commit/39b79335cb55144d11a3b01f93d46cc73342c6bb

> Let's just put
> it in virtio_pci_modern.h for now then?

Does this mean userspace needs to define the struct by their own
instead of depending on the uapi in the future?

Thanks

>
> > >
> > > > >
> > > > >
> > > > > > >
> > > > > > >
> > > > > > >
> > > > > > > >
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > > Since I want to add queue_reset after queue_notify_data, I 
> > > > > > > > > > submitted
> > > > > > > > > > this patch first.
> > > > > > > > > >
> > > > > > > > > > Signed-off-by: Xuan Zhuo 
> > > > > > > > > > Acked-by: Jason Wang 
> > > > > > > > > > ---
> > > > > > > > > >  include/uapi/linux/virtio_pci.h | 7 +++
> > > > > > > > > >  1 file changed, 7 insertions(+)
> > > > > > > > > >
> > > > > > > > > > diff --git a/include/uapi/linux/virtio_pci.h 
> > > > > > > > > > b/include/uapi/linux/virtio_pci.h
> > > > > > > > > > index 3a86f36d7e3d..22bec9bd0dfc 100644
> > > > > > > > > > --- a/include/uapi/linux/virtio_pci.h
> > > > > > > > > > +++ b/include/uapi/linux/virtio_pci.h
> > > > > > > > > > @@ -166,6 +166,13 @@ struct virtio_pci_common_cfg {
> > > > > > > > > >   __le32 queue_used_hi;   /* read-write */
> > > > > > > > > >  };
> > > > > > > > > >
> > > > > > > > > > +struct virtio_pci_common_cfg_notify {
> > > > > > > > > > + struct virtio_pci_common_cfg cfg;
> > > > > > > > > > +
> > > > > > > > > > + __le16 queue_notify_data;   /* read-write */
> > > > > > > > > > + __le16 padding;
> > > > > > > > > > +};
> > > > > > > > > > +
> > > > > > > > > >  /* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
> > > > > > > > > >  struct virtio_pci_cfg_cap {
> > > > > > > > > >   struct virtio_pci_cap cap;
> > > > > > > > > > --
> > > > > > > > > > 2.31.0
> > > > > > > > >
> > > > > > >
> > > > >
> > >
>


___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v10 25/41] virtio_pci: struct virtio_pci_common_cfg add queue_notify_data

2022-06-27 Thread Jason Wang
On Tue, Jun 28, 2022 at 2:10 PM Michael S. Tsirkin  wrote:
>
> On Tue, Jun 28, 2022 at 02:07:28PM +0800, Jason Wang wrote:
> > On Tue, Jun 28, 2022 at 1:46 PM Michael S. Tsirkin  wrote:
> > >
> > > On Tue, Jun 28, 2022 at 11:50:37AM +0800, Jason Wang wrote:
> > > > On Mon, Jun 27, 2022 at 7:53 PM Michael S. Tsirkin  
> > > > wrote:
> > > > >
> > > > > On Mon, Jun 27, 2022 at 04:14:20PM +0800, Jason Wang wrote:
> > > > > > On Mon, Jun 27, 2022 at 3:58 PM Michael S. Tsirkin 
> > > > > >  wrote:
> > > > > > >
> > > > > > > On Mon, Jun 27, 2022 at 03:45:30PM +0800, Jason Wang wrote:
> > > > > > > > On Mon, Jun 27, 2022 at 2:39 PM Michael S. Tsirkin 
> > > > > > > >  wrote:
> > > > > > > > >
> > > > > > > > > On Mon, Jun 27, 2022 at 10:30:42AM +0800, Jason Wang wrote:
> > > > > > > > > > On Fri, Jun 24, 2022 at 2:59 PM Michael S. Tsirkin 
> > > > > > > > > >  wrote:
> > > > > > > > > > >
> > > > > > > > > > > On Fri, Jun 24, 2022 at 10:56:05AM +0800, Xuan Zhuo wrote:
> > > > > > > > > > > > Add queue_notify_data in struct virtio_pci_common_cfg, 
> > > > > > > > > > > > which comes from
> > > > > > > > > > > > here https://github.com/oasis-tcs/virtio-spec/issues/89
> > > > > > > > > > > >
> > > > > > > > > > > > For not breaks uABI, add a new struct 
> > > > > > > > > > > > virtio_pci_common_cfg_notify.
> > > > > > > > > > >
> > > > > > > > > > > What exactly is meant by not breaking uABI?
> > > > > > > > > > > Users are supposed to be prepared for struct size to 
> > > > > > > > > > > change ... no?
> > > > > > > > > >
> > > > > > > > > > Not sure, any doc for this?
> > > > > > > > > >
> > > > > > > > > > Thanks
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > Well we have this:
> > > > > > > > >
> > > > > > > > > The drivers SHOULD only map part of configuration 
> > > > > > > > > structure
> > > > > > > > > large enough for device operation.  The drivers MUST 
> > > > > > > > > handle
> > > > > > > > > an unexpectedly large \field{length}, but MAY check 
> > > > > > > > > that \field{length}
> > > > > > > > > is large enough for device operation.
> > > > > > > >
> > > > > > > > Yes, but that's the device/driver interface. What's done here 
> > > > > > > > is the
> > > > > > > > userspace/kernel.
> > > > > > > >
> > > > > > > > Userspace may break if it uses e.g sizeof(struct 
> > > > > > > > virtio_pci_common_cfg)?
> > > > > > > >
> > > > > > > > Thanks
> > > > > > >
> > > > > > > Hmm I guess there's risk... but then how are we going to maintain 
> > > > > > > this
> > > > > > > going forward?  Add a new struct on any change?
> > > > > >
> > > > > > This is the way we have used it for the past 5 or more years. I 
> > > > > > don't
> > > > > > see why this must be handled in the vq reset feature.
> > > > > >
> > > > > > >Can we at least
> > > > > > > prevent this going forward somehow?
> > > > > >
> > > > > > Like have some padding?
> > > > > >
> > > > > > Thanks
> > > > >
> > > > > Maybe - this is what QEMU does ...
> > > >
> > > > Do you want this to be addressed in this series (it's already very huge 
> > > > anyhow)?
> > > >
> > > > Thanks
> > >
> > > Let's come up with a solution at leas

Re: [PATCH v11 01/40] virtio: add helper virtqueue_get_vring_max_size()

2022-06-29 Thread Jason Wang
On Wed, Jun 29, 2022 at 2:57 PM Xuan Zhuo  wrote:
>
> Record the maximum queue num supported by the device.
>
> virtio-net can display the maximum (supported by hardware) ring size in
> ethtool -g eth0.
>
> When the subsequent patch implements vring reset, it can judge whether
> the ring size passed by the driver is legal based on this.
>
> Signed-off-by: Xuan Zhuo 
> ---
>  arch/um/drivers/virtio_uml.c |  1 +
>  drivers/platform/mellanox/mlxbf-tmfifo.c |  2 ++
>  drivers/remoteproc/remoteproc_virtio.c   |  2 ++
>  drivers/s390/virtio/virtio_ccw.c |  3 +++
>  drivers/virtio/virtio_mmio.c |  2 ++
>  drivers/virtio/virtio_pci_legacy.c   |  2 ++
>  drivers/virtio/virtio_pci_modern.c   |  2 ++
>  drivers/virtio/virtio_ring.c | 14 ++
>  drivers/virtio/virtio_vdpa.c |  2 ++
>  include/linux/virtio.h   |  2 ++
>  10 files changed, 32 insertions(+)
>
> diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
> index 82ff3785bf69..e719af8bdf56 100644
> --- a/arch/um/drivers/virtio_uml.c
> +++ b/arch/um/drivers/virtio_uml.c
> @@ -958,6 +958,7 @@ static struct virtqueue *vu_setup_vq(struct virtio_device 
> *vdev,
> goto error_create;
> }
> vq->priv = info;
> +   vq->num_max = num;
> num = virtqueue_get_vring_size(vq);
>
> if (vu_dev->protocol_features &
> diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c 
> b/drivers/platform/mellanox/mlxbf-tmfifo.c
> index 38800e86ed8a..1ae3c56b66b0 100644
> --- a/drivers/platform/mellanox/mlxbf-tmfifo.c
> +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
> @@ -959,6 +959,8 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct 
> virtio_device *vdev,
> goto error;
> }
>
> +   vq->num_max = vring->num;
> +
> vqs[i] = vq;
> vring->vq = vq;
> vq->priv = vring;
> diff --git a/drivers/remoteproc/remoteproc_virtio.c 
> b/drivers/remoteproc/remoteproc_virtio.c
> index d43d74733f0a..0f7706e23eb9 100644
> --- a/drivers/remoteproc/remoteproc_virtio.c
> +++ b/drivers/remoteproc/remoteproc_virtio.c
> @@ -125,6 +125,8 @@ static struct virtqueue *rp_find_vq(struct virtio_device 
> *vdev,
> return ERR_PTR(-ENOMEM);
> }
>
> +   vq->num_max = num;
> +
> rvring->vq = vq;
> vq->priv = rvring;
>
> diff --git a/drivers/s390/virtio/virtio_ccw.c 
> b/drivers/s390/virtio/virtio_ccw.c
> index 161d3b141f0d..6b86d0280d6b 100644
> --- a/drivers/s390/virtio/virtio_ccw.c
> +++ b/drivers/s390/virtio/virtio_ccw.c
> @@ -530,6 +530,9 @@ static struct virtqueue *virtio_ccw_setup_vq(struct 
> virtio_device *vdev,
> err = -ENOMEM;
> goto out_err;
> }
> +
> +   vq->num_max = info->num;
> +
> /* it may have been reduced */
> info->num = virtqueue_get_vring_size(vq);
>
> diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
> index 083ff1eb743d..a20d5a6b5819 100644
> --- a/drivers/virtio/virtio_mmio.c
> +++ b/drivers/virtio/virtio_mmio.c
> @@ -403,6 +403,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device 
> *vdev, unsigned int in
> goto error_new_virtqueue;
> }
>
> +   vq->num_max = num;
> +
> /* Activate the queue */
> writel(virtqueue_get_vring_size(vq), vm_dev->base + 
> VIRTIO_MMIO_QUEUE_NUM);
> if (vm_dev->version == 1) {
> diff --git a/drivers/virtio/virtio_pci_legacy.c 
> b/drivers/virtio/virtio_pci_legacy.c
> index a5e5721145c7..2257f1b3d8ae 100644
> --- a/drivers/virtio/virtio_pci_legacy.c
> +++ b/drivers/virtio/virtio_pci_legacy.c
> @@ -135,6 +135,8 @@ static struct virtqueue *setup_vq(struct 
> virtio_pci_device *vp_dev,
> if (!vq)
> return ERR_PTR(-ENOMEM);
>
> +   vq->num_max = num;
> +
> q_pfn = virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
> if (q_pfn >> 32) {
> dev_err(&vp_dev->pci_dev->dev,
> diff --git a/drivers/virtio/virtio_pci_modern.c 
> b/drivers/virtio/virtio_pci_modern.c
> index 623906b4996c..e7e0b8c850f6 100644
> --- a/drivers/virtio/virtio_pci_modern.c
> +++ b/drivers/virtio/virtio_pci_modern.c
> @@ -218,6 +218,8 @@ static struct virtqueue *setup_vq(struct 
> virtio_pci_device *vp_dev,
> if (!vq)
> return ERR_PTR(-ENOMEM);
>
> +   vq->num_max = num;
> +
> /* activate the queue */
> vp_modern_set_queue_size(mdev, index, virtqueue_get_vring_size(vq));
> vp_modern_queue_address(mdev, index, virtqueue_get_desc_addr(vq),
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index a5ec724c01d8..4cac600856ad 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -2385,6 +2385,20 @@ void vring_transport_features(struct virtio_device 
> *vdev)
>  }
>  EXPORT_SYMBOL_GPL(vring_transport_feature

Re: [PATCH v11 02/40] virtio: struct virtio_config_ops add callbacks for queue_reset

2022-06-29 Thread Jason Wang
On Wed, Jun 29, 2022 at 2:57 PM Xuan Zhuo  wrote:
>
> reset can be divided into the following four steps (example):
>  1. transport: notify the device to reset the queue
>  2. vring: recycle the buffer submitted
>  3. vring: reset/resize the vring (may re-alloc)
>  4. transport: mmap vring to device, and enable the queue
>
> In order to support queue reset, add two callbacks(reset_vq,
> enable_reset_vq) in struct virtio_config_ops to implement steps 1 and 4.
>
> Signed-off-by: Xuan Zhuo 
> ---
>  include/linux/virtio_config.h | 12 
>  1 file changed, 12 insertions(+)
>
> diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
> index b47c2e7ed0ee..ded51b0d4823 100644
> --- a/include/linux/virtio_config.h
> +++ b/include/linux/virtio_config.h
> @@ -78,6 +78,16 @@ struct virtio_shm_region {
>   * @set_vq_affinity: set the affinity for a virtqueue (optional).
>   * @get_vq_affinity: get the affinity for a virtqueue (optional).
>   * @get_shm_region: get a shared memory region based on the index.
> + * @reset_vq: reset a queue individually (optional).
> + * vq: the virtqueue
> + * Returns 0 on success or error status
> + * reset_vq will guarantee that the callbacks are disabled and 
> synchronized.
> + * Except for the callback, the caller should guarantee that the vring is
> + * not accessed by any functions of virtqueue.
> + * @enable_reset_vq: enable a reset queue
> + * vq: the virtqueue
> + * Returns 0 on success or error status
> + * If reset_vq is set, then enable_reset_vq must also be set.
>   */
>  typedef void vq_callback_t(struct virtqueue *);
>  struct virtio_config_ops {
> @@ -104,6 +114,8 @@ struct virtio_config_ops {
> int index);
> bool (*get_shm_region)(struct virtio_device *vdev,
>struct virtio_shm_region *region, u8 id);
> +   int (*reset_vq)(struct virtqueue *vq);
> +   int (*enable_reset_vq)(struct virtqueue *vq);

I wonder if a single op with a boolean parameter is sufficient here.

Thanks

>  };
>
>  /* If driver didn't advertise the feature, it will never appear. */
> --
> 2.31.0
>


___
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


Re: [PATCH v11 05/40] virtio_ring: split vring_virtqueue

2022-06-29 Thread Jason Wang
On Wed, Jun 29, 2022 at 2:57 PM Xuan Zhuo  wrote:
>
> Separate the two inline structures(split and packed) from the structure
> vring_virtqueue.
>
> In this way, we can use these two structures later to pass parameters
> and retain temporary variables.
>
> Signed-off-by: Xuan Zhuo 

Acked-by: Jason Wang 

> ---
>  drivers/virtio/virtio_ring.c | 116 ++-
>  1 file changed, 60 insertions(+), 56 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index bb4e8ae09c9b..2806e033a651 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -85,6 +85,64 @@ struct vring_desc_extra {
> u16 next;   /* The next desc state in a list. */
>  };
>
> +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;
> +};
> +
> +struct vring_virtqueue_packed {
> +   /* Actual memory layout for this queue. */
> +   struct {
> +   unsigned int num;
> +   struct vring_packed_desc *desc;
> +   struct vring_packed_desc_event *driver;
> +   struct vring_packed_desc_event *device;
> +   } vring;
> +
> +   /* Driver ring wrap counter. */
> +   bool avail_wrap_counter;
> +
> +   /* Avail used flags. */
> +   u16 avail_used_flags;
> +
> +   /* Index of the next avail descriptor. */
> +   u16 next_avail_idx;
> +
> +   /*
> +* Last written value to driver->flags in
> +* guest byte order.
> +*/
> +   u16 event_flags_shadow;
> +
> +   /* Per-descriptor state. */
> +   struct vring_desc_state_packed *desc_state;
> +   struct vring_desc_extra *desc_extra;
> +
> +   /* DMA address and size information */
> +   dma_addr_t ring_dma_addr;
> +   dma_addr_t driver_event_dma_addr;
> +   dma_addr_t device_event_dma_addr;
> +   size_t ring_size_in_bytes;
> +   size_t event_size_in_bytes;
> +};
> +
>  struct vring_virtqueue {
> struct virtqueue vq;
>
> @@ -124,64 +182,10 @@ struct vring_virtqueue {
>
> union {
> /* Available for split ring */
> -   struct {
> -   /* 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;
> -   } split;
> +   struct vring_virtqueue_split split;
>
> /* Available for packed ring */
> -   struct {
> -   /* Actual memory layout for this queue. */
> -   struct {
> -   unsigned int num;
> -   struct vring_packed_desc *desc;
> -   struct vring_packed_desc_event *driver;
> -   struct vring_packed_desc_event *device;
> -   } vring;
> -
> -   /* Driver ring wrap counter. */
> -   bool avail_wrap_counter;
> -
> -   /* Avail used flags. */
> -   u16 avail_used_flags;
> -
> -   /* Index of the next avail descriptor. */
> -   u16 next_avail_idx;
> -
> -   /*
> -* Last written value to driver->flags in
> -* 

  1   2   >