From: Stefan Fritsch Subject: virtio: Support unused virtqueues To: tech@openbsd.org Date: Tue, 7 Jan 2025 09:09:30 +0100 Hi, another small preparatory diff that we will need for vio(4) multiqueue, if the hypervisor offers more packet queues than we want to use. The control queue comes after the packet queues. ok? Cheers, Stefan diff --git a/sys/dev/pv/virtio.c b/sys/dev/pv/virtio.c index 69eb26386ba..2d0c2386b87 100644 --- a/sys/dev/pv/virtio.c +++ b/sys/dev/pv/virtio.c @@ -167,6 +167,8 @@ virtio_attach_finish(struct virtio_softc *sc, struct virtio_attach_args *va) for (i = 0; i < sc->sc_nvqs; i++) { struct virtqueue *vq = &sc->sc_vqs[i]; + if (vq->vq_num == 0) + continue; virtio_setup_queue(sc, vq, vq->vq_dmamap->dm_segs[0].ds_addr); } virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK); @@ -185,9 +187,9 @@ virtio_reinit_start(struct virtio_softc *sc) for (i = 0; i < sc->sc_nvqs; i++) { int n; struct virtqueue *vq = &sc->sc_vqs[i]; - n = virtio_read_queue_size(sc, vq->vq_index); - if (n == 0) /* vq disappeared */ + if (vq->vq_num == 0) /* not used */ continue; + n = virtio_read_queue_size(sc, vq->vq_index); if (n != vq->vq_num) { panic("%s: virtqueue size changed, vq index %d", sc->sc_dev.dv_xname, vq->vq_index); @@ -274,8 +276,11 @@ virtio_check_vqs(struct virtio_softc *sc) int i, r = 0; /* going backwards is better for if_vio */ - for (i = sc->sc_nvqs - 1; i >= 0; i--) + for (i = sc->sc_nvqs - 1; i >= 0; i--) { + if (sc->sc_vqs[i].vq_num == 0) /* not used */ + continue; r |= virtio_check_vq(sc, &sc->sc_vqs[i]); + } return r; } @@ -305,6 +310,7 @@ virtio_init_vq(struct virtio_softc *sc, struct virtqueue *vq) int i, j; int vq_size = vq->vq_num; + VIRTIO_ASSERT(vq_size > 0); memset(vq->vq_vaddr, 0, vq->vq_bytesize); /* build the indirect descriptor chain */ @@ -468,6 +474,11 @@ virtio_free_vq(struct virtio_softc *sc, struct virtqueue *vq) struct vq_entry *qe; int i = 0; + if (vq->vq_num == 0) { + /* virtio_alloc_vq() was never called */ + return 0; + } + /* device must be already deactivated */ /* confirm the vq is empty */ SLIST_FOREACH(qe, &vq->vq_freelist, qe_list) { @@ -1017,6 +1028,10 @@ virtio_vq_dump(struct virtqueue *vq) #endif /* Common fields */ printf(" + addr: %p\n", vq); + if (vq->vq_num == 0) { + printf(" + vq is unused\n"); + return; + } printf(" + vq num: %d\n", vq->vq_num); printf(" + vq mask: 0x%X\n", vq->vq_mask); printf(" + vq index: %d\n", vq->vq_index); diff --git a/sys/dev/pv/virtiovar.h b/sys/dev/pv/virtiovar.h index bed9ff0ce09..207e43ce9b8 100644 --- a/sys/dev/pv/virtiovar.h +++ b/sys/dev/pv/virtiovar.h @@ -103,7 +103,8 @@ struct vq_entry { struct virtqueue { struct virtio_softc *vq_owner; - unsigned int vq_num; /* queue size (# of entries) */ + unsigned int vq_num; /* queue size (# of entries), + * 0 if unused/non-existant */ unsigned int vq_mask; /* (1 << vq_num - 1) */ int vq_index; /* queue number (0, 1, ...) */ @@ -180,7 +181,7 @@ struct virtio_softc { int sc_indirect; int sc_version_1; - int sc_nvqs; /* set by child */ + int sc_nvqs; /* size of sc_vqs, set by child */ struct virtqueue *sc_vqs; /* set by child */ struct device *sc_child; /* set by child,