Module Name:    src
Committed By:   reinoud
Date:           Thu Jan 28 15:43:13 UTC 2021

Modified Files:
        src/sys/dev/pci: virtio.c virtio_pci.c virtiovar.h
        src/sys/dev/virtio: virtio_mmio.c

Log Message:
Rewrite and streamline virtio device config read/write and explicitly cater
for the Aarch64-eb bus problem with Qemu. This removes lots of bus_space
`magic' and cleans up the code.


To generate a diff of this commit:
cvs rdiff -u -r1.44 -r1.45 src/sys/dev/pci/virtio.c
cvs rdiff -u -r1.26 -r1.27 src/sys/dev/pci/virtio_pci.c
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/pci/virtiovar.h
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/virtio/virtio_mmio.c

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/pci/virtio.c
diff -u src/sys/dev/pci/virtio.c:1.44 src/sys/dev/pci/virtio.c:1.45
--- src/sys/dev/pci/virtio.c:1.44	Wed Jan 20 21:59:48 2021
+++ src/sys/dev/pci/virtio.c	Thu Jan 28 15:43:12 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: virtio.c,v 1.44 2021/01/20 21:59:48 reinoud Exp $	*/
+/*	$NetBSD: virtio.c,v 1.45 2021/01/28 15:43:12 reinoud Exp $	*/
 
 /*
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.44 2021/01/20 21:59:48 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.45 2021/01/28 15:43:12 reinoud Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -146,135 +146,245 @@ virtio_negotiate_features(struct virtio_
 	for (int i = 0; i < num; i++) \
 		printf("%02x ", bus_space_read_1(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index+i)); \
 	printf(") -> "); printf(fmt, val); printf("\n");
+#define DPRINTFR2(n, fmt, val_s, val_n) \
+	printf("%s ", n); \
+	printf("\n        stream "); printf(fmt, val_s); printf(" norm "); printf(fmt, val_n); printf("\n");
 #else
 #define DPRINTFR(n, fmt, val, index, num)
+#define DPRINTFR2(n, fmt, val_s, val_n)
 #endif
 
+
 uint8_t
 virtio_read_device_config_1(struct virtio_softc *sc, int index) {
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
 	uint8_t val;
-	val = sc->sc_ops->read_dev_cfg_1(sc, index);
+
+	val = bus_space_read_1(iot, ioh, index);
+
 	DPRINTFR("read_1", "%02x", val, index, 1);
 	return val;
 }
 
 uint16_t
 virtio_read_device_config_2(struct virtio_softc *sc, int index) {
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
 	uint16_t val;
-	val = sc->sc_ops->read_dev_cfg_2(sc, index);
+
+	val = bus_space_read_2(iot, ioh, index);
+	if (BYTE_ORDER != sc->sc_bus_endian)
+		val = bswap16(val);
+
 	DPRINTFR("read_2", "%04x", val, index, 2);
+	DPRINTFR2("read_2", "%04x",
+		bus_space_read_stream_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index),
+		bus_space_read_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index));
 	return val;
 }
 
 uint32_t
 virtio_read_device_config_4(struct virtio_softc *sc, int index) {
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
 	uint32_t val;
-	val = sc->sc_ops->read_dev_cfg_4(sc, index);
+
+	val = bus_space_read_4(iot, ioh, index);
+	if (BYTE_ORDER != sc->sc_bus_endian)
+		val = bswap32(val);
+
 	DPRINTFR("read_4", "%08x", val, index, 4);
+	DPRINTFR2("read_4", "%08x",
+		bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index),
+		bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index));
 	return val;
 }
 
 uint64_t
 virtio_read_device_config_8(struct virtio_softc *sc, int index) {
-	uint64_t val;
-	val = sc->sc_ops->read_dev_cfg_8(sc, index);
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
+	uint64_t val, val_0, val_1, val_l, val_h;
+
+	val_0 = bus_space_read_4(iot, ioh, index);
+	val_1 = bus_space_read_4(iot, ioh, index + 4);
+	if (BYTE_ORDER != sc->sc_bus_endian) {
+		val_l = bswap32(val_1);
+		val_h = bswap32(val_0);
+	} else {
+		val_l = val_0;
+		val_h = val_1;
+	}
+
+#ifdef AARCH64EB_PROBLEM
+	/* XXX see comment at virtio_pci.c */
+	if (sc->sc_aarch64eb_bus_problem) {
+		val_l = val_1;
+		val_h = val_0;
+	}
+#endif
+
+	val = val_h << 32;
+	val |= val_l;
+
 	DPRINTFR("read_8", "%08lx", val, index, 8);
+	DPRINTFR2("read_8 low ", "%08x",
+		bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index),
+		bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index));
+	DPRINTFR2("read_8 high ", "%08x",
+		bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index + 4),
+		bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index + 4));
 	return val;
 }
 
 /*
  * In the older virtio spec, device config registers are host endian. On newer
- * they are little endian. The normal logic will cater for this. However some
- * devices however explicitly state that its fields are always little endian
- * and will still need to be swapped.
+ * they are little endian. Some newer devices however explicitly specify their
+ * register to always be little endian. These fuctions cater for these.
  */
 uint16_t
 virtio_read_device_config_le_2(struct virtio_softc *sc, int index) {
-	bool virtio_v1 = (sc->sc_active_features & VIRTIO_F_VERSION_1);
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
 	uint16_t val;
 
-	val = sc->sc_ops->read_dev_cfg_2(sc, index);
-	val = virtio_v1 ? val : le16toh(val);
-	DPRINTFR("read_le_2", "%08x", val, index, 2);
+	val = bus_space_read_2(iot, ioh, index);
+	if (sc->sc_bus_endian != LITTLE_ENDIAN)
+		val = bswap16(val);
+
+	DPRINTFR("read_le_2", "%04x", val, index, 2);
+	DPRINTFR2("read_le_2", "%04x",
+		bus_space_read_stream_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0),
+		bus_space_read_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0));
 	return val;
 }
 
 uint32_t
 virtio_read_device_config_le_4(struct virtio_softc *sc, int index) {
-	bool virtio_v1 = (sc->sc_active_features & VIRTIO_F_VERSION_1);
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
 	uint32_t val;
 
-	val = sc->sc_ops->read_dev_cfg_4(sc, index);
-	val = virtio_v1 ? val : le32toh(val);
+	val = bus_space_read_4(iot, ioh, index);
+	if (sc->sc_bus_endian != LITTLE_ENDIAN)
+		val = bswap32(val);
+
 	DPRINTFR("read_le_4", "%08x", val, index, 4);
+	DPRINTFR2("read_le_4", "%08x",
+		bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0),
+		bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0));
 	return val;
 }
 
 void
 virtio_write_device_config_1(struct virtio_softc *sc, int index, uint8_t value)
 {
-	sc->sc_ops->write_dev_cfg_1(sc, index, value);
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
+
+	bus_space_write_1(iot, ioh, index, value);
 }
 
 void
 virtio_write_device_config_2(struct virtio_softc *sc, int index, uint16_t value)
 {
-	sc->sc_ops->write_dev_cfg_2(sc, index, value);
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
+
+	if (BYTE_ORDER != sc->sc_bus_endian)
+		value = bswap16(value);
+	bus_space_write_2(iot, ioh, index, value);
 }
 
 void
 virtio_write_device_config_4(struct virtio_softc *sc, int index, uint32_t value)
 {
-	sc->sc_ops->write_dev_cfg_4(sc, index, value);
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
+
+	if (BYTE_ORDER != sc->sc_bus_endian)
+		value = bswap32(value);
+	bus_space_write_4(iot, ioh, index, value);
 }
 
 void
 virtio_write_device_config_8(struct virtio_softc *sc, int index, uint64_t value)
 {
-	sc->sc_ops->write_dev_cfg_8(sc, index, value);
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
+	uint64_t val_0, val_1, val_l, val_h;
+
+	val_l = BUS_ADDR_LO32(value);
+	val_h = BUS_ADDR_HI32(value);
+
+	if (BYTE_ORDER != sc->sc_bus_endian) {
+		val_0 = bswap32(val_h);
+		val_1 = bswap32(val_l);
+	} else {
+		val_0 = val_l;
+		val_1 = val_h;
+	}
+
+#ifdef AARCH64EB_PROBLEM
+	/* XXX see comment at virtio_pci.c */
+	if (sc->sc_aarch64eb_bus_problem) {
+		val_0 = val_h;
+		val_1 = val_l;
+	}
+#endif
+
+	bus_space_write_4(iot, ioh, index, val_0);
+	bus_space_write_4(iot, ioh, index + 4, val_1);
 }
 
 /*
  * In the older virtio spec, device config registers are host endian. On newer
- * they are little endian. The normal logic will cater for this. However some
- * devices however explicitly state that its fields are always little endian
- * and will still need to be swapped.
+ * they are little endian. Some newer devices however explicitly specify their
+ * register to always be little endian. These fuctions cater for these.
  */
 void
 virtio_write_device_config_le_2(struct virtio_softc *sc, int index, uint16_t value)
 {
-	bool virtio_v1 = (sc->sc_active_features & VIRTIO_F_VERSION_1);
-	value = virtio_v1 ? value : htole16(value);
-	sc->sc_ops->write_dev_cfg_2(sc, index, value);
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
+
+	if (sc->sc_bus_endian != LITTLE_ENDIAN)
+		value = bswap16(value);
+	bus_space_write_2(iot, ioh, index, value);
 }
 
 void
 virtio_write_device_config_le_4(struct virtio_softc *sc, int index, uint32_t value)
 {
-	bool virtio_v1 = (sc->sc_active_features & VIRTIO_F_VERSION_1);
-	value = virtio_v1 ? value : htole32(value);
-	sc->sc_ops->write_dev_cfg_4(sc, index, value);
+	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
+	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
+
+	if (sc->sc_bus_endian != LITTLE_ENDIAN)
+		value = bswap32(value);
+	bus_space_write_4(iot, ioh, index, value);
 }
 
+
 /*
  * data structures endian helpers
  */
 uint16_t virtio_rw16(struct virtio_softc *sc, uint16_t val)
 {
 	KASSERT(sc);
-	return (sc->sc_devcfg_swap) ? bswap16(val) : val;
+	return BYTE_ORDER != sc->sc_struct_endian ? bswap16(val) : val;
 }
 
 uint32_t virtio_rw32(struct virtio_softc *sc, uint32_t val)
 {
 	KASSERT(sc);
-	return (sc->sc_devcfg_swap) ? bswap32(val) : val;
+	return BYTE_ORDER != sc->sc_struct_endian ? bswap32(val) : val;
 }
 
 uint64_t virtio_rw64(struct virtio_softc *sc, uint64_t val)
 {
 	KASSERT(sc);
-	return (sc->sc_devcfg_swap) ? bswap64(val) : val;
+	return BYTE_ORDER != sc->sc_struct_endian ? bswap64(val) : val;
 }
 
 

Index: src/sys/dev/pci/virtio_pci.c
diff -u src/sys/dev/pci/virtio_pci.c:1.26 src/sys/dev/pci/virtio_pci.c:1.27
--- src/sys/dev/pci/virtio_pci.c:1.26	Tue Jan 26 16:40:16 2021
+++ src/sys/dev/pci/virtio_pci.c	Thu Jan 28 15:43:12 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: virtio_pci.c,v 1.26 2021/01/26 16:40:16 reinoud Exp $ */
+/* $NetBSD: virtio_pci.c,v 1.27 2021/01/28 15:43:12 reinoud Exp $ */
 
 /*
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: virtio_pci.c,v 1.26 2021/01/26 16:40:16 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: virtio_pci.c,v 1.27 2021/01/28 15:43:12 reinoud Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -106,15 +106,6 @@ static void	virtio_pci_set_status_10(str
 static void	virtio_pci_negotiate_features_10(struct virtio_softc *, uint64_t);
 static int	virtio_pci_find_cap(struct virtio_pci_softc *psc, int cfg_type, void *buf, int buflen);
 
-static uint8_t	virtio_pci_read_device_config_1(struct virtio_softc *, int);
-static uint16_t	virtio_pci_read_device_config_2(struct virtio_softc *, int);
-static uint32_t	virtio_pci_read_device_config_4(struct virtio_softc *, int);
-static uint64_t	virtio_pci_read_device_config_8(struct virtio_softc *, int);
-static void 	virtio_pci_write_device_config_1(struct virtio_softc *, int, uint8_t);
-static void	virtio_pci_write_device_config_2(struct virtio_softc *, int, uint16_t);
-static void	virtio_pci_write_device_config_4(struct virtio_softc *, int, uint32_t);
-static void	virtio_pci_write_device_config_8(struct virtio_softc *, int, uint64_t);
-
 static int	virtio_pci_setup_interrupts(struct virtio_softc *);
 static void	virtio_pci_free_interrupts(struct virtio_softc *);
 static int	virtio_pci_adjust_config_region(struct virtio_pci_softc *psc);
@@ -131,61 +122,33 @@ static int	virtio_pci_setup_intx_interru
 #define VIRTIO_MSIX_CONFIG_VECTOR_INDEX	0
 #define VIRTIO_MSIX_QUEUE_VECTOR_INDEX	1
 
-#if 0
-/* we use the legacy virtio spec, so the PCI registers are host native
- * byte order, not PCI (i.e. LE) byte order */
-#if BYTE_ORDER == BIG_ENDIAN
-#define REG_HI_OFF      0
-#define REG_LO_OFF      4
-#ifndef __BUS_SPACE_HAS_STREAM_METHODS
-#define bus_space_read_stream_1 bus_space_read_1
-#define bus_space_write_stream_1 bus_space_write_1
-static inline uint16_t
-bus_space_read_stream_2(bus_space_tag_t t, bus_space_handle_t h,
-    bus_size_t o)
-{
-	return le16toh(bus_space_read_2(t, h, o));
-}
-static inline void
-bus_space_write_stream_2(bus_space_tag_t t, bus_space_handle_t h,
-    bus_size_t o, uint16_t v)
-{
-	bus_space_write_2(t, h, o, htole16(v));
-}
-static inline uint32_t
-bus_space_read_stream_4(bus_space_tag_t t, bus_space_handle_t h,
-    bus_size_t o)
-{
-	return le32toh(bus_space_read_4(t, h, o));
-}
-static inline void
-bus_space_write_stream_4(bus_space_tag_t t, bus_space_handle_t h,
-    bus_size_t o, uint32_t v)
-{
-	bus_space_write_4(t, h, o, htole32(v));
-}
-#endif
-#else
-#define REG_HI_OFF	4
-#define REG_LO_OFF	0
-#ifndef __BUS_SPACE_HAS_STREAM_METHODS
-#define bus_space_read_stream_1 bus_space_read_1
-#define bus_space_read_stream_2 bus_space_read_2
-#define bus_space_read_stream_4 bus_space_read_4
-#define bus_space_write_stream_1 bus_space_write_1
-#define bus_space_write_stream_2 bus_space_write_2
-#define bus_space_write_stream_4 bus_space_write_4
-#endif
-#endif
-#endif
-
+/*
+ * When using PCI attached virtio on aarch64-eb under Qemu, the IO space
+ * suddenly read BIG_ENDIAN where it should stay LITTLE_ENDIAN. The data read
+ * 1 byte at a time seem OK but reading bigger lengths result in swapped
+ * endian. This is most notable on reading 8 byters since we can't use
+ * bus_space_{read,write}_8() and it has to be patched there explicitly. We
+ * define the AARCH64EB_PROBLEM to signal we're vulnerable to this and set the
+ * accompanied sc->sc_aarch64_eb_bus_problem variable when attaching using the
+ * IO space.
+ */
 
-#if BYTE_ORDER == LITTLE_ENDIAN
-#	define VIODEVRW_SWAP_09 false 
-#	define VIODEVRW_SWAP_10 false
-#else /* big endian */
-#	define VIODEVRW_SWAP_09 false
-#	define VIODEVRW_SWAP_10 true
+#if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN
+	/* source of AARCH64EB_PROBLEM */
+#	define READ_ENDIAN_09	BIG_ENDIAN	/* XXX bug, should be LITTLE_ENDIAN */
+#	define READ_ENDIAN_10	BIG_ENDIAN
+#	define STRUCT_ENDIAN_09	BIG_ENDIAN
+#	define STRUCT_ENDIAN_10	LITTLE_ENDIAN
+#elif BYTE_ORDER == BIG_ENDIAN
+#	define READ_ENDIAN_09	LITTLE_ENDIAN
+#	define READ_ENDIAN_10	BIG_ENDIAN
+#	define STRUCT_ENDIAN_09	BIG_ENDIAN
+#	define STRUCT_ENDIAN_10	LITTLE_ENDIAN
+#else /* little endian */
+#	define READ_ENDIAN_09	LITTLE_ENDIAN
+#	define READ_ENDIAN_10	LITTLE_ENDIAN
+#	define STRUCT_ENDIAN_09	LITTLE_ENDIAN
+#	define STRUCT_ENDIAN_10	LITTLE_ENDIAN
 #endif
 
 
@@ -195,16 +158,6 @@ CFATTACH_DECL3_NEW(virtio_pci, sizeof(st
 
 static const struct virtio_ops virtio_pci_ops_09 = {
 	.kick = virtio_pci_kick_09,
-
-	.read_dev_cfg_1 = virtio_pci_read_device_config_1,
-	.read_dev_cfg_2 = virtio_pci_read_device_config_2,
-	.read_dev_cfg_4 = virtio_pci_read_device_config_4,
-	.read_dev_cfg_8 = virtio_pci_read_device_config_8,
-	.write_dev_cfg_1 = virtio_pci_write_device_config_1,
-	.write_dev_cfg_2 = virtio_pci_write_device_config_2,
-	.write_dev_cfg_4 = virtio_pci_write_device_config_4,
-	.write_dev_cfg_8 = virtio_pci_write_device_config_8,
-
 	.read_queue_size = virtio_pci_read_queue_size_09,
 	.setup_queue = virtio_pci_setup_queue_09,
 	.set_status = virtio_pci_set_status_09,
@@ -215,16 +168,6 @@ static const struct virtio_ops virtio_pc
 
 static const struct virtio_ops virtio_pci_ops_10 = {
 	.kick = virtio_pci_kick_10,
-
-	.read_dev_cfg_1 = virtio_pci_read_device_config_1,
-	.read_dev_cfg_2 = virtio_pci_read_device_config_2,
-	.read_dev_cfg_4 = virtio_pci_read_device_config_4,
-	.read_dev_cfg_8 = virtio_pci_read_device_config_8,
-	.write_dev_cfg_1 = virtio_pci_write_device_config_1,
-	.write_dev_cfg_2 = virtio_pci_write_device_config_2,
-	.write_dev_cfg_4 = virtio_pci_write_device_config_4,
-	.write_dev_cfg_8 = virtio_pci_write_device_config_8,
-
 	.read_queue_size = virtio_pci_read_queue_size_10,
 	.setup_queue = virtio_pci_setup_queue_10,
 	.set_status = virtio_pci_set_status_10,
@@ -424,7 +367,11 @@ virtio_pci_attach_09(device_t self, void
 
 	/* set our version 0.9 ops */
 	sc->sc_ops = &virtio_pci_ops_09;
-	sc->sc_devcfg_swap = VIODEVRW_SWAP_09;
+	sc->sc_bus_endian    = READ_ENDIAN_09;
+	sc->sc_struct_endian = STRUCT_ENDIAN_09;
+#if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN
+	sc->sc_aarch64eb_bus_problem = true;
+#endif
 	return 0;
 }
 
@@ -545,7 +492,8 @@ virtio_pci_attach_10(device_t self, void
 
 	/* set our version 1.0 ops */
 	sc->sc_ops = &virtio_pci_ops_10;
-	sc->sc_devcfg_swap = VIODEVRW_SWAP_10;
+	sc->sc_bus_endian    = READ_ENDIAN_10;
+	sc->sc_struct_endian = STRUCT_ENDIAN_10;
 	return 0;
 
 err:
@@ -855,166 +803,6 @@ virtio_pci_negotiate_features_10(struct 
 	return;
 }
 
-/* -------------------------------------
- * Read/write device config code
- * -------------------------------------*/
-
-static uint8_t
-virtio_pci_read_device_config_1(struct virtio_softc *vsc, int index)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-	return bus_space_read_1(iot, ioh, index);
-}
-
-static uint16_t
-virtio_pci_read_device_config_2(struct virtio_softc *vsc, int index)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-	uint16_t val;
-
-#if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN
-	val = bus_space_read_2(iot, ioh, index);
-	return val;
-#else
-	val = bus_space_read_stream_2(iot, ioh, index);
-	if (vsc->sc_devcfg_swap)
-		return bswap16(val);
-	return val;
-#endif
-}
-
-static uint32_t
-virtio_pci_read_device_config_4(struct virtio_softc *vsc, int index)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-	uint32_t val;
-
-#if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN
-	val = bus_space_read_4(iot, ioh, index);
-	return val;
-#else
-	val = bus_space_read_stream_4(iot, ioh, index);
-	if (vsc->sc_devcfg_swap)
-		return bswap32(val);
-	return val;
-#endif
-}
-
-static uint64_t
-virtio_pci_read_device_config_8(struct virtio_softc *vsc, int index)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-	uint64_t val, val_h, val_l;
-
-#if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN
-	if (vsc->sc_devcfg_swap) {
-		val_l = bus_space_read_4(iot, ioh, index);
-		val_h = bus_space_read_4(iot, ioh, index + 4);
-	} else {
-		val_h = bus_space_read_4(iot, ioh, index);
-		val_l = bus_space_read_4(iot, ioh, index + 4);
-	}
-	val = val_h << 32;
-	val |= val_l;
-	return val;
-#elif BYTE_ORDER == BIG_ENDIAN
-	val_h = bus_space_read_stream_4(iot, ioh, index);
-	val_l = bus_space_read_stream_4(iot, ioh, index + 4);
-	val = val_h << 32;
-	val |= val_l;
-	if (vsc->sc_devcfg_swap)
-		return bswap64(val);
-	return val;
-#else
-	val_l = bus_space_read_4(iot, ioh, index);
-	val_h = bus_space_read_4(iot, ioh, index + 4);
-	val = val_h << 32;
-	val |= val_l;
-
-	return val;
-#endif
-}
-
-static void
-virtio_pci_write_device_config_1(struct virtio_softc *vsc,
-			     int index, uint8_t value)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-	bus_space_write_1(iot, ioh, index, value);
-}
-
-static void
-virtio_pci_write_device_config_2(struct virtio_softc *vsc,
-			     int index, uint16_t value)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-#if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN
-	bus_space_write_2(iot, ioh, index, value);
-#else
-	if (vsc->sc_devcfg_swap)
-		value = bswap16(value);
-	bus_space_write_stream_2(iot, ioh, index, value);
-#endif
-}
-
-static void
-virtio_pci_write_device_config_4(struct virtio_softc *vsc,
-			     int index, uint32_t value)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-#if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN
-	bus_space_write_4(iot, ioh, index, value);
-#else
-	if (vsc->sc_devcfg_swap)
-		value = bswap32(value);
-	bus_space_write_stream_4(iot, ioh, index, value);
-#endif
-}
-
-static void
-virtio_pci_write_device_config_8(struct virtio_softc *vsc,
-			     int index, uint64_t value)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-	uint64_t val_h, val_l;
-
-#if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN
-	val_l = value & 0xffffffff;
-	val_h = value >> 32;
-	if (vsc->sc_devcfg_swap) {
-		bus_space_write_4(iot, ioh, index, val_l);
-		bus_space_write_4(iot, ioh, index + 4, val_h);
-	} else {
-		bus_space_write_4(iot, ioh, index, val_h);
-		bus_space_write_4(iot, ioh, index + 4, val_l);
-	}
-#elif BYTE_ORDER == BIG_ENDIAN
-	if (vsc->sc_devcfg_swap)
-		value = bswap64(value);
-	val_l = value & 0xffffffff;
-	val_h = value >> 32;
-
-	bus_space_write_stream_4(iot, ioh, index, val_h);
-	bus_space_write_stream_4(iot, ioh, index + 4, val_l);
-#else
-	val_l = value & 0xffffffff;
-	val_h = value >> 32;
-	bus_space_write_stream_4(iot, ioh, index, val_l);
-	bus_space_write_stream_4(iot, ioh, index + 4, val_h);
-#endif
-}
 
 /* -------------------------------------
  * Generic PCI interrupt code

Index: src/sys/dev/pci/virtiovar.h
diff -u src/sys/dev/pci/virtiovar.h:1.18 src/sys/dev/pci/virtiovar.h:1.19
--- src/sys/dev/pci/virtiovar.h:1.18	Wed Jan 20 21:59:48 2021
+++ src/sys/dev/pci/virtiovar.h	Thu Jan 28 15:43:12 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: virtiovar.h,v 1.18 2021/01/20 21:59:48 reinoud Exp $	*/
+/*	$NetBSD: virtiovar.h,v 1.19 2021/01/28 15:43:12 reinoud Exp $	*/
 
 /*
  * Copyright (c) 2010 Minoura Makoto.
@@ -135,16 +135,6 @@ typedef int (*virtio_callback)(struct vi
 #ifdef VIRTIO_PRIVATE
 struct virtio_ops {
 	void		(*kick)(struct virtio_softc *, uint16_t);
-
-	uint8_t		(*read_dev_cfg_1)(struct virtio_softc *, int);
-	uint16_t	(*read_dev_cfg_2)(struct virtio_softc *, int);
-	uint32_t	(*read_dev_cfg_4)(struct virtio_softc *, int);
-	uint64_t	(*read_dev_cfg_8)(struct virtio_softc *, int);
-	void		(*write_dev_cfg_1)(struct virtio_softc *, int, uint8_t);
-	void		(*write_dev_cfg_2)(struct virtio_softc *, int, uint16_t);
-	void		(*write_dev_cfg_4)(struct virtio_softc *, int, uint32_t);
-	void		(*write_dev_cfg_8)(struct virtio_softc *, int, uint64_t);
-
 	uint16_t	(*read_queue_size)(struct virtio_softc *, uint16_t);
 	void		(*setup_queue)(struct virtio_softc *, uint16_t, uint64_t);
 	void		(*set_status)(struct virtio_softc *, int);
@@ -158,7 +148,12 @@ struct virtio_softc {
 	const struct virtio_ops *sc_ops;
 	bus_dma_tag_t		sc_dmat;
 
-	bool			sc_devcfg_swap;
+#define AARCH64EB_PROBLEM	/* see comment in virtio_pci.c */
+	bool			sc_aarch64eb_bus_problem;
+
+	int			sc_bus_endian;
+	int			sc_struct_endian;
+
 	bus_space_tag_t		sc_devcfg_iot;
 	bus_space_handle_t	sc_devcfg_ioh;
 	bus_size_t		sc_devcfg_iosize;

Index: src/sys/dev/virtio/virtio_mmio.c
diff -u src/sys/dev/virtio/virtio_mmio.c:1.4 src/sys/dev/virtio/virtio_mmio.c:1.5
--- src/sys/dev/virtio/virtio_mmio.c:1.4	Wed Jan 20 19:46:48 2021
+++ src/sys/dev/virtio/virtio_mmio.c	Thu Jan 28 15:43:13 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: virtio_mmio.c,v 1.4 2021/01/20 19:46:48 reinoud Exp $	*/
+/*	$NetBSD: virtio_mmio.c,v 1.5 2021/01/28 15:43:13 reinoud Exp $	*/
 /*	$OpenBSD: virtio_mmio.c,v 1.2 2017/02/24 17:12:31 patrick Exp $	*/
 
 /*
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.4 2021/01/20 19:46:48 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.5 2021/01/28 15:43:13 reinoud Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -68,43 +68,24 @@ __KERNEL_RCSID(0, "$NetBSD: virtio_mmio.
 /*
  * MMIO configuration space for virtio-mmio v1 is in guest byte order.
  *
- * AArch64 BE is special in that its bus space functions always read little
- * endian like on the PCI bus and thus need swapping to read host endian
- * registers.
- *
- * XXX this might also be true for other big endian machines.
- * XXX: TODO test virtio MMIO on non AArch64 big endian machines.
+ * XXX Note that aarch64eb pretends to be little endian. the MMIO registers
+ * are in little endian but the device config registers and data structures
+ * are in big endian; this is due to a bug in current Qemu.
  */
 
 #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN
-#define	VIO16TOH(x)	le16toh(x)
-#define	VIO32TOH(x)	le32toh(x)
-#define	VIO64TOH(x)	le64toh(x)
-#define	HTOVIO16(x)	htole16(x)
-#define	HTOVIO32(x)	htole32(x)
-#define	HTOVIO64(x)	htole64(x)
-#define VIODEVRW_SWAP false	/* can only be native endian now */
+#	define READ_ENDIAN	LITTLE_ENDIAN
+#	define STRUCT_ENDIAN	BIG_ENDIAN
+#elif BYTE_ORDER == BIG_ENDIAN
+#	define READ_ENDIAN	BIG_ENDIAN
+#	define STRUCT_ENDIAN	BIG_ENDIAN
 #else
-#define	VIO16TOH(x)	(x)
-#define	VIO32TOH(x)	(x)
-#define	VIO64TOH(x)	(x)
-#define	HTOVIO16(x)	(x)
-#define	HTOVIO32(x)	(x)
-#define	HTOVIO64(x)	(x)
-#define VIODEVRW_SWAP false	/* will only be native endian now */
+#	define READ_ENDIAN	LITTLE_ENDIAN
+#	define STRUCT_ENDIAN	LITTLE_ENDIAN
 #endif
 
 
 static void	virtio_mmio_kick(struct virtio_softc *, uint16_t);
-static uint8_t	virtio_mmio_read_device_config_1(struct virtio_softc *, int);
-static uint16_t	virtio_mmio_read_device_config_2(struct virtio_softc *, int);
-static uint32_t	virtio_mmio_read_device_config_4(struct virtio_softc *, int);
-static uint64_t	virtio_mmio_read_device_config_8(struct virtio_softc *, int);
-static void	virtio_mmio_write_device_config_1(struct virtio_softc *, int, uint8_t);
-static void	virtio_mmio_write_device_config_2(struct virtio_softc *, int, uint16_t);
-static void	virtio_mmio_write_device_config_4(struct virtio_softc *, int, uint32_t);
-static void	virtio_mmio_write_device_config_8(struct virtio_softc *, int, uint64_t);
-
 static uint16_t	virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t);
 static void	virtio_mmio_setup_queue(struct virtio_softc *, uint16_t, uint64_t);
 static void	virtio_mmio_set_status(struct virtio_softc *, int);
@@ -114,16 +95,6 @@ static void	virtio_mmio_free_interrupts(
 
 static const struct virtio_ops virtio_mmio_ops = {
 	.kick = virtio_mmio_kick,
-
-	.read_dev_cfg_1 = virtio_mmio_read_device_config_1,
-	.read_dev_cfg_2 = virtio_mmio_read_device_config_2,
-	.read_dev_cfg_4 = virtio_mmio_read_device_config_4,
-	.read_dev_cfg_8 = virtio_mmio_read_device_config_8,
-	.write_dev_cfg_1 = virtio_mmio_write_device_config_1,
-	.write_dev_cfg_2 = virtio_mmio_write_device_config_2,
-	.write_dev_cfg_4 = virtio_mmio_write_device_config_4,
-	.write_dev_cfg_8 = virtio_mmio_write_device_config_8,
-
 	.read_queue_size = virtio_mmio_read_queue_size,
 	.setup_queue = virtio_mmio_setup_queue,
 	.set_status = virtio_mmio_set_status,
@@ -202,7 +173,8 @@ virtio_mmio_common_attach(struct virtio_
 
 	virtio_print_device_type(self, id, ver);
 	vsc->sc_ops = &virtio_mmio_ops;
-	vsc->sc_devcfg_swap = VIODEVRW_SWAP;
+	vsc->sc_bus_endian    = READ_ENDIAN;
+	vsc->sc_struct_endian = STRUCT_ENDIAN;
 
 	/* set up our device config tag */
 	vsc->sc_devcfg_iosize = sc->sc_iosize - VIRTIO_MMIO_CONFIG;
@@ -269,100 +241,6 @@ virtio_mmio_negotiate_features(struct vi
 	vsc->sc_active_features = r;
 }
 
-#
-/*
- * Device configuration registers.
- */
-
-/* ----------------------------------------------------
- * Read/write device config code
- * ----------------------------------------------------*/
-
-static uint8_t
-virtio_mmio_read_device_config_1(struct virtio_softc *vsc, int index)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-	return bus_space_read_1(iot, ioh, index);
-}
-
-static uint16_t
-virtio_mmio_read_device_config_2(struct virtio_softc *vsc, int index)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-	return VIO16TOH(bus_space_read_2(iot, ioh, index));
-}
-
-static uint32_t
-virtio_mmio_read_device_config_4(struct virtio_softc *vsc, int index)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-	return VIO32TOH(bus_space_read_4(iot, ioh, index));
-}
-
-static uint64_t
-virtio_mmio_read_device_config_8(struct virtio_softc *vsc, int index)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-	uint64_t r;
-
-	r = bus_space_read_4(iot, ioh, index + sizeof(uint32_t));
-	r <<= 32;
-	r += bus_space_read_4(iot, ioh, index);
-	return VIO64TOH(r);
-}
-
-static void
-virtio_mmio_write_device_config_1(struct virtio_softc *vsc,
-			     int index, uint8_t value)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-	bus_space_write_1(iot, ioh, index, value);
-}
-
-static void
-virtio_mmio_write_device_config_2(struct virtio_softc *vsc,
-			     int index, uint16_t value)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-	value = HTOVIO16(value);
-	bus_space_write_2(iot, ioh, index, value);
-}
-
-static void
-virtio_mmio_write_device_config_4(struct virtio_softc *vsc,
-			     int index, uint32_t value)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-	value = HTOVIO32(value);
-	bus_space_write_4(iot, ioh, index, value);
-}
-
-static void
-virtio_mmio_write_device_config_8(struct virtio_softc *vsc,
-			     int index, uint64_t value)
-{
-	bus_space_tag_t	   iot = vsc->sc_devcfg_iot;
-	bus_space_handle_t ioh = vsc->sc_devcfg_ioh;
-
-	value = HTOVIO64(value);
-	bus_space_write_4(iot, ioh, index, value & 0xffffffff);
-	bus_space_write_4(iot, ioh, index + sizeof(uint32_t), value >> 32);
-}
-
-
 /*
  * Interrupt handler.
  */

Reply via email to