Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev Rewrite and streamline virtio device config read/wri...



details:   https://anonhg.NetBSD.org/src/rev/2f4ced9fd5bd
branches:  trunk
changeset: 950411:2f4ced9fd5bd
user:      reinoud <reinoud%NetBSD.org@localhost>
date:      Thu Jan 28 15:43:12 2021 +0000

description:
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.

diffstat:

 sys/dev/pci/virtio.c         |  176 +++++++++++++++++++++-----
 sys/dev/pci/virtio_pci.c     |  282 +++++-------------------------------------
 sys/dev/pci/virtiovar.h      |   19 +-
 sys/dev/virtio/virtio_mmio.c |  150 ++--------------------
 4 files changed, 199 insertions(+), 428 deletions(-)

diffs (truncated from 881 to 300 lines):

diff -r d8d9c0933c13 -r 2f4ced9fd5bd sys/dev/pci/virtio.c
--- a/sys/dev/pci/virtio.c      Thu Jan 28 14:57:43 2021 +0000
+++ b/sys/dev/pci/virtio.c      Thu Jan 28 15:43:12 2021 +0000
@@ -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 @@
        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;
 }
 
 
diff -r d8d9c0933c13 -r 2f4ced9fd5bd sys/dev/pci/virtio_pci.c
--- a/sys/dev/pci/virtio_pci.c  Thu Jan 28 14:57:43 2021 +0000
+++ b/sys/dev/pci/virtio_pci.c  Thu Jan 28 15:43:12 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: virtio_pci.c,v 1.26 2021/01/26 16:40:16 reinoud Exp $ */



Home | Main Index | Thread Index | Old Index