Module Name:    src
Committed By:   thorpej
Date:           Sat Jan  6 06:59:33 UTC 2024

Modified Files:
        src/sys/dev/virtio: virtio_mmio.c virtio_mmiovar.h

Log Message:
Perform VirtIO 1.0 feature negotation in the MMIO transport.  This is
required for HV's that have MMIO-v2 and don't support transitional devices.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/virtio/virtio_mmio.c
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/virtio/virtio_mmiovar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/virtio/virtio_mmio.c
diff -u src/sys/dev/virtio/virtio_mmio.c:1.12 src/sys/dev/virtio/virtio_mmio.c:1.13
--- src/sys/dev/virtio/virtio_mmio.c:1.12	Tue Jan  2 07:24:50 2024
+++ src/sys/dev/virtio/virtio_mmio.c	Sat Jan  6 06:59:33 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: virtio_mmio.c,v 1.12 2024/01/02 07:24:50 thorpej Exp $	*/
+/*	$NetBSD: virtio_mmio.c,v 1.13 2024/01/06 06:59:33 thorpej Exp $	*/
 /*	$OpenBSD: virtio_mmio.c,v 1.2 2017/02/24 17:12:31 patrick Exp $	*/
 
 /*-
@@ -58,7 +58,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.12 2024/01/02 07:24:50 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.13 2024/01/06 06:59:33 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -99,9 +99,6 @@ __KERNEL_RCSID(0, "$NetBSD: virtio_mmio.
 #define	VIRTIO_MMIO_V2_CONFIG_GEN	0x0fc
 #define VIRTIO_MMIO_CONFIG		0x100
 
-#define VIRTIO_MMIO_INT_VRING		(1 << 0)
-#define VIRTIO_MMIO_INT_CONFIG		(1 << 1)
-
 /*
  * MMIO configuration space for virtio-mmio v1 is in guest byte order.
  *
@@ -124,6 +121,7 @@ static void	virtio_mmio_kick(struct virt
 static uint16_t	virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t);
 static void	virtio_mmio_v1_setup_queue(struct virtio_softc *, uint16_t, uint64_t);
 static void	virtio_mmio_v2_setup_queue(struct virtio_softc *, uint16_t, uint64_t);
+static int	virtio_mmio_get_status(struct virtio_softc *);
 static void	virtio_mmio_set_status(struct virtio_softc *, int);
 static void	virtio_mmio_negotiate_features(struct virtio_softc *, uint64_t);
 static int	virtio_mmio_alloc_interrupts(struct virtio_softc *);
@@ -232,6 +230,14 @@ virtio_mmio_v2_setup_queue(struct virtio
 	}
 }
 
+static int
+virtio_mmio_get_status(struct virtio_softc *vsc)
+{
+	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+
+	return virtio_mmio_reg_read(sc, VIRTIO_MMIO_STATUS);
+}
+
 static void
 virtio_mmio_set_status(struct virtio_softc *vsc, int status)
 {
@@ -260,7 +266,8 @@ virtio_mmio_common_attach(struct virtio_
 {
 	struct virtio_softc *vsc = &sc->sc_sc;
 	device_t self = vsc->sc_dev;
-	uint32_t id, magic, ver;
+	uint32_t id, magic;
+	int virtio_vers;
 
 	magic = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
 	    VIRTIO_MMIO_MAGIC_VALUE);
@@ -276,25 +283,35 @@ virtio_mmio_common_attach(struct virtio_
 	vsc->sc_bus_endian    = READ_ENDIAN;
 	vsc->sc_struct_endian = STRUCT_ENDIAN;
 
-	ver = virtio_mmio_reg_read(sc, VIRTIO_MMIO_VERSION);
-	switch (ver) {
+	sc->sc_mmio_vers = virtio_mmio_reg_read(sc, VIRTIO_MMIO_VERSION);
+	switch (sc->sc_mmio_vers) {
 	case 1:
 		/* we could use PAGE_SIZE, but virtio(4) assumes 4KiB for now */
 		virtio_mmio_reg_write(sc,
 		    VIRTIO_MMIO_V1_GUEST_PAGE_SIZE, VIRTIO_PAGE_SIZE);
 		vsc->sc_ops = &virtio_mmio_v1_ops;
+		/*
+		 * MMIO v1 ("legacy") is documented in the VirtIO 0.9.x
+		 * draft(s) and uses the same page-oriented queue setup,
+		 * so that's what we'll report as the VirtIO version.
+		 */
+		virtio_vers = 0;
 		break;
 
 	case 2:
 		vsc->sc_ops = &virtio_mmio_v2_ops;
+		/*
+		 * MMIO v2 is documented in the VirtIO 1.0 spec.
+		 */
+		virtio_vers = 1;
 		break;
 
 	default:
 		aprint_error_dev(vsc->sc_dev,
-		    "unknown version 0x%08x; giving up\n", ver);
+		    "unknown version 0x%08x; giving up\n", sc->sc_mmio_vers);
 		return;
 	}
