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.
*/