pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations

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 as defined in the virtio spec.

Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Eric Farman <farman@linux.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Message-ID: <20260630141917.673995-4-jrossi@linux.ibm.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
Zhuoying Cai
2026-06-30 10:19:14 -04:00
committed by Cornelia Huck
parent 730173107a
commit 084feb9098
4 changed files with 26 additions and 17 deletions

View File

@@ -21,7 +21,6 @@ VirtioPciCap c_cap; /* Common capabilities */
VirtioPciCap d_cap; /* Device capabilities */
VirtioPciCap n_cap; /* Notify capabilities */
uint32_t notify_mult;
uint16_t q_notify_offset;
static int virtio_pci_set_status(uint8_t status)
{
@@ -74,10 +73,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);
}
/*
@@ -301,8 +300,7 @@ static int virtio_pci_read_pci_cap_config(void)
}
rc = vpci_read_bswap32(pos + VPCI_N_CAP_MULT, PCI_CFGBAR, &notify_mult);
if (rc || vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar,
&q_notify_offset)) {
if (rc) {
puts("Failed to read notification queue configuration");
return -EIO;
}
@@ -332,7 +330,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 +377,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(c_cap.off + VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
printf("Failed to read virt-queue %d size\n", i);
return -EIO;
}
info.num = vq_size;
if (vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar, &vq_notify)) {
printf("Failed to read virt-queue %d notify offset\n", i);
return -EIO;
}
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);

View File

@@ -64,7 +64,7 @@ typedef struct VirtioPciCap VirtioPciCap;
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);

View File

@@ -114,7 +114,7 @@ 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;

View File

@@ -107,6 +107,7 @@ struct VRing {
VRingUsed *used;
long cookie;
int id;
uint16_t pci_notify;
};
typedef struct VRing VRing;