19da9560cSBryan Venteicher /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 39da9560cSBryan Venteicher * 49da9560cSBryan Venteicher * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org> 59da9560cSBryan Venteicher * All rights reserved. 69da9560cSBryan Venteicher * 79da9560cSBryan Venteicher * Redistribution and use in source and binary forms, with or without 89da9560cSBryan Venteicher * modification, are permitted provided that the following conditions 99da9560cSBryan Venteicher * are met: 109da9560cSBryan Venteicher * 1. Redistributions of source code must retain the above copyright 119da9560cSBryan Venteicher * notice unmodified, this list of conditions, and the following 129da9560cSBryan Venteicher * disclaimer. 139da9560cSBryan Venteicher * 2. Redistributions in binary form must reproduce the above copyright 149da9560cSBryan Venteicher * notice, this list of conditions and the following disclaimer in the 159da9560cSBryan Venteicher * documentation and/or other materials provided with the distribution. 169da9560cSBryan Venteicher * 179da9560cSBryan Venteicher * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 189da9560cSBryan Venteicher * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 199da9560cSBryan Venteicher * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 209da9560cSBryan Venteicher * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 219da9560cSBryan Venteicher * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 229da9560cSBryan Venteicher * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239da9560cSBryan Venteicher * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249da9560cSBryan Venteicher * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259da9560cSBryan Venteicher * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 269da9560cSBryan Venteicher * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279da9560cSBryan Venteicher */ 289da9560cSBryan Venteicher 299da9560cSBryan Venteicher /* Driver for the legacy VirtIO PCI interface. */ 309da9560cSBryan Venteicher 319da9560cSBryan Venteicher #include <sys/param.h> 329da9560cSBryan Venteicher #include <sys/systm.h> 339da9560cSBryan Venteicher #include <sys/bus.h> 349da9560cSBryan Venteicher #include <sys/lock.h> 359da9560cSBryan Venteicher #include <sys/kernel.h> 369da9560cSBryan Venteicher #include <sys/module.h> 379da9560cSBryan Venteicher #include <sys/endian.h> 389da9560cSBryan Venteicher 399da9560cSBryan Venteicher #include <machine/bus.h> 409da9560cSBryan Venteicher #include <machine/resource.h> 419da9560cSBryan Venteicher #include <sys/bus.h> 429da9560cSBryan Venteicher #include <sys/rman.h> 439da9560cSBryan Venteicher 449da9560cSBryan Venteicher #include <dev/pci/pcivar.h> 459da9560cSBryan Venteicher #include <dev/pci/pcireg.h> 469da9560cSBryan Venteicher 479da9560cSBryan Venteicher #include <dev/virtio/virtio.h> 489da9560cSBryan Venteicher #include <dev/virtio/virtqueue.h> 499da9560cSBryan Venteicher #include <dev/virtio/pci/virtio_pci.h> 509da9560cSBryan Venteicher #include <dev/virtio/pci/virtio_pci_legacy_var.h> 519da9560cSBryan Venteicher 529da9560cSBryan Venteicher #include "virtio_bus_if.h" 539da9560cSBryan Venteicher #include "virtio_pci_if.h" 549da9560cSBryan Venteicher #include "virtio_if.h" 559da9560cSBryan Venteicher 569da9560cSBryan Venteicher struct vtpci_legacy_softc { 579da9560cSBryan Venteicher device_t vtpci_dev; 589da9560cSBryan Venteicher struct vtpci_common vtpci_common; 59cf5d1112SKa Ho Ng int vtpci_res_type; 609da9560cSBryan Venteicher struct resource *vtpci_res; 61faf9a4e9SKa Ho Ng struct resource *vtpci_msix_table_res; 62faf9a4e9SKa Ho Ng struct resource *vtpci_msix_pba_res; 639da9560cSBryan Venteicher }; 649da9560cSBryan Venteicher 659da9560cSBryan Venteicher static int vtpci_legacy_probe(device_t); 669da9560cSBryan Venteicher static int vtpci_legacy_attach(device_t); 679da9560cSBryan Venteicher static int vtpci_legacy_detach(device_t); 689da9560cSBryan Venteicher static int vtpci_legacy_suspend(device_t); 699da9560cSBryan Venteicher static int vtpci_legacy_resume(device_t); 709da9560cSBryan Venteicher static int vtpci_legacy_shutdown(device_t); 719da9560cSBryan Venteicher 729da9560cSBryan Venteicher static void vtpci_legacy_driver_added(device_t, driver_t *); 739da9560cSBryan Venteicher static void vtpci_legacy_child_detached(device_t, device_t); 749da9560cSBryan Venteicher static int vtpci_legacy_read_ivar(device_t, device_t, int, uintptr_t *); 759da9560cSBryan Venteicher static int vtpci_legacy_write_ivar(device_t, device_t, int, uintptr_t); 769da9560cSBryan Venteicher 779da9560cSBryan Venteicher static uint8_t vtpci_legacy_read_isr(device_t); 789da9560cSBryan Venteicher static uint16_t vtpci_legacy_get_vq_size(device_t, int); 799da9560cSBryan Venteicher static bus_size_t vtpci_legacy_get_vq_notify_off(device_t, int); 809da9560cSBryan Venteicher static void vtpci_legacy_set_vq(device_t, struct virtqueue *); 819da9560cSBryan Venteicher static void vtpci_legacy_disable_vq(device_t, int); 829da9560cSBryan Venteicher static int vtpci_legacy_register_cfg_msix(device_t, 839da9560cSBryan Venteicher struct vtpci_interrupt *); 849da9560cSBryan Venteicher static int vtpci_legacy_register_vq_msix(device_t, int idx, 859da9560cSBryan Venteicher struct vtpci_interrupt *); 869da9560cSBryan Venteicher 879da9560cSBryan Venteicher static uint64_t vtpci_legacy_negotiate_features(device_t, uint64_t); 88ccb576a8SMina Galić static bool vtpci_legacy_with_feature(device_t, uint64_t); 89180c0240SMina Galić static int vtpci_legacy_alloc_virtqueues(device_t, int, 909da9560cSBryan Venteicher struct vq_alloc_info *); 919da9560cSBryan Venteicher static int vtpci_legacy_setup_interrupts(device_t, enum intr_type); 929da9560cSBryan Venteicher static void vtpci_legacy_stop(device_t); 939da9560cSBryan Venteicher static int vtpci_legacy_reinit(device_t, uint64_t); 949da9560cSBryan Venteicher static void vtpci_legacy_reinit_complete(device_t); 959da9560cSBryan Venteicher static void vtpci_legacy_notify_vq(device_t, uint16_t, bus_size_t); 969da9560cSBryan Venteicher static void vtpci_legacy_read_dev_config(device_t, bus_size_t, void *, int); 976c4f9516SAlex Richardson static void vtpci_legacy_write_dev_config(device_t, bus_size_t, const void *, int); 989da9560cSBryan Venteicher 99faf9a4e9SKa Ho Ng static bool vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc); 100faf9a4e9SKa Ho Ng static void vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc); 1019da9560cSBryan Venteicher static int vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *); 1029da9560cSBryan Venteicher static void vtpci_legacy_free_resources(struct vtpci_legacy_softc *); 1039da9560cSBryan Venteicher 1049da9560cSBryan Venteicher static void vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *); 1059da9560cSBryan Venteicher 1069da9560cSBryan Venteicher static uint8_t vtpci_legacy_get_status(struct vtpci_legacy_softc *); 1079da9560cSBryan Venteicher static void vtpci_legacy_set_status(struct vtpci_legacy_softc *, uint8_t); 1089da9560cSBryan Venteicher static void vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *, int); 1099da9560cSBryan Venteicher static void vtpci_legacy_reset(struct vtpci_legacy_softc *); 1109da9560cSBryan Venteicher 1119da9560cSBryan Venteicher #define VIRTIO_PCI_LEGACY_CONFIG(_sc) \ 1129da9560cSBryan Venteicher VIRTIO_PCI_CONFIG_OFF(vtpci_is_msix_enabled(&(_sc)->vtpci_common)) 1139da9560cSBryan Venteicher 1149da9560cSBryan Venteicher #define vtpci_legacy_read_config_1(sc, o) \ 1159da9560cSBryan Venteicher bus_read_1((sc)->vtpci_res, (o)) 1169da9560cSBryan Venteicher #define vtpci_legacy_write_config_1(sc, o, v) \ 1179da9560cSBryan Venteicher bus_write_1((sc)->vtpci_res, (o), (v)) 1189da9560cSBryan Venteicher /* 1199da9560cSBryan Venteicher * VirtIO specifies that PCI Configuration area is guest endian. However, 1209da9560cSBryan Venteicher * since PCI devices are inherently little-endian, on big-endian systems 1219da9560cSBryan Venteicher * the bus layer transparently converts it to BE. For virtio-legacy, this 1229da9560cSBryan Venteicher * conversion is undesired, so an extra byte swap is required to fix it. 1239da9560cSBryan Venteicher */ 1249da9560cSBryan Venteicher #define vtpci_legacy_read_config_2(sc, o) \ 1259da9560cSBryan Venteicher le16toh(bus_read_2((sc)->vtpci_res, (o))) 1269da9560cSBryan Venteicher #define vtpci_legacy_read_config_4(sc, o) \ 1279da9560cSBryan Venteicher le32toh(bus_read_4((sc)->vtpci_res, (o))) 1289da9560cSBryan Venteicher #define vtpci_legacy_write_config_2(sc, o, v) \ 1299da9560cSBryan Venteicher bus_write_2((sc)->vtpci_res, (o), (htole16(v))) 1309da9560cSBryan Venteicher #define vtpci_legacy_write_config_4(sc, o, v) \ 1319da9560cSBryan Venteicher bus_write_4((sc)->vtpci_res, (o), (htole32(v))) 1329da9560cSBryan Venteicher /* PCI Header LE. On BE systems the bus layer takes care of byte swapping. */ 1339da9560cSBryan Venteicher #define vtpci_legacy_read_header_2(sc, o) \ 1349da9560cSBryan Venteicher bus_read_2((sc)->vtpci_res, (o)) 1359da9560cSBryan Venteicher #define vtpci_legacy_read_header_4(sc, o) \ 1369da9560cSBryan Venteicher bus_read_4((sc)->vtpci_res, (o)) 1379da9560cSBryan Venteicher #define vtpci_legacy_write_header_2(sc, o, v) \ 1389da9560cSBryan Venteicher bus_write_2((sc)->vtpci_res, (o), (v)) 1399da9560cSBryan Venteicher #define vtpci_legacy_write_header_4(sc, o, v) \ 1409da9560cSBryan Venteicher bus_write_4((sc)->vtpci_res, (o), (v)) 1419da9560cSBryan Venteicher 1429da9560cSBryan Venteicher static device_method_t vtpci_legacy_methods[] = { 1439da9560cSBryan Venteicher /* Device interface. */ 1449da9560cSBryan Venteicher DEVMETHOD(device_probe, vtpci_legacy_probe), 1459da9560cSBryan Venteicher DEVMETHOD(device_attach, vtpci_legacy_attach), 1469da9560cSBryan Venteicher DEVMETHOD(device_detach, vtpci_legacy_detach), 1479da9560cSBryan Venteicher DEVMETHOD(device_suspend, vtpci_legacy_suspend), 1489da9560cSBryan Venteicher DEVMETHOD(device_resume, vtpci_legacy_resume), 1499da9560cSBryan Venteicher DEVMETHOD(device_shutdown, vtpci_legacy_shutdown), 1509da9560cSBryan Venteicher 1519da9560cSBryan Venteicher /* Bus interface. */ 1529da9560cSBryan Venteicher DEVMETHOD(bus_driver_added, vtpci_legacy_driver_added), 1539da9560cSBryan Venteicher DEVMETHOD(bus_child_detached, vtpci_legacy_child_detached), 154ddfc9c4cSWarner Losh DEVMETHOD(bus_child_pnpinfo, virtio_child_pnpinfo), 1559da9560cSBryan Venteicher DEVMETHOD(bus_read_ivar, vtpci_legacy_read_ivar), 1569da9560cSBryan Venteicher DEVMETHOD(bus_write_ivar, vtpci_legacy_write_ivar), 1579da9560cSBryan Venteicher 1589da9560cSBryan Venteicher /* VirtIO PCI interface. */ 1599da9560cSBryan Venteicher DEVMETHOD(virtio_pci_read_isr, vtpci_legacy_read_isr), 1609da9560cSBryan Venteicher DEVMETHOD(virtio_pci_get_vq_size, vtpci_legacy_get_vq_size), 1619da9560cSBryan Venteicher DEVMETHOD(virtio_pci_get_vq_notify_off, vtpci_legacy_get_vq_notify_off), 1629da9560cSBryan Venteicher DEVMETHOD(virtio_pci_set_vq, vtpci_legacy_set_vq), 1639da9560cSBryan Venteicher DEVMETHOD(virtio_pci_disable_vq, vtpci_legacy_disable_vq), 1649da9560cSBryan Venteicher DEVMETHOD(virtio_pci_register_cfg_msix, vtpci_legacy_register_cfg_msix), 1659da9560cSBryan Venteicher DEVMETHOD(virtio_pci_register_vq_msix, vtpci_legacy_register_vq_msix), 1669da9560cSBryan Venteicher 1679da9560cSBryan Venteicher /* VirtIO bus interface. */ 1689da9560cSBryan Venteicher DEVMETHOD(virtio_bus_negotiate_features, vtpci_legacy_negotiate_features), 1699da9560cSBryan Venteicher DEVMETHOD(virtio_bus_with_feature, vtpci_legacy_with_feature), 1709da9560cSBryan Venteicher DEVMETHOD(virtio_bus_alloc_virtqueues, vtpci_legacy_alloc_virtqueues), 1719da9560cSBryan Venteicher DEVMETHOD(virtio_bus_setup_intr, vtpci_legacy_setup_interrupts), 1729da9560cSBryan Venteicher DEVMETHOD(virtio_bus_stop, vtpci_legacy_stop), 1739da9560cSBryan Venteicher DEVMETHOD(virtio_bus_reinit, vtpci_legacy_reinit), 1749da9560cSBryan Venteicher DEVMETHOD(virtio_bus_reinit_complete, vtpci_legacy_reinit_complete), 1759da9560cSBryan Venteicher DEVMETHOD(virtio_bus_notify_vq, vtpci_legacy_notify_vq), 1769da9560cSBryan Venteicher DEVMETHOD(virtio_bus_read_device_config, vtpci_legacy_read_dev_config), 1779da9560cSBryan Venteicher DEVMETHOD(virtio_bus_write_device_config, vtpci_legacy_write_dev_config), 1789da9560cSBryan Venteicher 1799da9560cSBryan Venteicher DEVMETHOD_END 1809da9560cSBryan Venteicher }; 1819da9560cSBryan Venteicher 1829da9560cSBryan Venteicher static driver_t vtpci_legacy_driver = { 1839da9560cSBryan Venteicher .name = "virtio_pci", 1849da9560cSBryan Venteicher .methods = vtpci_legacy_methods, 1859da9560cSBryan Venteicher .size = sizeof(struct vtpci_legacy_softc) 1869da9560cSBryan Venteicher }; 1879da9560cSBryan Venteicher 1885c4c96d3SJohn Baldwin DRIVER_MODULE(virtio_pci_legacy, pci, vtpci_legacy_driver, 0, 0); 1899da9560cSBryan Venteicher 1909da9560cSBryan Venteicher static int 1919da9560cSBryan Venteicher vtpci_legacy_probe(device_t dev) 1929da9560cSBryan Venteicher { 1939da9560cSBryan Venteicher const char *name; 1949da9560cSBryan Venteicher 1959da9560cSBryan Venteicher if (pci_get_vendor(dev) != VIRTIO_PCI_VENDORID) 1969da9560cSBryan Venteicher return (ENXIO); 1979da9560cSBryan Venteicher 1989da9560cSBryan Venteicher if (pci_get_device(dev) < VIRTIO_PCI_DEVICEID_MIN || 1999da9560cSBryan Venteicher pci_get_device(dev) > VIRTIO_PCI_DEVICEID_LEGACY_MAX) 2009da9560cSBryan Venteicher return (ENXIO); 2019da9560cSBryan Venteicher 2029da9560cSBryan Venteicher if (pci_get_revid(dev) != VIRTIO_PCI_ABI_VERSION) 2039da9560cSBryan Venteicher return (ENXIO); 2049da9560cSBryan Venteicher 2059da9560cSBryan Venteicher name = virtio_device_name(pci_get_subdevice(dev)); 2069da9560cSBryan Venteicher if (name == NULL) 2079da9560cSBryan Venteicher name = "Unknown"; 2089da9560cSBryan Venteicher 209*de140d60SMark Johnston device_set_descf(dev, "VirtIO PCI (legacy) %s adapter", name); 2109da9560cSBryan Venteicher 2119da9560cSBryan Venteicher /* Prefer transitional modern VirtIO PCI. */ 2129da9560cSBryan Venteicher return (BUS_PROBE_LOW_PRIORITY); 2139da9560cSBryan Venteicher } 2149da9560cSBryan Venteicher 2159da9560cSBryan Venteicher static int 2169da9560cSBryan Venteicher vtpci_legacy_attach(device_t dev) 2179da9560cSBryan Venteicher { 2189da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 2199da9560cSBryan Venteicher int error; 2209da9560cSBryan Venteicher 2219da9560cSBryan Venteicher sc = device_get_softc(dev); 2229da9560cSBryan Venteicher sc->vtpci_dev = dev; 2239da9560cSBryan Venteicher vtpci_init(&sc->vtpci_common, dev, false); 2249da9560cSBryan Venteicher 2259da9560cSBryan Venteicher error = vtpci_legacy_alloc_resources(sc); 2269da9560cSBryan Venteicher if (error) { 227cf5d1112SKa Ho Ng device_printf(dev, "cannot map I/O space nor memory space\n"); 2289da9560cSBryan Venteicher return (error); 2299da9560cSBryan Venteicher } 2309da9560cSBryan Venteicher 231faf9a4e9SKa Ho Ng if (vtpci_is_msix_available(&sc->vtpci_common) && 232faf9a4e9SKa Ho Ng !vtpci_legacy_setup_msix(sc)) { 233faf9a4e9SKa Ho Ng device_printf(dev, "cannot setup MSI-x resources\n"); 234faf9a4e9SKa Ho Ng error = ENXIO; 235faf9a4e9SKa Ho Ng goto fail; 236faf9a4e9SKa Ho Ng } 237faf9a4e9SKa Ho Ng 2389da9560cSBryan Venteicher vtpci_legacy_reset(sc); 2399da9560cSBryan Venteicher 2409da9560cSBryan Venteicher /* Tell the host we've noticed this device. */ 2419da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK); 2429da9560cSBryan Venteicher 2439da9560cSBryan Venteicher error = vtpci_add_child(&sc->vtpci_common); 2449da9560cSBryan Venteicher if (error) 2459da9560cSBryan Venteicher goto fail; 2469da9560cSBryan Venteicher 2479da9560cSBryan Venteicher vtpci_legacy_probe_and_attach_child(sc); 2489da9560cSBryan Venteicher 2499da9560cSBryan Venteicher return (0); 2509da9560cSBryan Venteicher 2519da9560cSBryan Venteicher fail: 2529da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_FAILED); 2539da9560cSBryan Venteicher vtpci_legacy_detach(dev); 2549da9560cSBryan Venteicher 2559da9560cSBryan Venteicher return (error); 2569da9560cSBryan Venteicher } 2579da9560cSBryan Venteicher 2589da9560cSBryan Venteicher static int 2599da9560cSBryan Venteicher vtpci_legacy_detach(device_t dev) 2609da9560cSBryan Venteicher { 2619da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 2629da9560cSBryan Venteicher int error; 2639da9560cSBryan Venteicher 2649da9560cSBryan Venteicher sc = device_get_softc(dev); 2659da9560cSBryan Venteicher 2669da9560cSBryan Venteicher error = vtpci_delete_child(&sc->vtpci_common); 2679da9560cSBryan Venteicher if (error) 2689da9560cSBryan Venteicher return (error); 2699da9560cSBryan Venteicher 2709da9560cSBryan Venteicher vtpci_legacy_reset(sc); 271faf9a4e9SKa Ho Ng vtpci_legacy_teardown_msix(sc); 2729da9560cSBryan Venteicher vtpci_legacy_free_resources(sc); 2739da9560cSBryan Venteicher 2749da9560cSBryan Venteicher return (0); 2759da9560cSBryan Venteicher } 2769da9560cSBryan Venteicher 2779da9560cSBryan Venteicher static int 2789da9560cSBryan Venteicher vtpci_legacy_suspend(device_t dev) 2799da9560cSBryan Venteicher { 2809da9560cSBryan Venteicher return (bus_generic_suspend(dev)); 2819da9560cSBryan Venteicher } 2829da9560cSBryan Venteicher 2839da9560cSBryan Venteicher static int 2849da9560cSBryan Venteicher vtpci_legacy_resume(device_t dev) 2859da9560cSBryan Venteicher { 2869da9560cSBryan Venteicher return (bus_generic_resume(dev)); 2879da9560cSBryan Venteicher } 2889da9560cSBryan Venteicher 2899da9560cSBryan Venteicher static int 2909da9560cSBryan Venteicher vtpci_legacy_shutdown(device_t dev) 2919da9560cSBryan Venteicher { 2929da9560cSBryan Venteicher (void) bus_generic_shutdown(dev); 2939da9560cSBryan Venteicher /* Forcibly stop the host device. */ 2949da9560cSBryan Venteicher vtpci_legacy_stop(dev); 2959da9560cSBryan Venteicher 2969da9560cSBryan Venteicher return (0); 2979da9560cSBryan Venteicher } 2989da9560cSBryan Venteicher 2999da9560cSBryan Venteicher static void 3009da9560cSBryan Venteicher vtpci_legacy_driver_added(device_t dev, driver_t *driver) 3019da9560cSBryan Venteicher { 3029da9560cSBryan Venteicher vtpci_legacy_probe_and_attach_child(device_get_softc(dev)); 3039da9560cSBryan Venteicher } 3049da9560cSBryan Venteicher 3059da9560cSBryan Venteicher static void 3069da9560cSBryan Venteicher vtpci_legacy_child_detached(device_t dev, device_t child) 3079da9560cSBryan Venteicher { 3089da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3099da9560cSBryan Venteicher 3109da9560cSBryan Venteicher sc = device_get_softc(dev); 3119da9560cSBryan Venteicher 3129da9560cSBryan Venteicher vtpci_legacy_reset(sc); 3139da9560cSBryan Venteicher vtpci_child_detached(&sc->vtpci_common); 3149da9560cSBryan Venteicher 3159da9560cSBryan Venteicher /* After the reset, retell the host we've noticed this device. */ 3169da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK); 3179da9560cSBryan Venteicher } 3189da9560cSBryan Venteicher 3199da9560cSBryan Venteicher static int 3209da9560cSBryan Venteicher vtpci_legacy_read_ivar(device_t dev, device_t child, int index, 3219da9560cSBryan Venteicher uintptr_t *result) 3229da9560cSBryan Venteicher { 3239da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3249da9560cSBryan Venteicher struct vtpci_common *cn; 3259da9560cSBryan Venteicher 3269da9560cSBryan Venteicher sc = device_get_softc(dev); 3279da9560cSBryan Venteicher cn = &sc->vtpci_common; 3289da9560cSBryan Venteicher 3299da9560cSBryan Venteicher if (vtpci_child_device(cn) != child) 3309da9560cSBryan Venteicher return (ENOENT); 3319da9560cSBryan Venteicher 3329da9560cSBryan Venteicher switch (index) { 3339da9560cSBryan Venteicher case VIRTIO_IVAR_DEVTYPE: 3349da9560cSBryan Venteicher *result = pci_get_subdevice(dev); 3359da9560cSBryan Venteicher break; 3369da9560cSBryan Venteicher default: 3379da9560cSBryan Venteicher return (vtpci_read_ivar(cn, index, result)); 3389da9560cSBryan Venteicher } 3399da9560cSBryan Venteicher 3409da9560cSBryan Venteicher return (0); 3419da9560cSBryan Venteicher } 3429da9560cSBryan Venteicher 3439da9560cSBryan Venteicher static int 3449da9560cSBryan Venteicher vtpci_legacy_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 3459da9560cSBryan Venteicher { 3469da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3479da9560cSBryan Venteicher struct vtpci_common *cn; 3489da9560cSBryan Venteicher 3499da9560cSBryan Venteicher sc = device_get_softc(dev); 3509da9560cSBryan Venteicher cn = &sc->vtpci_common; 3519da9560cSBryan Venteicher 3529da9560cSBryan Venteicher if (vtpci_child_device(cn) != child) 3539da9560cSBryan Venteicher return (ENOENT); 3549da9560cSBryan Venteicher 3559da9560cSBryan Venteicher switch (index) { 3569da9560cSBryan Venteicher default: 3579da9560cSBryan Venteicher return (vtpci_write_ivar(cn, index, value)); 3589da9560cSBryan Venteicher } 3599da9560cSBryan Venteicher 3609da9560cSBryan Venteicher return (0); 3619da9560cSBryan Venteicher } 3629da9560cSBryan Venteicher 3639da9560cSBryan Venteicher static uint64_t 3649da9560cSBryan Venteicher vtpci_legacy_negotiate_features(device_t dev, uint64_t child_features) 3659da9560cSBryan Venteicher { 3669da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3679da9560cSBryan Venteicher uint64_t host_features, features; 3689da9560cSBryan Venteicher 3699da9560cSBryan Venteicher sc = device_get_softc(dev); 3709da9560cSBryan Venteicher host_features = vtpci_legacy_read_header_4(sc, VIRTIO_PCI_HOST_FEATURES); 3719da9560cSBryan Venteicher 3729da9560cSBryan Venteicher features = vtpci_negotiate_features(&sc->vtpci_common, 3739da9560cSBryan Venteicher child_features, host_features); 3749da9560cSBryan Venteicher vtpci_legacy_write_header_4(sc, VIRTIO_PCI_GUEST_FEATURES, features); 3759da9560cSBryan Venteicher 3769da9560cSBryan Venteicher return (features); 3779da9560cSBryan Venteicher } 3789da9560cSBryan Venteicher 379ccb576a8SMina Galić static bool 3809da9560cSBryan Venteicher vtpci_legacy_with_feature(device_t dev, uint64_t feature) 3819da9560cSBryan Venteicher { 3829da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3839da9560cSBryan Venteicher 3849da9560cSBryan Venteicher sc = device_get_softc(dev); 3859da9560cSBryan Venteicher 3869da9560cSBryan Venteicher return (vtpci_with_feature(&sc->vtpci_common, feature)); 3879da9560cSBryan Venteicher } 3889da9560cSBryan Venteicher 3899da9560cSBryan Venteicher static int 390180c0240SMina Galić vtpci_legacy_alloc_virtqueues(device_t dev, int nvqs, 3919da9560cSBryan Venteicher struct vq_alloc_info *vq_info) 3929da9560cSBryan Venteicher { 3939da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3949da9560cSBryan Venteicher struct vtpci_common *cn; 3959da9560cSBryan Venteicher 3969da9560cSBryan Venteicher sc = device_get_softc(dev); 3979da9560cSBryan Venteicher cn = &sc->vtpci_common; 3989da9560cSBryan Venteicher 399180c0240SMina Galić return (vtpci_alloc_virtqueues(cn, nvqs, vq_info)); 4009da9560cSBryan Venteicher } 4019da9560cSBryan Venteicher 4029da9560cSBryan Venteicher static int 4039da9560cSBryan Venteicher vtpci_legacy_setup_interrupts(device_t dev, enum intr_type type) 4049da9560cSBryan Venteicher { 4059da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4069da9560cSBryan Venteicher 4079da9560cSBryan Venteicher sc = device_get_softc(dev); 4089da9560cSBryan Venteicher 4099da9560cSBryan Venteicher return (vtpci_setup_interrupts(&sc->vtpci_common, type)); 4109da9560cSBryan Venteicher } 4119da9560cSBryan Venteicher 4129da9560cSBryan Venteicher static void 4139da9560cSBryan Venteicher vtpci_legacy_stop(device_t dev) 4149da9560cSBryan Venteicher { 4159da9560cSBryan Venteicher vtpci_legacy_reset(device_get_softc(dev)); 4169da9560cSBryan Venteicher } 4179da9560cSBryan Venteicher 4189da9560cSBryan Venteicher static int 4199da9560cSBryan Venteicher vtpci_legacy_reinit(device_t dev, uint64_t features) 4209da9560cSBryan Venteicher { 4219da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4229da9560cSBryan Venteicher struct vtpci_common *cn; 4239da9560cSBryan Venteicher int error; 4249da9560cSBryan Venteicher 4259da9560cSBryan Venteicher sc = device_get_softc(dev); 4269da9560cSBryan Venteicher cn = &sc->vtpci_common; 4279da9560cSBryan Venteicher 4289da9560cSBryan Venteicher /* 4299da9560cSBryan Venteicher * Redrive the device initialization. This is a bit of an abuse of 4309da9560cSBryan Venteicher * the specification, but VirtualBox, QEMU/KVM, and BHyVe seem to 4319da9560cSBryan Venteicher * play nice. 4329da9560cSBryan Venteicher * 4339da9560cSBryan Venteicher * We do not allow the host device to change from what was originally 4349da9560cSBryan Venteicher * negotiated beyond what the guest driver changed. MSIX state should 4359da9560cSBryan Venteicher * not change, number of virtqueues and their size remain the same, etc. 4369da9560cSBryan Venteicher * This will need to be rethought when we want to support migration. 4379da9560cSBryan Venteicher */ 4389da9560cSBryan Venteicher 4399da9560cSBryan Venteicher if (vtpci_legacy_get_status(sc) != VIRTIO_CONFIG_STATUS_RESET) 4409da9560cSBryan Venteicher vtpci_legacy_stop(dev); 4419da9560cSBryan Venteicher 4429da9560cSBryan Venteicher /* 4439da9560cSBryan Venteicher * Quickly drive the status through ACK and DRIVER. The device does 4449da9560cSBryan Venteicher * not become usable again until DRIVER_OK in reinit complete. 4459da9560cSBryan Venteicher */ 4469da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK); 4479da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER); 4489da9560cSBryan Venteicher 4499da9560cSBryan Venteicher vtpci_legacy_negotiate_features(dev, features); 4509da9560cSBryan Venteicher 4519da9560cSBryan Venteicher error = vtpci_reinit(cn); 4529da9560cSBryan Venteicher if (error) 4539da9560cSBryan Venteicher return (error); 4549da9560cSBryan Venteicher 4559da9560cSBryan Venteicher return (0); 4569da9560cSBryan Venteicher } 4579da9560cSBryan Venteicher 4589da9560cSBryan Venteicher static void 4599da9560cSBryan Venteicher vtpci_legacy_reinit_complete(device_t dev) 4609da9560cSBryan Venteicher { 4619da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4629da9560cSBryan Venteicher 4639da9560cSBryan Venteicher sc = device_get_softc(dev); 4649da9560cSBryan Venteicher 4659da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER_OK); 4669da9560cSBryan Venteicher } 4679da9560cSBryan Venteicher 4689da9560cSBryan Venteicher static void 4699da9560cSBryan Venteicher vtpci_legacy_notify_vq(device_t dev, uint16_t queue, bus_size_t offset) 4709da9560cSBryan Venteicher { 4719da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4729da9560cSBryan Venteicher 4739da9560cSBryan Venteicher sc = device_get_softc(dev); 4749da9560cSBryan Venteicher MPASS(offset == VIRTIO_PCI_QUEUE_NOTIFY); 4759da9560cSBryan Venteicher 4769da9560cSBryan Venteicher vtpci_legacy_write_header_2(sc, offset, queue); 4779da9560cSBryan Venteicher } 4789da9560cSBryan Venteicher 4799da9560cSBryan Venteicher static uint8_t 4809da9560cSBryan Venteicher vtpci_legacy_get_status(struct vtpci_legacy_softc *sc) 4819da9560cSBryan Venteicher { 4829da9560cSBryan Venteicher return (vtpci_legacy_read_config_1(sc, VIRTIO_PCI_STATUS)); 4839da9560cSBryan Venteicher } 4849da9560cSBryan Venteicher 4859da9560cSBryan Venteicher static void 4869da9560cSBryan Venteicher vtpci_legacy_set_status(struct vtpci_legacy_softc *sc, uint8_t status) 4879da9560cSBryan Venteicher { 4889da9560cSBryan Venteicher if (status != VIRTIO_CONFIG_STATUS_RESET) 4899da9560cSBryan Venteicher status |= vtpci_legacy_get_status(sc); 4909da9560cSBryan Venteicher 4919da9560cSBryan Venteicher vtpci_legacy_write_config_1(sc, VIRTIO_PCI_STATUS, status); 4929da9560cSBryan Venteicher } 4939da9560cSBryan Venteicher 4949da9560cSBryan Venteicher static void 4959da9560cSBryan Venteicher vtpci_legacy_read_dev_config(device_t dev, bus_size_t offset, 4969da9560cSBryan Venteicher void *dst, int length) 4979da9560cSBryan Venteicher { 4989da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4999da9560cSBryan Venteicher bus_size_t off; 5009da9560cSBryan Venteicher uint8_t *d; 50189c085b8SAndrew Turner int i; 5029da9560cSBryan Venteicher 5039da9560cSBryan Venteicher sc = device_get_softc(dev); 5049da9560cSBryan Venteicher off = VIRTIO_PCI_LEGACY_CONFIG(sc) + offset; 5059da9560cSBryan Venteicher 50689c085b8SAndrew Turner d = dst; 50789c085b8SAndrew Turner for (i = 0; i < length; i++) { 50889c085b8SAndrew Turner d[i] = vtpci_legacy_read_config_1(sc, off + i); 5099da9560cSBryan Venteicher } 5109da9560cSBryan Venteicher } 5119da9560cSBryan Venteicher 5129da9560cSBryan Venteicher static void 5139da9560cSBryan Venteicher vtpci_legacy_write_dev_config(device_t dev, bus_size_t offset, 5146c4f9516SAlex Richardson const void *src, int length) 5159da9560cSBryan Venteicher { 5169da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 5179da9560cSBryan Venteicher bus_size_t off; 5186c4f9516SAlex Richardson const uint8_t *s; 51989c085b8SAndrew Turner int i; 5209da9560cSBryan Venteicher 5219da9560cSBryan Venteicher sc = device_get_softc(dev); 5229da9560cSBryan Venteicher off = VIRTIO_PCI_LEGACY_CONFIG(sc) + offset; 5239da9560cSBryan Venteicher 52489c085b8SAndrew Turner s = src; 52589c085b8SAndrew Turner for (i = 0; i < length; i++) { 52689c085b8SAndrew Turner vtpci_legacy_write_config_1(sc, off + i, s[i]); 5279da9560cSBryan Venteicher } 5289da9560cSBryan Venteicher } 5299da9560cSBryan Venteicher 530faf9a4e9SKa Ho Ng static bool 531faf9a4e9SKa Ho Ng vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc) 532faf9a4e9SKa Ho Ng { 533faf9a4e9SKa Ho Ng device_t dev; 534faf9a4e9SKa Ho Ng int rid, table_rid; 535faf9a4e9SKa Ho Ng 536faf9a4e9SKa Ho Ng dev = sc->vtpci_dev; 537faf9a4e9SKa Ho Ng 538faf9a4e9SKa Ho Ng rid = table_rid = pci_msix_table_bar(dev); 539faf9a4e9SKa Ho Ng if (rid != PCIR_BAR(0)) { 540faf9a4e9SKa Ho Ng sc->vtpci_msix_table_res = bus_alloc_resource_any( 541faf9a4e9SKa Ho Ng dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 542faf9a4e9SKa Ho Ng if (sc->vtpci_msix_table_res == NULL) 543faf9a4e9SKa Ho Ng return (false); 544faf9a4e9SKa Ho Ng } 545faf9a4e9SKa Ho Ng 546faf9a4e9SKa Ho Ng rid = pci_msix_pba_bar(dev); 547faf9a4e9SKa Ho Ng if (rid != table_rid && rid != PCIR_BAR(0)) { 548faf9a4e9SKa Ho Ng sc->vtpci_msix_pba_res = bus_alloc_resource_any( 549faf9a4e9SKa Ho Ng dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 550faf9a4e9SKa Ho Ng if (sc->vtpci_msix_pba_res == NULL) 551faf9a4e9SKa Ho Ng return (false); 552faf9a4e9SKa Ho Ng } 553faf9a4e9SKa Ho Ng 554faf9a4e9SKa Ho Ng return (true); 555faf9a4e9SKa Ho Ng } 556faf9a4e9SKa Ho Ng 557faf9a4e9SKa Ho Ng static void 558faf9a4e9SKa Ho Ng vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc) 559faf9a4e9SKa Ho Ng { 560faf9a4e9SKa Ho Ng device_t dev; 561faf9a4e9SKa Ho Ng 562faf9a4e9SKa Ho Ng dev = sc->vtpci_dev; 563faf9a4e9SKa Ho Ng 564faf9a4e9SKa Ho Ng if (sc->vtpci_msix_pba_res != NULL) { 565faf9a4e9SKa Ho Ng bus_release_resource(dev, SYS_RES_MEMORY, 566faf9a4e9SKa Ho Ng rman_get_rid(sc->vtpci_msix_pba_res), 567faf9a4e9SKa Ho Ng sc->vtpci_msix_pba_res); 568faf9a4e9SKa Ho Ng sc->vtpci_msix_pba_res = NULL; 569faf9a4e9SKa Ho Ng } 570faf9a4e9SKa Ho Ng if (sc->vtpci_msix_table_res != NULL) { 571faf9a4e9SKa Ho Ng bus_release_resource(dev, SYS_RES_MEMORY, 572faf9a4e9SKa Ho Ng rman_get_rid(sc->vtpci_msix_table_res), 573faf9a4e9SKa Ho Ng sc->vtpci_msix_table_res); 574faf9a4e9SKa Ho Ng sc->vtpci_msix_table_res = NULL; 575faf9a4e9SKa Ho Ng } 576faf9a4e9SKa Ho Ng } 577faf9a4e9SKa Ho Ng 5789da9560cSBryan Venteicher static int 5799da9560cSBryan Venteicher vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *sc) 5809da9560cSBryan Venteicher { 581cf5d1112SKa Ho Ng const int res_types[] = { SYS_RES_IOPORT, SYS_RES_MEMORY }; 5829da9560cSBryan Venteicher device_t dev; 583cf5d1112SKa Ho Ng int rid, i; 5849da9560cSBryan Venteicher 5859da9560cSBryan Venteicher dev = sc->vtpci_dev; 5869da9560cSBryan Venteicher 587cf5d1112SKa Ho Ng /* 588cf5d1112SKa Ho Ng * Most hypervisors export the common configuration structure in IO 589cf5d1112SKa Ho Ng * space, but some use memory space; try both. 590cf5d1112SKa Ho Ng */ 591cf5d1112SKa Ho Ng for (i = 0; nitems(res_types); i++) { 5929da9560cSBryan Venteicher rid = PCIR_BAR(0); 593cf5d1112SKa Ho Ng sc->vtpci_res_type = res_types[i]; 594cf5d1112SKa Ho Ng sc->vtpci_res = bus_alloc_resource_any(dev, res_types[i], &rid, 595cf5d1112SKa Ho Ng RF_ACTIVE); 596cf5d1112SKa Ho Ng if (sc->vtpci_res != NULL) 597cf5d1112SKa Ho Ng break; 598cf5d1112SKa Ho Ng } 599cf5d1112SKa Ho Ng if (sc->vtpci_res == NULL) 6009da9560cSBryan Venteicher return (ENXIO); 6019da9560cSBryan Venteicher 6029da9560cSBryan Venteicher return (0); 6039da9560cSBryan Venteicher } 6049da9560cSBryan Venteicher 6059da9560cSBryan Venteicher static void 6069da9560cSBryan Venteicher vtpci_legacy_free_resources(struct vtpci_legacy_softc *sc) 6079da9560cSBryan Venteicher { 6089da9560cSBryan Venteicher device_t dev; 6099da9560cSBryan Venteicher 6109da9560cSBryan Venteicher dev = sc->vtpci_dev; 6119da9560cSBryan Venteicher 6129da9560cSBryan Venteicher if (sc->vtpci_res != NULL) { 613cf5d1112SKa Ho Ng bus_release_resource(dev, sc->vtpci_res_type, PCIR_BAR(0), 6149da9560cSBryan Venteicher sc->vtpci_res); 6159da9560cSBryan Venteicher sc->vtpci_res = NULL; 6169da9560cSBryan Venteicher } 6179da9560cSBryan Venteicher } 6189da9560cSBryan Venteicher 6199da9560cSBryan Venteicher static void 6209da9560cSBryan Venteicher vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *sc) 6219da9560cSBryan Venteicher { 6229da9560cSBryan Venteicher device_t dev, child; 6239da9560cSBryan Venteicher 6249da9560cSBryan Venteicher dev = sc->vtpci_dev; 6259da9560cSBryan Venteicher child = vtpci_child_device(&sc->vtpci_common); 6269da9560cSBryan Venteicher 6279da9560cSBryan Venteicher if (child == NULL || device_get_state(child) != DS_NOTPRESENT) 6289da9560cSBryan Venteicher return; 6299da9560cSBryan Venteicher 6309da9560cSBryan Venteicher if (device_probe(child) != 0) 6319da9560cSBryan Venteicher return; 6329da9560cSBryan Venteicher 6339da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER); 6349da9560cSBryan Venteicher 6359da9560cSBryan Venteicher if (device_attach(child) != 0) { 6369da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_FAILED); 6379da9560cSBryan Venteicher /* Reset status for future attempt. */ 6389da9560cSBryan Venteicher vtpci_legacy_child_detached(dev, child); 6399da9560cSBryan Venteicher } else { 6409da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER_OK); 6419da9560cSBryan Venteicher VIRTIO_ATTACH_COMPLETED(child); 6429da9560cSBryan Venteicher } 6439da9560cSBryan Venteicher } 6449da9560cSBryan Venteicher 6459da9560cSBryan Venteicher static int 6469da9560cSBryan Venteicher vtpci_legacy_register_msix(struct vtpci_legacy_softc *sc, int offset, 6479da9560cSBryan Venteicher struct vtpci_interrupt *intr) 6489da9560cSBryan Venteicher { 6499da9560cSBryan Venteicher uint16_t vector; 6509da9560cSBryan Venteicher 6519da9560cSBryan Venteicher if (intr != NULL) { 6529da9560cSBryan Venteicher /* Map from guest rid to host vector. */ 6539da9560cSBryan Venteicher vector = intr->vti_rid - 1; 6549da9560cSBryan Venteicher } else 6559da9560cSBryan Venteicher vector = VIRTIO_MSI_NO_VECTOR; 6569da9560cSBryan Venteicher 6579da9560cSBryan Venteicher vtpci_legacy_write_header_2(sc, offset, vector); 6589da9560cSBryan Venteicher return (vtpci_legacy_read_header_2(sc, offset) == vector ? 0 : ENODEV); 6599da9560cSBryan Venteicher } 6609da9560cSBryan Venteicher 6619da9560cSBryan Venteicher static int 6629da9560cSBryan Venteicher vtpci_legacy_register_cfg_msix(device_t dev, struct vtpci_interrupt *intr) 6639da9560cSBryan Venteicher { 6649da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 6659da9560cSBryan Venteicher int error; 6669da9560cSBryan Venteicher 6679da9560cSBryan Venteicher sc = device_get_softc(dev); 6689da9560cSBryan Venteicher 6699da9560cSBryan Venteicher error = vtpci_legacy_register_msix(sc, VIRTIO_MSI_CONFIG_VECTOR, intr); 6709da9560cSBryan Venteicher if (error) { 6719da9560cSBryan Venteicher device_printf(dev, 6729da9560cSBryan Venteicher "unable to register config MSIX interrupt\n"); 6739da9560cSBryan Venteicher return (error); 6749da9560cSBryan Venteicher } 6759da9560cSBryan Venteicher 6769da9560cSBryan Venteicher return (0); 6779da9560cSBryan Venteicher } 6789da9560cSBryan Venteicher 6799da9560cSBryan Venteicher static int 6809da9560cSBryan Venteicher vtpci_legacy_register_vq_msix(device_t dev, int idx, 6819da9560cSBryan Venteicher struct vtpci_interrupt *intr) 6829da9560cSBryan Venteicher { 6839da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 6849da9560cSBryan Venteicher int error; 6859da9560cSBryan Venteicher 6869da9560cSBryan Venteicher sc = device_get_softc(dev); 6879da9560cSBryan Venteicher 6889da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(sc, idx); 6899da9560cSBryan Venteicher error = vtpci_legacy_register_msix(sc, VIRTIO_MSI_QUEUE_VECTOR, intr); 6909da9560cSBryan Venteicher if (error) { 6919da9560cSBryan Venteicher device_printf(dev, 6929da9560cSBryan Venteicher "unable to register virtqueue MSIX interrupt\n"); 6939da9560cSBryan Venteicher return (error); 6949da9560cSBryan Venteicher } 6959da9560cSBryan Venteicher 6969da9560cSBryan Venteicher return (0); 6979da9560cSBryan Venteicher } 6989da9560cSBryan Venteicher 6999da9560cSBryan Venteicher static void 7009da9560cSBryan Venteicher vtpci_legacy_reset(struct vtpci_legacy_softc *sc) 7019da9560cSBryan Venteicher { 7029da9560cSBryan Venteicher /* 7039da9560cSBryan Venteicher * Setting the status to RESET sets the host device to the 7049da9560cSBryan Venteicher * original, uninitialized state. 7059da9560cSBryan Venteicher */ 7069da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_RESET); 7079da9560cSBryan Venteicher (void) vtpci_legacy_get_status(sc); 7089da9560cSBryan Venteicher } 7099da9560cSBryan Venteicher 7109da9560cSBryan Venteicher static void 7119da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *sc, int idx) 7129da9560cSBryan Venteicher { 7139da9560cSBryan Venteicher vtpci_legacy_write_header_2(sc, VIRTIO_PCI_QUEUE_SEL, idx); 7149da9560cSBryan Venteicher } 7159da9560cSBryan Venteicher 7169da9560cSBryan Venteicher static uint8_t 7179da9560cSBryan Venteicher vtpci_legacy_read_isr(device_t dev) 7189da9560cSBryan Venteicher { 7199da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 7209da9560cSBryan Venteicher 7219da9560cSBryan Venteicher sc = device_get_softc(dev); 7229da9560cSBryan Venteicher 7239da9560cSBryan Venteicher return (vtpci_legacy_read_config_1(sc, VIRTIO_PCI_ISR)); 7249da9560cSBryan Venteicher } 7259da9560cSBryan Venteicher 7269da9560cSBryan Venteicher static uint16_t 7279da9560cSBryan Venteicher vtpci_legacy_get_vq_size(device_t dev, int idx) 7289da9560cSBryan Venteicher { 7299da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 7309da9560cSBryan Venteicher 7319da9560cSBryan Venteicher sc = device_get_softc(dev); 7329da9560cSBryan Venteicher 7339da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(sc, idx); 7349da9560cSBryan Venteicher return (vtpci_legacy_read_header_2(sc, VIRTIO_PCI_QUEUE_NUM)); 7359da9560cSBryan Venteicher } 7369da9560cSBryan Venteicher 7379da9560cSBryan Venteicher static bus_size_t 7389da9560cSBryan Venteicher vtpci_legacy_get_vq_notify_off(device_t dev, int idx) 7399da9560cSBryan Venteicher { 7409da9560cSBryan Venteicher return (VIRTIO_PCI_QUEUE_NOTIFY); 7419da9560cSBryan Venteicher } 7429da9560cSBryan Venteicher 7439da9560cSBryan Venteicher static void 7449da9560cSBryan Venteicher vtpci_legacy_set_vq(device_t dev, struct virtqueue *vq) 7459da9560cSBryan Venteicher { 7469da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 7479da9560cSBryan Venteicher 7489da9560cSBryan Venteicher sc = device_get_softc(dev); 7499da9560cSBryan Venteicher 7509da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(sc, virtqueue_index(vq)); 7519da9560cSBryan Venteicher vtpci_legacy_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN, 7529da9560cSBryan Venteicher virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); 7539da9560cSBryan Venteicher } 7549da9560cSBryan Venteicher 7559da9560cSBryan Venteicher static void 7569da9560cSBryan Venteicher vtpci_legacy_disable_vq(device_t dev, int idx) 7579da9560cSBryan Venteicher { 7589da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 7599da9560cSBryan Venteicher 7609da9560cSBryan Venteicher sc = device_get_softc(dev); 7619da9560cSBryan Venteicher 7629da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(sc, idx); 7639da9560cSBryan Venteicher vtpci_legacy_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN, 0); 7649da9560cSBryan Venteicher } 765