On Thu, Feb 05, 2026 at 03:43:10PM -0800, Farhan Ali wrote:
> <...snip...>
> 
> On 1/27/2026 8:15 AM, [email protected] wrote:
> > int virtio_pci_setup(VDev *vdev)
> > +{
> > +    VRing *vr;
> > +    int rc;
> > +    uint8_t status;
> > +    int i = 0;
> > +
> > +    vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
> > +    vdev->cmd_vr_idx = 0;
> > +
> > +    if (virtio_reset(vdev)) {
> > +        return -EIO;
> > +    }
> > +
> > +    status = VPCI_S_ACKNOWLEDGE;
> > +    if (virtio_pci_set_status(status)) {
> > +        puts("Virtio-pci device Failed to ACKNOWLEDGE");
> > +        return -EIO;
> > +    }
> > +
> > +    rc = virtio_pci_read_pci_cap_config();
> > +    if (rc) {
> > +        puts("Invalid virtio PCI capabilities");
> > +        return -EIO;
> > +    }
> > +
> > +    vdev->guest_features[1] = VIRTIO_F_VERSION_1;
> > +    if (virtio_pci_negotiate()) {
> > +        panic("Virtio feature negotation failed!");
> > +    }
> > +
> > +    switch (vdev->dev_type) {
> > +    case VIRTIO_ID_BLOCK:
> > +        vdev->nr_vqs = 1;
> > +        vdev->cmd_vr_idx = 0;
> > +        vdev->config.blk.blk_size = 0;
> > +        virtio_pci_get_blk_config();
> > +        break;
> > +    default:
> > +        puts("Unsupported virtio device");
> > +        return -ENODEV;
> > +    }
> > +
> > +    status |= VPCI_S_DRIVER;
> > +    rc = virtio_pci_set_status(status);
> > +    if (rc) {
> > +        puts("Set status failed");
> > +        return -EIO;
> > +    }
> > +
> > +    /* Configure virt-queues for pci */
> > +    for (i = 0; i < vdev->nr_vqs; i++) {
> > +        VqInfo info = {
> > +            .queue = (unsigned long long) virtio_get_ring_area(i),
> > +            .align = KVM_S390_VIRTIO_RING_ALIGN,
> > +            .index = i,
> > +            .num = 0,
> > +        };
> > +
> > +        vr = &vdev->vrings[i];
> > +
> > +        if (vpci_read_flex(VPCI_C_COMMON_NUMQ, c_cap.bar, &info.num, 2)) {
> > +            return -EIO;
> > +        }
> > +
> > +        vring_init(vr, &info);
> > +
> > +        if (vpci_set_selected_vq(vr->id)) {
> > +            puts("Failed to set selected virt-queue");
> > +            return -EIO;
> > +        }
> > +
> > +        if (vpci_set_queue_size(VIRTIO_RING_SIZE)) {
> > +            puts("Failed to set virt-queue size");
> > +            return -EIO;
> > +        }
> > +
> > +        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);
> > +        if (rc) {
> > +            puts("Failed to configure virt-queue address");
> > +            return -EIO;
> > +        }
> > +
> > +        if (vpci_set_queue_enable(true)) {
> > +            puts("Failed to set virt-queue enabled");
> > +            return -EIO;
> > +        }
> > +    }
> > +
> > +    status |= VPCI_S_FEATURES_OK | VPCI_S_DRIVER_OK;
> > +    return virtio_pci_set_status(status);
> 
> Should we also enable Bus master bit as part of the device setup? QEMU
> though has a workaround where if we have setup the ACKNOWLEDGE and DRIVER
> status flags set then it would enable the Bus master by default since older
> Linux virtio-pci drivers didn't do it 
> (https://github.com/qemu/qemu/blob/cd5a79dc98e3087e7658e643bdbbb0baec77ac8a/hw/virtio/virtio-pci.c#L480-L487).
> But latest virtio-pci drivers seems to be doing the right thing, so not sure
> how long this workaround would be supported :) .
> 

Please do. linux 2.6.x is ancient and there's no guarantee we will keep
supporting this indefinitely.


