On 5/4/26 6:16 PM, [email protected] wrote:
> From: Jared Rossi <[email protected]>
> 
> The initial support for virtio-blk-pci IPL devices used a single virt-queue, 
> but
> other device types require multiple queues, and for PCI device types this also
> requires a per-queue notification offset.
> 
> Add a PCI notify field to the VRing struct so that each queue has a unique
> notify offset.  Also re-select the target queue before writing buffers to
> ensure the proper queue is active.
> 
> Signed-off-by: Jared Rossi <[email protected]>
> ---
>  pc-bios/s390-ccw/virtio-pci.c | 36 ++++++++++++++++++++++-------------
>  pc-bios/s390-ccw/virtio-pci.h |  3 ++-
>  pc-bios/s390-ccw/virtio.c     |  4 +++-
>  pc-bios/s390-ccw/virtio.h     |  1 +
>  4 files changed, 29 insertions(+), 15 deletions(-)
> 
> diff --git a/pc-bios/s390-ccw/virtio-pci.c b/pc-bios/s390-ccw/virtio-pci.c
> index 53bdb52e76..736869f4f5 100644
> --- a/pc-bios/s390-ccw/virtio-pci.c
> +++ b/pc-bios/s390-ccw/virtio-pci.c
> @@ -74,10 +74,10 @@ int virtio_pci_reset(VDev *vdev)
>      return 0;
>  }
>  
> -long virtio_pci_notify(int vq_id)
> +long virtio_pci_notify(VRing *vr)
>  {
> -    uint32_t offset = n_cap.off + notify_mult * q_notify_offset;
> -    return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vq_id);
> +    uint32_t offset = n_cap.off + notify_mult * vr->pci_notify;
> +    return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vr->id);
>  }
>  
>  /*
> @@ -166,7 +166,7 @@ int vpci_read_flex(uint64_t offset, uint8_t pcias, void 
> *buf, int len)
>      return 0;
>  }
>  
> -static int vpci_set_selected_vq(uint16_t queue_num)
> +int vpci_set_selected_vq(uint16_t queue_num)
>  {
>      return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_SELECT, c_cap.bar, 
> queue_num);
>  }
> @@ -332,7 +332,6 @@ int virtio_pci_setup(VDev *vdev)
>      VRing *vr;
>      int rc;
>      uint8_t status;
> -    uint16_t vq_size;
>      int i = 0;
>  
>      vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
> @@ -380,28 +379,39 @@ int virtio_pci_setup(VDev *vdev)
>          return -EIO;
>      }
>  
> -    if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
> -        puts("Failed to read virt-queue configuration");
> -        return -EIO;
> -    }
> -
>      /* Configure virt-queues for pci */
>      for (i = 0; i < vdev->nr_vqs; i++) {
> +        uint16_t vq_size;
> +        uint16_t vq_notify;
>          VqInfo info = {
>              .queue = (unsigned long long) virtio_get_ring_area(i),
>              .align = KVM_S390_VIRTIO_RING_ALIGN,
>              .index = i,
> -            .num = vq_size,
> +            .num = 0,
>          };
>  
>          vr = &vdev->vrings[i];
> -        vring_init(vr, &info);
>  
> -        if (vpci_set_selected_vq(vr->id)) {
> +        if (vpci_set_selected_vq(i)) {
>              puts("Failed to set selected virt-queue");
>              return -EIO;
>          }
>  
> +        if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {

Small nit: c_cap.off + VPCI_C_OFFSET_Q_SIZE

> +            puts("Failed to read virt-queue configuration");
> +            return -EIO;
> +        }
> +
> +        info.num = vq_size;
> +
> +        if (vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar, 
> &vq_notify)) {
> +            puts("Failed to read virt-queue configuration");
> +            return -EIO;
> +        }

Since the notification offset is now read per queue, should we remove
the same read in virtio_pci_read_pci_cap_config() as well as the global
q_notify_offset variable?

if (rc || vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar,
&q_notify_offset))

> +
> +        vr->pci_notify = vq_notify;
> +        vring_init(vr, &info);
> +
>          rc = set_pci_vq_addr(VPCI_C_OFFSET_Q_DESCLO, vr->desc);
>          rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_AVAILLO, vr->avail);
>          rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_USEDLO, vr->used);
> diff --git a/pc-bios/s390-ccw/virtio-pci.h b/pc-bios/s390-ccw/virtio-pci.h
> index 90d07cb9a7..993fc285ac 100644
> --- a/pc-bios/s390-ccw/virtio-pci.h
> +++ b/pc-bios/s390-ccw/virtio-pci.h
> @@ -62,9 +62,10 @@ struct VirtioPciCap {
>  };
>  typedef struct VirtioPciCap  VirtioPciCap;
>  
> +int vpci_set_selected_vq(uint16_t queue_num);
>  void virtio_pci_id2type(VDev *vdev, uint16_t device_id);
>  int virtio_pci_reset(VDev *vdev);
> -long virtio_pci_notify(int vq_id);
> +long virtio_pci_notify(VRing *vr);
>  int virtio_pci_setup(VDev *vdev);
>  int virtio_pci_setup_device(void);
>  
> diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
> index 30e6b2bc16..00850acc2f 100644
> --- a/pc-bios/s390-ccw/virtio.c
> +++ b/pc-bios/s390-ccw/virtio.c
> @@ -114,7 +114,8 @@ bool vring_notify(VRing *vr)
>          vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
>          break;
>      case S390_IPL_TYPE_PCI:
> -        vr->cookie = virtio_pci_notify(vr->id);
> +        vr->cookie = virtio_pci_notify(vr);
> +        break;
>      default:
>          return 1;
>      }
> @@ -154,6 +155,7 @@ static void vr_bswap_descriptor(VRingDesc *desc)
>  void vring_send_buf(VRing *vr, void *p, int len, int flags)
>  {
>      if (!be_ipl()) {
> +        vpci_set_selected_vq(vr->id);
>          vr->avail->idx = bswap16(vr->avail->idx);
>      }
>  
> diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
> index d32a4830ca..75ae5bdbc2 100644
> --- a/pc-bios/s390-ccw/virtio.h
> +++ b/pc-bios/s390-ccw/virtio.h
> @@ -107,6 +107,7 @@ struct VRing {
>      VRingUsed *used;
>      long cookie;
>      int id;
> +    uint16_t pci_notify;
>  };
>  typedef struct VRing VRing;
>  


Reply via email to