The branch main has been updated by bryanv:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=926cedd9a0713c8ed9ff340b09401847b8bfd62c

commit 926cedd9a0713c8ed9ff340b09401847b8bfd62c
Author:     Bryan Venteicher <[email protected]>
AuthorDate: 2022-08-17 20:15:04 +0000
Commit:     Bryan Venteicher <[email protected]>
CommitDate: 2022-08-17 20:15:04 +0000

    virtio_mmio: Improve V1 spec conformance
    
    Implement the virtio_bus_finalize_features method so the FEATURES_OK
    status bit is set. Implement the virtio_bus_config_generation method
    to ensure larger than 4-byte reads are consistent.
    
    Reviewed by:    cperciva
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D36150
---
 sys/dev/virtio/mmio/virtio_mmio.c | 87 +++++++++++++++++++++++++++++++++++----
 1 file changed, 78 insertions(+), 9 deletions(-)

diff --git a/sys/dev/virtio/mmio/virtio_mmio.c 
b/sys/dev/virtio/mmio/virtio_mmio.c
index 5e17cf59a84a..e2164eb9e195 100644
--- a/sys/dev/virtio/mmio/virtio_mmio.c
+++ b/sys/dev/virtio/mmio/virtio_mmio.c
@@ -74,6 +74,7 @@ static void   vtmmio_child_detached(device_t, device_t);
 static int     vtmmio_read_ivar(device_t, device_t, int, uintptr_t *);
 static int     vtmmio_write_ivar(device_t, device_t, int, uintptr_t);
 static uint64_t        vtmmio_negotiate_features(device_t, uint64_t);
+static int     vtmmio_finalize_features(device_t);
 static int     vtmmio_with_feature(device_t, uint64_t);
 static void    vtmmio_set_virtqueue(struct vtmmio_softc *sc,
                    struct virtqueue *vq, uint32_t size);
@@ -85,9 +86,11 @@ static void  vtmmio_poll(device_t);
 static int     vtmmio_reinit(device_t, uint64_t);
 static void    vtmmio_reinit_complete(device_t);
 static void    vtmmio_notify_virtqueue(device_t, uint16_t, bus_size_t);
+static int     vtmmio_config_generation(device_t);
 static uint8_t vtmmio_get_status(device_t);
 static void    vtmmio_set_status(device_t, uint8_t);
 static void    vtmmio_read_dev_config(device_t, bus_size_t, void *, int);
+static uint64_t        vtmmio_read_dev_config_8(struct vtmmio_softc *, 
bus_size_t);
 static void    vtmmio_write_dev_config(device_t, bus_size_t, const void *, 
int);
 static void    vtmmio_describe_features(struct vtmmio_softc *, const char *,
                    uint64_t);
