Index | Thread | Search

From:
Stefan Fritsch <sf@openbsd.org>
Subject:
virtio: Support unused virtqueues
To:
tech@openbsd.org
Date:
Tue, 7 Jan 2025 09:09:30 +0100

Download raw body.

Thread
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,