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;
>