On 5/8/26 1:23 PM, Eric Farman wrote:
On Mon, 2026-05-04 at 18:16 -0400, [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.
Why is this patch 2/5, when the series is n/6?
The short answer is I goofed it up. The contents of the patch are as
intended.
It should be 2/6.
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);
You no longer need the q_notify_offset variable nor the read into it.
(Ah, Joy already pointed this out; nice!)
}
/*
@@ -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)) {
+ 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;
+ }
For either of these error exits, do you need an identifier logged as to -which-
virtqueue failed, as
you're in a loop?
Yes, that would certainly be useful information to have. I'll add it.
+
+ 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;
Thank you for the review comments.
Regards,
Jared Rossi