-	aprint_normal_dev(self, "VirtIO-MMIO v%d\n", ver);
+	aprint_normal_dev(self, "VirtIO-MMIO-v%u\n", sc->sc_mmio_vers);
 
 	id = virtio_mmio_reg_read(sc, VIRTIO_MMIO_DEVICE_ID);
 	if (id == 0) {
@@ -302,7 +319,7 @@ virtio_mmio_common_attach(struct virtio_
 		return;
 	}
 
-	virtio_print_device_type(self, id, ver);
+	virtio_print_device_type(self, id, virtio_vers);
 
 	/* set up our device config tag */
 	vsc->sc_devcfg_iosize = sc->sc_iosize - VIRTIO_MMIO_CONFIG;
@@ -347,21 +364,89 @@ virtio_mmio_common_detach(struct virtio_
 
 /*
  * Feature negotiation.
+ *
+ * We fold pre-VirtIO-1.0 feature negotiation into this single routine
+ * because the "legacy" (MMIO-v1) also had the feature sel registers.
  */
 static void
 virtio_mmio_negotiate_features(struct virtio_softc *vsc, uint64_t
     driver_features)
 {
 	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
-	uint32_t r;
+	device_t self = vsc->sc_dev;
+	uint64_t saved_driver_features = driver_features;
+	uint64_t device_features, negotiated;
+	uint32_t device_status;
+
+	driver_features |= VIRTIO_F_VERSION_1;
+	vsc->sc_active_features = 0;
 
 	virtio_mmio_reg_write(sc, VIRTIO_MMIO_DEVICE_FEATURES_SEL, 0);
-	r = virtio_mmio_reg_read(sc, VIRTIO_MMIO_DEVICE_FEATURES);
-	r &= driver_features;
+	device_features = virtio_mmio_reg_read(sc, VIRTIO_MMIO_DEVICE_FEATURES);
+	virtio_mmio_reg_write(sc, VIRTIO_MMIO_DEVICE_FEATURES_SEL, 1);
+	device_features |= (uint64_t)
+	    virtio_mmio_reg_read(sc, VIRTIO_MMIO_DEVICE_FEATURES) << 32;
+
+	/* notify on empty is 0.9 only */
+	if (device_features & VIRTIO_F_VERSION_1) {
+		driver_features &= ~VIRTIO_F_NOTIFY_ON_EMPTY;
+	} else {
+		/*
+		 * Require version 1 for MMIO-v2 transport.
+		 */
+		if (sc->sc_mmio_vers >= 2) {
+			aprint_error_dev(self, "MMIO-v%u requires version 1\n",
+			    sc->sc_mmio_vers);
+			virtio_mmio_set_status(vsc,
+			    VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
+			return;
+		}
+		/*
+		 * If the driver requires version 1, but the device doesn't
+		 * support it, fail now.
+		 */
+		if (saved_driver_features & VIRTIO_F_VERSION_1) {
+			aprint_error_dev(self, "device rejected version 1\n");
+			virtio_mmio_set_status(vsc,
+			    VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
+			return;
+		}
+	}
+
+	negotiated = device_features & driver_features;
+
 	virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0);
-	virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES, r);
+	virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES,
+	    (uint32_t)negotiated);
+	virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 1);
+	virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES,
+	    (uint32_t)(negotiated >> 32));
+
+	/*
+	 * FEATURES_OK status is not present pre-1.0.
+	 */
+	if (device_features & VIRTIO_F_VERSION_1) {
+		virtio_mmio_set_status(vsc,
+		    VIRTIO_CONFIG_DEVICE_STATUS_FEATURES_OK);
+		device_status = virtio_mmio_get_status(vsc);
+		if ((device_status &
+		     VIRTIO_CONFIG_DEVICE_STATUS_FEATURES_OK) == 0) {
+			aprint_error_dev(self, "feature negotiation failed\n");
+			virtio_mmio_set_status(vsc,
+			    VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
+			return;
+		}
+	}
+
+	if (negotiated & VIRTIO_F_VERSION_1) {
+		/*
+		 * All VirtIO 1.0 access is little-endian.
+		 */
+		vsc->sc_bus_endian    = LITTLE_ENDIAN;
+		vsc->sc_struct_endian = LITTLE_ENDIAN;
+	}
 
-	vsc->sc_active_features = r;
+	vsc->sc_active_features = negotiated;
 }
 
 /*
@@ -377,10 +462,10 @@ virtio_mmio_intr(void *arg)
 	/* check and ack the interrupt */
 	isr = virtio_mmio_reg_read(sc, VIRTIO_MMIO_INTERRUPT_STATUS);
 	virtio_mmio_reg_write(sc, VIRTIO_MMIO_INTERRUPT_ACK, isr);
-	if ((isr & VIRTIO_MMIO_INT_CONFIG) &&
+	if ((isr & VIRTIO_CONFIG_ISR_CONFIG_CHANGE) &&
 	    (vsc->sc_config_change != NULL))
 		r = (vsc->sc_config_change)(vsc);
-	if ((isr & VIRTIO_MMIO_INT_VRING) &&
+	if ((isr & VIRTIO_CONFIG_ISR_QUEUE_INTERRUPT) &&
 	    (vsc->sc_intrhand != NULL)) {
 		if (vsc->sc_soft_ih != NULL)
 			softint_schedule(vsc->sc_soft_ih);

Index: src/sys/dev/virtio/virtio_mmiovar.h
diff -u src/sys/dev/virtio/virtio_mmiovar.h:1.6 src/sys/dev/virtio/virtio_mmiovar.h:1.7
--- src/sys/dev/virtio/virtio_mmiovar.h:1.6	Tue Jan  2 07:24:50 2024
+++ src/sys/dev/virtio/virtio_mmiovar.h	Sat Jan  6 06:59:33 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: virtio_mmiovar.h,v 1.6 2024/01/02 07:24:50 thorpej Exp $ */
+/* $NetBSD: virtio_mmiovar.h,v 1.7 2024/01/06 06:59:33 thorpej Exp $ */
 /*
  * Copyright (c) 2018 Jonathan A. Kollasch
  * All rights reserved.
@@ -36,6 +36,7 @@ struct virtio_mmio_softc {
 	bus_space_tag_t		sc_iot;
 	bus_space_handle_t	sc_ioh;
 	bus_size_t		sc_iosize;
+	uint32_t		sc_mmio_vers;
 	bool			sc_le_regs;
 
 	void			*sc_ih;

Reply via email to