@@ -152,6 +155,7 @@ static device_method_t vtmmio_methods[] = {
 
        /* VirtIO bus interface. */
        DEVMETHOD(virtio_bus_negotiate_features,  vtmmio_negotiate_features),
+       DEVMETHOD(virtio_bus_finalize_features,   vtmmio_finalize_features),
        DEVMETHOD(virtio_bus_with_feature,        vtmmio_with_feature),
        DEVMETHOD(virtio_bus_alloc_virtqueues,    vtmmio_alloc_virtqueues),
        DEVMETHOD(virtio_bus_setup_intr,          vtmmio_setup_intr),
@@ -160,6 +164,7 @@ static device_method_t vtmmio_methods[] = {
        DEVMETHOD(virtio_bus_reinit,              vtmmio_reinit),
        DEVMETHOD(virtio_bus_reinit_complete,     vtmmio_reinit_complete),
        DEVMETHOD(virtio_bus_notify_vq,           vtmmio_notify_virtqueue),
+       DEVMETHOD(virtio_bus_config_generation,   vtmmio_config_generation),
        DEVMETHOD(virtio_bus_read_device_config,  vtmmio_read_dev_config),
        DEVMETHOD(virtio_bus_write_device_config, vtmmio_write_dev_config),
 
@@ -461,6 +466,31 @@ vtmmio_negotiate_features(device_t dev, uint64_t 
child_features)
        return (features);
 }
 
+static int
+vtmmio_finalize_features(device_t dev)
+{
+       struct vtmmio_softc *sc;
+       uint8_t status;
+
+       sc = device_get_softc(dev);
+
+       if (sc->vtmmio_version > 1) {
+               /*
+                * Must re-read the status after setting it to verify the
+                * negotiated features were accepted by the device.
+                */
+               vtmmio_set_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
+
+               status = vtmmio_get_status(dev);
+               if ((status & VIRTIO_CONFIG_S_FEATURES_OK) == 0) {
+                       device_printf(dev, "desired features were not 
accepted\n");
+                       return (ENOTSUP);
+               }
+       }
+
+       return (0);
+}
+
 static int
 vtmmio_with_feature(device_t dev, uint64_t feature)
 {
@@ -540,8 +570,6 @@ vtmmio_alloc_virtqueues(device_t dev, int flags, int nvqs,
                vqx = &sc->vtmmio_vqs[idx];
                info = &vq_info[idx];
 
-               vtmmio_write_config_4(sc, VIRTIO_MMIO_QUEUE_SEL, idx);
-
                vtmmio_select_virtqueue(sc, idx);
                size = vtmmio_read_config_4(sc, VIRTIO_MMIO_QUEUE_NUM_MAX);
 
@@ -605,7 +633,16 @@ vtmmio_reinit(device_t dev, uint64_t features)
        vtmmio_set_status(dev, VIRTIO_CONFIG_STATUS_ACK);
        vtmmio_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER);
 
+       /*
+        * TODO: Check that features are not added as to what was
+        * originally negotiated.
+        */
        vtmmio_negotiate_features(dev, features);
+       error = vtmmio_finalize_features(dev);
+       if (error) {
+               device_printf(dev, "cannot finalize features during reinit\n");
+               return (error);
+       }
 
        if (sc->vtmmio_version == 1) {
                vtmmio_write_config_4(sc, VIRTIO_MMIO_GUEST_PAGE_SIZE,
@@ -639,6 +676,22 @@ vtmmio_notify_virtqueue(device_t dev, uint16_t queue, 
bus_size_t offset)
        vtmmio_write_config_4(sc, offset, queue);
 }
 
+static int
+vtmmio_config_generation(device_t dev)
+{
+       struct vtmmio_softc *sc;
+       uint32_t gen;
+
+       sc = device_get_softc(dev);
+
+       if (sc->vtmmio_version > 1)
+               gen = vtmmio_read_config_4(sc, VIRTIO_MMIO_CONFIG_GENERATION);
+       else
+               gen = 0;
+
+       return (gen);
+}
+
 static uint8_t
 vtmmio_get_status(device_t dev)
 {
@@ -670,7 +723,6 @@ vtmmio_read_dev_config(device_t dev, bus_size_t offset,
        bus_size_t off;
        uint8_t *d;
        int size;
-       uint64_t low32, high32;
 
        sc = device_get_softc(dev);
        off = VIRTIO_MMIO_CONFIG + offset;
@@ -707,9 +759,7 @@ vtmmio_read_dev_config(device_t dev, bus_size_t offset,
                            le32toh(vtmmio_read_config_4(sc, off));
                        break;
                case 8:
-                       low32 = le32toh(vtmmio_read_config_4(sc, off));
-                       high32 = le32toh(vtmmio_read_config_4(sc, off + 4));
-                       *(uint64_t *)dst = (high32 << 32) | low32;
+                       *(uint64_t *)dst = vtmmio_read_dev_config_8(sc, off);
                        break;
                default:
                        panic("%s: invalid length %d\n", __func__, length);
@@ -735,6 +785,24 @@ vtmmio_read_dev_config(device_t dev, bus_size_t offset,
        }
 }
 
+static uint64_t
+vtmmio_read_dev_config_8(struct vtmmio_softc *sc, bus_size_t off)
+{
+       device_t dev;
+       int gen;
+       uint32_t val0, val1;
+
+       dev = sc->dev;
+
+       do {
+               gen = vtmmio_config_generation(dev);
+               val0 = le32toh(vtmmio_read_config_4(sc, off));
+               val1 = le32toh(vtmmio_read_config_4(sc, off + 4));
+       } while (gen != vtmmio_config_generation(dev));
+
+       return (((uint64_t) val1 << 32) | val0);
+}
+
 static void
 vtmmio_write_dev_config(device_t dev, bus_size_t offset,
     const void *src, int length)
@@ -888,10 +956,11 @@ vtmmio_free_virtqueues(struct vtmmio_softc *sc)
                vqx = &sc->vtmmio_vqs[idx];
 
                vtmmio_select_virtqueue(sc, idx);
-               if (sc->vtmmio_version == 1)
-                       vtmmio_write_config_4(sc, VIRTIO_MMIO_QUEUE_PFN, 0);
-               else
+               if (sc->vtmmio_version > 1) {
                        vtmmio_write_config_4(sc, VIRTIO_MMIO_QUEUE_READY, 0);
+                       vtmmio_read_config_4(sc, VIRTIO_MMIO_QUEUE_READY);
+               } else
+                       vtmmio_write_config_4(sc, VIRTIO_MMIO_QUEUE_PFN, 0);
 
                virtqueue_free(vqx->vtv_vq);
                vqx->vtv_vq = NULL;

Reply via email to