> > +}
> > +
> 
> <..snip..>
> 
> 
> > diff --git a/pc-bios/s390-ccw/virtio-pci.h b/pc-bios/s390-ccw/virtio-pci.h
> > index 96c17ac3c7..883b00e0c6 100644
> > --- a/pc-bios/s390-ccw/virtio-pci.h
> > +++ b/pc-bios/s390-ccw/virtio-pci.h
> > @@ -71,6 +71,8 @@ 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);
> > +int virtio_pci_setup(VDev *vdev);
> > +int virtio_pci_setup_device(void);
> >   int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len);
> >   int vpci_read_bswap64(uint64_t offset, uint8_t pcias, uint64_t *buf);
> > diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
> > index 956b34ff33..f65571a920 100644
> > --- a/pc-bios/s390-ccw/virtio.c
> > +++ b/pc-bios/s390-ccw/virtio.c
> > @@ -17,6 +17,7 @@
> >   #include "virtio.h"
> >   #include "virtio-scsi.h"
> >   #include "virtio-ccw.h"
> > +#include "virtio-pci.h"
> >   #include "bswap.h"
> >   #include "helper.h"
> >   #include "s390-time.h"
> > @@ -112,6 +113,8 @@ bool vring_notify(VRing *vr)
> >       case S390_IPL_TYPE_CCW:
> >           vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
> >           break;
> > +    case S390_IPL_TYPE_PCI:
> > +        vr->cookie = virtio_pci_notify(vr->id);
> >       default:
> >           return 1;
> >       }
> > @@ -119,8 +122,43 @@ bool vring_notify(VRing *vr)
> >       return vr->cookie >= 0;
> >   }
> > +/*
> > + * Get endienness of the IPL type
> > + * Return true for s390x native big-endian
> > + */
> > +bool be_ipl(void)
> > +{
> > +    switch (virtio_get_device()->ipl_type) {
> > +    case S390_IPL_TYPE_QEMU_SCSI:
> > +    case S390_IPL_TYPE_CCW:
> > +        return true;
> > +    case S390_IPL_TYPE_PCI:
> > +        return false;
> > +    default:
> > +        return true;
> > +    }
> > +}
> > +
> > +/*
> > + * Format the virtio ring descriptor endianness
> > + * Return the available index increment in the appropriate endianness
> > + */
> > +static uint16_t vr_fmt_descriptor(VRingDesc *desc)
> > +{
> > +    if (!be_ipl()) {
> > +        desc->addr = bswap64(desc->addr);
> > +        desc->len = bswap32(desc->len);
> > +        desc->flags = bswap16(desc->flags);
> > +        desc->next = bswap16(desc->next);
> > +    }
> > +
> > +    return be_ipl() ? 1 : bswap16(1);
> > +}
> > +
> >   void vring_send_buf(VRing *vr, void *p, int len, int flags)
> >   {
> > +    uint16_t increment;
> > +
> >       /* For follow-up chains we need to keep the first entry point */
> >       if (!(flags & VRING_HIDDEN_IS_CHAIN)) {
> >           vr->avail->ring[vr->avail->idx % vr->num] = vr->next_idx;
> > @@ -131,11 +169,13 @@ void vring_send_buf(VRing *vr, void *p, int len, int 
> > flags)
> >       vr->desc[vr->next_idx].flags = flags & ~VRING_HIDDEN_IS_CHAIN;
> >       vr->desc[vr->next_idx].next = vr->next_idx;
> >       vr->desc[vr->next_idx].next++;
> > +
> > +    increment = vr_fmt_descriptor(&vr->desc[vr->next_idx]);
> 
> If we are only returning 1 from the function vr_fmt_descriptor(), why not
> just set increment=1 or remove it completely and keep vr->avail->idx++? That
> way we don't need to do any endian conversion?
> 
> Thanks
> 
> Farhan
> 
> 
> >       vr->next_idx++;
> >       /* Chains only have a single ID */
> >       if (!(flags & VRING_DESC_F_NEXT)) {
> > -        vr->avail->idx++;
> > +        vr->avail->idx += increment;
> >       }
> >   }


Reply via email to