19da9560cSBryan Venteicher /*- 29da9560cSBryan Venteicher * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 329da9560cSBryan Venteicher __FBSDID("$FreeBSD$"); 339da9560cSBryan Venteicher 349da9560cSBryan Venteicher #include <sys/param.h> 359da9560cSBryan Venteicher #include <sys/systm.h> 369da9560cSBryan Venteicher #include <sys/bus.h> 379da9560cSBryan Venteicher #include <sys/lock.h> 389da9560cSBryan Venteicher #include <sys/kernel.h> 399da9560cSBryan Venteicher #include <sys/module.h> 409da9560cSBryan Venteicher #include <sys/endian.h> 419da9560cSBryan Venteicher 429da9560cSBryan Venteicher #include <machine/bus.h> 439da9560cSBryan Venteicher #include <machine/resource.h> 449da9560cSBryan Venteicher #include <sys/bus.h> 459da9560cSBryan Venteicher #include <sys/rman.h> 469da9560cSBryan Venteicher 479da9560cSBryan Venteicher #include <dev/pci/pcivar.h> 489da9560cSBryan Venteicher #include <dev/pci/pcireg.h> 499da9560cSBryan Venteicher 509da9560cSBryan Venteicher #include <dev/virtio/virtio.h> 519da9560cSBryan Venteicher #include <dev/virtio/virtqueue.h> 529da9560cSBryan Venteicher #include <dev/virtio/pci/virtio_pci.h> 539da9560cSBryan Venteicher #include <dev/virtio/pci/virtio_pci_legacy_var.h> 549da9560cSBryan Venteicher 559da9560cSBryan Venteicher #include "virtio_bus_if.h" 569da9560cSBryan Venteicher #include "virtio_pci_if.h" 579da9560cSBryan Venteicher #include "virtio_if.h" 589da9560cSBryan Venteicher 599da9560cSBryan Venteicher struct vtpci_legacy_softc { 609da9560cSBryan Venteicher device_t vtpci_dev; 619da9560cSBryan Venteicher struct vtpci_common vtpci_common; 62cf5d1112SKa Ho Ng int vtpci_res_type; 639da9560cSBryan Venteicher struct resource *vtpci_res; 64faf9a4e9SKa Ho Ng struct resource *vtpci_msix_table_res; 65faf9a4e9SKa Ho Ng struct resource *vtpci_msix_pba_res; 669da9560cSBryan Venteicher }; 679da9560cSBryan Venteicher 689da9560cSBryan Venteicher static int vtpci_legacy_probe(device_t); 699da9560cSBryan Venteicher static int vtpci_legacy_attach(device_t); 709da9560cSBryan Venteicher static int vtpci_legacy_detach(device_t); 719da9560cSBryan Venteicher static int vtpci_legacy_suspend(device_t); 729da9560cSBryan Venteicher static int vtpci_legacy_resume(device_t); 739da9560cSBryan Venteicher static int vtpci_legacy_shutdown(device_t); 749da9560cSBryan Venteicher 759da9560cSBryan Venteicher static void vtpci_legacy_driver_added(device_t, driver_t *); 769da9560cSBryan Venteicher static void vtpci_legacy_child_detached(device_t, device_t); 779da9560cSBryan Venteicher static int vtpci_legacy_read_ivar(device_t, device_t, int, uintptr_t *); 789da9560cSBryan Venteicher static int vtpci_legacy_write_ivar(device_t, device_t, int, uintptr_t); 799da9560cSBryan Venteicher 809da9560cSBryan Venteicher static uint8_t vtpci_legacy_read_isr(device_t); 819da9560cSBryan Venteicher static uint16_t vtpci_legacy_get_vq_size(device_t, int); 829da9560cSBryan Venteicher static bus_size_t vtpci_legacy_get_vq_notify_off(device_t, int); 839da9560cSBryan Venteicher static void vtpci_legacy_set_vq(device_t, struct virtqueue *); 849da9560cSBryan Venteicher static void vtpci_legacy_disable_vq(device_t, int); 859da9560cSBryan Venteicher static int vtpci_legacy_register_cfg_msix(device_t, 869da9560cSBryan Venteicher struct vtpci_interrupt *); 879da9560cSBryan Venteicher static int vtpci_legacy_register_vq_msix(device_t, int idx, 889da9560cSBryan Venteicher struct vtpci_interrupt *); 899da9560cSBryan Venteicher 909da9560cSBryan Venteicher static uint64_t vtpci_legacy_negotiate_features(device_t, uint64_t); 919da9560cSBryan Venteicher static int vtpci_legacy_with_feature(device_t, uint64_t); 929da9560cSBryan Venteicher static int vtpci_legacy_alloc_virtqueues(device_t, int, int, 939da9560cSBryan Venteicher struct vq_alloc_info *); 949da9560cSBryan Venteicher static int vtpci_legacy_setup_interrupts(device_t, enum intr_type); 959da9560cSBryan Venteicher static void vtpci_legacy_stop(device_t); 969da9560cSBryan Venteicher static int vtpci_legacy_reinit(device_t, uint64_t); 979da9560cSBryan Venteicher static void vtpci_legacy_reinit_complete(device_t); 989da9560cSBryan Venteicher static void vtpci_legacy_notify_vq(device_t, uint16_t, bus_size_t); 999da9560cSBryan Venteicher static void vtpci_legacy_read_dev_config(device_t, bus_size_t, void *, int); 1009da9560cSBryan Venteicher static void vtpci_legacy_write_dev_config(device_t, bus_size_t, void *, int); 1019da9560cSBryan Venteicher 102faf9a4e9SKa Ho Ng static bool vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc); 103faf9a4e9SKa Ho Ng static void vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc); 1049da9560cSBryan Venteicher static int vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *); 1059da9560cSBryan Venteicher static void vtpci_legacy_free_resources(struct vtpci_legacy_softc *); 1069da9560cSBryan Venteicher 1079da9560cSBryan Venteicher static void vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *); 1089da9560cSBryan Venteicher 1099da9560cSBryan Venteicher static uint8_t vtpci_legacy_get_status(struct vtpci_legacy_softc *); 1109da9560cSBryan Venteicher static void vtpci_legacy_set_status(struct vtpci_legacy_softc *, uint8_t); 1119da9560cSBryan Venteicher static void vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *, int); 1129da9560cSBryan Venteicher static void vtpci_legacy_reset(struct vtpci_legacy_softc *); 1139da9560cSBryan Venteicher 1149da9560cSBryan Venteicher #define VIRTIO_PCI_LEGACY_CONFIG(_sc) \ 1159da9560cSBryan Venteicher VIRTIO_PCI_CONFIG_OFF(vtpci_is_msix_enabled(&(_sc)->vtpci_common)) 1169da9560cSBryan Venteicher 1179da9560cSBryan Venteicher #define vtpci_legacy_read_config_1(sc, o) \ 1189da9560cSBryan Venteicher bus_read_1((sc)->vtpci_res, (o)) 1199da9560cSBryan Venteicher #define vtpci_legacy_write_config_1(sc, o, v) \ 1209da9560cSBryan Venteicher bus_write_1((sc)->vtpci_res, (o), (v)) 1219da9560cSBryan Venteicher /* 1229da9560cSBryan Venteicher * VirtIO specifies that PCI Configuration area is guest endian. However, 1239da9560cSBryan Venteicher * since PCI devices are inherently little-endian, on big-endian systems 1249da9560cSBryan Venteicher * the bus layer transparently converts it to BE. For virtio-legacy, this 1259da9560cSBryan Venteicher * conversion is undesired, so an extra byte swap is required to fix it. 1269da9560cSBryan Venteicher */ 1279da9560cSBryan Venteicher #define vtpci_legacy_read_config_2(sc, o) \ 1289da9560cSBryan Venteicher le16toh(bus_read_2((sc)->vtpci_res, (o))) 1299da9560cSBryan Venteicher #define vtpci_legacy_read_config_4(sc, o) \ 1309da9560cSBryan Venteicher le32toh(bus_read_4((sc)->vtpci_res, (o))) 1319da9560cSBryan Venteicher #define vtpci_legacy_write_config_2(sc, o, v) \ 1329da9560cSBryan Venteicher bus_write_2((sc)->vtpci_res, (o), (htole16(v))) 1339da9560cSBryan Venteicher #define vtpci_legacy_write_config_4(sc, o, v) \ 1349da9560cSBryan Venteicher bus_write_4((sc)->vtpci_res, (o), (htole32(v))) 1359da9560cSBryan Venteicher /* PCI Header LE. On BE systems the bus layer takes care of byte swapping. */ 1369da9560cSBryan Venteicher #define vtpci_legacy_read_header_2(sc, o) \ 1379da9560cSBryan Venteicher bus_read_2((sc)->vtpci_res, (o)) 1389da9560cSBryan Venteicher #define vtpci_legacy_read_header_4(sc, o) \ 1399da9560cSBryan Venteicher bus_read_4((sc)->vtpci_res, (o)) 1409da9560cSBryan Venteicher #define vtpci_legacy_write_header_2(sc, o, v) \ 1419da9560cSBryan Venteicher bus_write_2((sc)->vtpci_res, (o), (v)) 1429da9560cSBryan Venteicher #define vtpci_legacy_write_header_4(sc, o, v) \ 1439da9560cSBryan Venteicher bus_write_4((sc)->vtpci_res, (o), (v)) 1449da9560cSBryan Venteicher 1459da9560cSBryan Venteicher static device_method_t vtpci_legacy_methods[] = { 1469da9560cSBryan Venteicher /* Device interface. */ 1479da9560cSBryan Venteicher DEVMETHOD(device_probe, vtpci_legacy_probe), 1489da9560cSBryan Venteicher DEVMETHOD(device_attach, vtpci_legacy_attach), 1499da9560cSBryan Venteicher DEVMETHOD(device_detach, vtpci_legacy_detach), 1509da9560cSBryan Venteicher DEVMETHOD(device_suspend, vtpci_legacy_suspend), 1519da9560cSBryan Venteicher DEVMETHOD(device_resume, vtpci_legacy_resume), 1529da9560cSBryan Venteicher DEVMETHOD(device_shutdown, vtpci_legacy_shutdown), 1539da9560cSBryan Venteicher 1549da9560cSBryan Venteicher /* Bus interface. */ 1559da9560cSBryan Venteicher DEVMETHOD(bus_driver_added, vtpci_legacy_driver_added), 1569da9560cSBryan Venteicher DEVMETHOD(bus_child_detached, vtpci_legacy_child_detached), 157*ddfc9c4cSWarner Losh DEVMETHOD(bus_child_pnpinfo, virtio_child_pnpinfo), 1589da9560cSBryan Venteicher DEVMETHOD(bus_read_ivar, vtpci_legacy_read_ivar), 1599da9560cSBryan Venteicher DEVMETHOD(bus_write_ivar, vtpci_legacy_write_ivar), 1609da9560cSBryan Venteicher 1619da9560cSBryan Venteicher /* VirtIO PCI interface. */ 1629da9560cSBryan Venteicher DEVMETHOD(virtio_pci_read_isr, vtpci_legacy_read_isr), 1639da9560cSBryan Venteicher DEVMETHOD(virtio_pci_get_vq_size, vtpci_legacy_get_vq_size), 1649da9560cSBryan Venteicher DEVMETHOD(virtio_pci_get_vq_notify_off, vtpci_legacy_get_vq_notify_off), 1659da9560cSBryan Venteicher DEVMETHOD(virtio_pci_set_vq, vtpci_legacy_set_vq), 1669da9560cSBryan Venteicher DEVMETHOD(virtio_pci_disable_vq, vtpci_legacy_disable_vq), 1679da9560cSBryan Venteicher DEVMETHOD(virtio_pci_register_cfg_msix, vtpci_legacy_register_cfg_msix), 1689da9560cSBryan Venteicher DEVMETHOD(virtio_pci_register_vq_msix, vtpci_legacy_register_vq_msix), 1699da9560cSBryan Venteicher 1709da9560cSBryan Venteicher /* VirtIO bus interface. */ 1719da9560cSBryan Venteicher DEVMETHOD(virtio_bus_negotiate_features, vtpci_legacy_negotiate_features), 1729da9560cSBryan Venteicher DEVMETHOD(virtio_bus_with_feature, vtpci_legacy_with_feature), 1739da9560cSBryan Venteicher DEVMETHOD(virtio_bus_alloc_virtqueues, vtpci_legacy_alloc_virtqueues), 1749da9560cSBryan Venteicher DEVMETHOD(virtio_bus_setup_intr, vtpci_legacy_setup_interrupts), 1759da9560cSBryan Venteicher DEVMETHOD(virtio_bus_stop, vtpci_legacy_stop), 1769da9560cSBryan Venteicher DEVMETHOD(virtio_bus_reinit, vtpci_legacy_reinit), 1779da9560cSBryan Venteicher DEVMETHOD(virtio_bus_reinit_complete, vtpci_legacy_reinit_complete), 1789da9560cSBryan Venteicher DEVMETHOD(virtio_bus_notify_vq, vtpci_legacy_notify_vq), 1799da9560cSBryan Venteicher DEVMETHOD(virtio_bus_read_device_config, vtpci_legacy_read_dev_config), 1809da9560cSBryan Venteicher DEVMETHOD(virtio_bus_write_device_config, vtpci_legacy_write_dev_config), 1819da9560cSBryan Venteicher 1829da9560cSBryan Venteicher DEVMETHOD_END 1839da9560cSBryan Venteicher }; 1849da9560cSBryan Venteicher 1859da9560cSBryan Venteicher static driver_t vtpci_legacy_driver = { 1869da9560cSBryan Venteicher .name = "virtio_pci", 1879da9560cSBryan Venteicher .methods = vtpci_legacy_methods, 1889da9560cSBryan Venteicher .size = sizeof(struct vtpci_legacy_softc) 1899da9560cSBryan Venteicher }; 1909da9560cSBryan Venteicher 1919da9560cSBryan Venteicher devclass_t vtpci_legacy_devclass; 1929da9560cSBryan Venteicher 1939da9560cSBryan Venteicher DRIVER_MODULE(virtio_pci_legacy, pci, vtpci_legacy_driver, 1949da9560cSBryan Venteicher vtpci_legacy_devclass, 0, 0); 1959da9560cSBryan Venteicher 1969da9560cSBryan Venteicher static int 1979da9560cSBryan Venteicher vtpci_legacy_probe(device_t dev) 1989da9560cSBryan Venteicher { 1999da9560cSBryan Venteicher char desc[64]; 2009da9560cSBryan Venteicher const char *name; 2019da9560cSBryan Venteicher 2029da9560cSBryan Venteicher if (pci_get_vendor(dev) != VIRTIO_PCI_VENDORID) 2039da9560cSBryan Venteicher return (ENXIO); 2049da9560cSBryan Venteicher 2059da9560cSBryan Venteicher if (pci_get_device(dev) < VIRTIO_PCI_DEVICEID_MIN || 2069da9560cSBryan Venteicher pci_get_device(dev) > VIRTIO_PCI_DEVICEID_LEGACY_MAX) 2079da9560cSBryan Venteicher return (ENXIO); 2089da9560cSBryan Venteicher 2099da9560cSBryan Venteicher if (pci_get_revid(dev) != VIRTIO_PCI_ABI_VERSION) 2109da9560cSBryan Venteicher return (ENXIO); 2119da9560cSBryan Venteicher 2129da9560cSBryan Venteicher name = virtio_device_name(pci_get_subdevice(dev)); 2139da9560cSBryan Venteicher if (name == NULL) 2149da9560cSBryan Venteicher name = "Unknown"; 2159da9560cSBryan Venteicher 2169da9560cSBryan Venteicher snprintf(desc, sizeof(desc), "VirtIO PCI (legacy) %s adapter", name); 2179da9560cSBryan Venteicher device_set_desc_copy(dev, desc); 2189da9560cSBryan Venteicher 2199da9560cSBryan Venteicher /* Prefer transitional modern VirtIO PCI. */ 2209da9560cSBryan Venteicher return (BUS_PROBE_LOW_PRIORITY); 2219da9560cSBryan Venteicher } 2229da9560cSBryan Venteicher 2239da9560cSBryan Venteicher static int 2249da9560cSBryan Venteicher vtpci_legacy_attach(device_t dev) 2259da9560cSBryan Venteicher { 2269da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 2279da9560cSBryan Venteicher int error; 2289da9560cSBryan Venteicher 2299da9560cSBryan Venteicher sc = device_get_softc(dev); 2309da9560cSBryan Venteicher sc->vtpci_dev = dev; 2319da9560cSBryan Venteicher vtpci_init(&sc->vtpci_common, dev, false); 2329da9560cSBryan Venteicher 2339da9560cSBryan Venteicher error = vtpci_legacy_alloc_resources(sc); 2349da9560cSBryan Venteicher if (error) { 235cf5d1112SKa Ho Ng device_printf(dev, "cannot map I/O space nor memory space\n"); 2369da9560cSBryan Venteicher return (error); 2379da9560cSBryan Venteicher } 2389da9560cSBryan Venteicher 239faf9a4e9SKa Ho Ng if (vtpci_is_msix_available(&sc->vtpci_common) && 240faf9a4e9SKa Ho Ng !vtpci_legacy_setup_msix(sc)) { 241faf9a4e9SKa Ho Ng device_printf(dev, "cannot setup MSI-x resources\n"); 242faf9a4e9SKa Ho Ng error = ENXIO; 243faf9a4e9SKa Ho Ng goto fail; 244faf9a4e9SKa Ho Ng } 245faf9a4e9SKa Ho Ng 2469da9560cSBryan Venteicher vtpci_legacy_reset(sc); 2479da9560cSBryan Venteicher 2489da9560cSBryan Venteicher /* Tell the host we've noticed this device. */ 2499da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK); 2509da9560cSBryan Venteicher 2519da9560cSBryan Venteicher error = vtpci_add_child(&sc->vtpci_common); 2529da9560cSBryan Venteicher if (error) 2539da9560cSBryan Venteicher goto fail; 2549da9560cSBryan Venteicher 2559da9560cSBryan Venteicher vtpci_legacy_probe_and_attach_child(sc); 2569da9560cSBryan Venteicher 2579da9560cSBryan Venteicher return (0); 2589da9560cSBryan Venteicher 2599da9560cSBryan Venteicher fail: 2609da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_FAILED); 2619da9560cSBryan Venteicher vtpci_legacy_detach(dev); 2629da9560cSBryan Venteicher 2639da9560cSBryan Venteicher return (error); 2649da9560cSBryan Venteicher } 2659da9560cSBryan Venteicher 2669da9560cSBryan Venteicher static int 2679da9560cSBryan Venteicher vtpci_legacy_detach(device_t dev) 2689da9560cSBryan Venteicher { 2699da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 2709da9560cSBryan Venteicher int error; 2719da9560cSBryan Venteicher 2729da9560cSBryan Venteicher sc = device_get_softc(dev); 2739da9560cSBryan Venteicher 2749da9560cSBryan Venteicher error = vtpci_delete_child(&sc->vtpci_common); 2759da9560cSBryan Venteicher if (error) 2769da9560cSBryan Venteicher return (error); 2779da9560cSBryan Venteicher 2789da9560cSBryan Venteicher vtpci_legacy_reset(sc); 279faf9a4e9SKa Ho Ng vtpci_legacy_teardown_msix(sc); 2809da9560cSBryan Venteicher vtpci_legacy_free_resources(sc); 2819da9560cSBryan Venteicher 2829da9560cSBryan Venteicher return (0); 2839da9560cSBryan Venteicher } 2849da9560cSBryan Venteicher 2859da9560cSBryan Venteicher static int 2869da9560cSBryan Venteicher vtpci_legacy_suspend(device_t dev) 2879da9560cSBryan Venteicher { 2889da9560cSBryan Venteicher return (bus_generic_suspend(dev)); 2899da9560cSBryan Venteicher } 2909da9560cSBryan Venteicher 2919da9560cSBryan Venteicher static int 2929da9560cSBryan Venteicher vtpci_legacy_resume(device_t dev) 2939da9560cSBryan Venteicher { 2949da9560cSBryan Venteicher return (bus_generic_resume(dev)); 2959da9560cSBryan Venteicher } 2969da9560cSBryan Venteicher 2979da9560cSBryan Venteicher static int 2989da9560cSBryan Venteicher vtpci_legacy_shutdown(device_t dev) 2999da9560cSBryan Venteicher { 3009da9560cSBryan Venteicher (void) bus_generic_shutdown(dev); 3019da9560cSBryan Venteicher /* Forcibly stop the host device. */ 3029da9560cSBryan Venteicher vtpci_legacy_stop(dev); 3039da9560cSBryan Venteicher 3049da9560cSBryan Venteicher return (0); 3059da9560cSBryan Venteicher } 3069da9560cSBryan Venteicher 3079da9560cSBryan Venteicher static void 3089da9560cSBryan Venteicher vtpci_legacy_driver_added(device_t dev, driver_t *driver) 3099da9560cSBryan Venteicher { 3109da9560cSBryan Venteicher vtpci_legacy_probe_and_attach_child(device_get_softc(dev)); 3119da9560cSBryan Venteicher } 3129da9560cSBryan Venteicher 3139da9560cSBryan Venteicher static void 3149da9560cSBryan Venteicher vtpci_legacy_child_detached(device_t dev, device_t child) 3159da9560cSBryan Venteicher { 3169da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3179da9560cSBryan Venteicher 3189da9560cSBryan Venteicher sc = device_get_softc(dev); 3199da9560cSBryan Venteicher 3209da9560cSBryan Venteicher vtpci_legacy_reset(sc); 3219da9560cSBryan Venteicher vtpci_child_detached(&sc->vtpci_common); 3229da9560cSBryan Venteicher 3239da9560cSBryan Venteicher /* After the reset, retell the host we've noticed this device. */ 3249da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK); 3259da9560cSBryan Venteicher } 3269da9560cSBryan Venteicher 3279da9560cSBryan Venteicher static int 3289da9560cSBryan Venteicher vtpci_legacy_read_ivar(device_t dev, device_t child, int index, 3299da9560cSBryan Venteicher uintptr_t *result) 3309da9560cSBryan Venteicher { 3319da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3329da9560cSBryan Venteicher struct vtpci_common *cn; 3339da9560cSBryan Venteicher 3349da9560cSBryan Venteicher sc = device_get_softc(dev); 3359da9560cSBryan Venteicher cn = &sc->vtpci_common; 3369da9560cSBryan Venteicher 3379da9560cSBryan Venteicher if (vtpci_child_device(cn) != child) 3389da9560cSBryan Venteicher return (ENOENT); 3399da9560cSBryan Venteicher 3409da9560cSBryan Venteicher switch (index) { 3419da9560cSBryan Venteicher case VIRTIO_IVAR_DEVTYPE: 3429da9560cSBryan Venteicher *result = pci_get_subdevice(dev); 3439da9560cSBryan Venteicher break; 3449da9560cSBryan Venteicher default: 3459da9560cSBryan Venteicher return (vtpci_read_ivar(cn, index, result)); 3469da9560cSBryan Venteicher } 3479da9560cSBryan Venteicher 3489da9560cSBryan Venteicher return (0); 3499da9560cSBryan Venteicher } 3509da9560cSBryan Venteicher 3519da9560cSBryan Venteicher static int 3529da9560cSBryan Venteicher vtpci_legacy_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 3539da9560cSBryan Venteicher { 3549da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3559da9560cSBryan Venteicher struct vtpci_common *cn; 3569da9560cSBryan Venteicher 3579da9560cSBryan Venteicher sc = device_get_softc(dev); 3589da9560cSBryan Venteicher cn = &sc->vtpci_common; 3599da9560cSBryan Venteicher 3609da9560cSBryan Venteicher if (vtpci_child_device(cn) != child) 3619da9560cSBryan Venteicher return (ENOENT); 3629da9560cSBryan Venteicher 3639da9560cSBryan Venteicher switch (index) { 3649da9560cSBryan Venteicher default: 3659da9560cSBryan Venteicher return (vtpci_write_ivar(cn, index, value)); 3669da9560cSBryan Venteicher } 3679da9560cSBryan Venteicher 3689da9560cSBryan Venteicher return (0); 3699da9560cSBryan Venteicher } 3709da9560cSBryan Venteicher 3719da9560cSBryan Venteicher static uint64_t 3729da9560cSBryan Venteicher vtpci_legacy_negotiate_features(device_t dev, uint64_t child_features) 3739da9560cSBryan Venteicher { 3749da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3759da9560cSBryan Venteicher uint64_t host_features, features; 3769da9560cSBryan Venteicher 3779da9560cSBryan Venteicher sc = device_get_softc(dev); 3789da9560cSBryan Venteicher host_features = vtpci_legacy_read_header_4(sc, VIRTIO_PCI_HOST_FEATURES); 3799da9560cSBryan Venteicher 3809da9560cSBryan Venteicher features = vtpci_negotiate_features(&sc->vtpci_common, 3819da9560cSBryan Venteicher child_features, host_features); 3829da9560cSBryan Venteicher vtpci_legacy_write_header_4(sc, VIRTIO_PCI_GUEST_FEATURES, features); 3839da9560cSBryan Venteicher 3849da9560cSBryan Venteicher return (features); 3859da9560cSBryan Venteicher } 3869da9560cSBryan Venteicher 3879da9560cSBryan Venteicher static int 3889da9560cSBryan Venteicher vtpci_legacy_with_feature(device_t dev, uint64_t feature) 3899da9560cSBryan Venteicher { 3909da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 3919da9560cSBryan Venteicher 3929da9560cSBryan Venteicher sc = device_get_softc(dev); 3939da9560cSBryan Venteicher 3949da9560cSBryan Venteicher return (vtpci_with_feature(&sc->vtpci_common, feature)); 3959da9560cSBryan Venteicher } 3969da9560cSBryan Venteicher 3979da9560cSBryan Venteicher static int 3989da9560cSBryan Venteicher vtpci_legacy_alloc_virtqueues(device_t dev, int flags, int nvqs, 3999da9560cSBryan Venteicher struct vq_alloc_info *vq_info) 4009da9560cSBryan Venteicher { 4019da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4029da9560cSBryan Venteicher struct vtpci_common *cn; 4039da9560cSBryan Venteicher 4049da9560cSBryan Venteicher sc = device_get_softc(dev); 4059da9560cSBryan Venteicher cn = &sc->vtpci_common; 4069da9560cSBryan Venteicher 4079da9560cSBryan Venteicher return (vtpci_alloc_virtqueues(cn, flags, nvqs, vq_info)); 4089da9560cSBryan Venteicher } 4099da9560cSBryan Venteicher 4109da9560cSBryan Venteicher static int 4119da9560cSBryan Venteicher vtpci_legacy_setup_interrupts(device_t dev, enum intr_type type) 4129da9560cSBryan Venteicher { 4139da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4149da9560cSBryan Venteicher 4159da9560cSBryan Venteicher sc = device_get_softc(dev); 4169da9560cSBryan Venteicher 4179da9560cSBryan Venteicher return (vtpci_setup_interrupts(&sc->vtpci_common, type)); 4189da9560cSBryan Venteicher } 4199da9560cSBryan Venteicher 4209da9560cSBryan Venteicher static void 4219da9560cSBryan Venteicher vtpci_legacy_stop(device_t dev) 4229da9560cSBryan Venteicher { 4239da9560cSBryan Venteicher vtpci_legacy_reset(device_get_softc(dev)); 4249da9560cSBryan Venteicher } 4259da9560cSBryan Venteicher 4269da9560cSBryan Venteicher static int 4279da9560cSBryan Venteicher vtpci_legacy_reinit(device_t dev, uint64_t features) 4289da9560cSBryan Venteicher { 4299da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4309da9560cSBryan Venteicher struct vtpci_common *cn; 4319da9560cSBryan Venteicher int error; 4329da9560cSBryan Venteicher 4339da9560cSBryan Venteicher sc = device_get_softc(dev); 4349da9560cSBryan Venteicher cn = &sc->vtpci_common; 4359da9560cSBryan Venteicher 4369da9560cSBryan Venteicher /* 4379da9560cSBryan Venteicher * Redrive the device initialization. This is a bit of an abuse of 4389da9560cSBryan Venteicher * the specification, but VirtualBox, QEMU/KVM, and BHyVe seem to 4399da9560cSBryan Venteicher * play nice. 4409da9560cSBryan Venteicher * 4419da9560cSBryan Venteicher * We do not allow the host device to change from what was originally 4429da9560cSBryan Venteicher * negotiated beyond what the guest driver changed. MSIX state should 4439da9560cSBryan Venteicher * not change, number of virtqueues and their size remain the same, etc. 4449da9560cSBryan Venteicher * This will need to be rethought when we want to support migration. 4459da9560cSBryan Venteicher */ 4469da9560cSBryan Venteicher 4479da9560cSBryan Venteicher if (vtpci_legacy_get_status(sc) != VIRTIO_CONFIG_STATUS_RESET) 4489da9560cSBryan Venteicher vtpci_legacy_stop(dev); 4499da9560cSBryan Venteicher 4509da9560cSBryan Venteicher /* 4519da9560cSBryan Venteicher * Quickly drive the status through ACK and DRIVER. The device does 4529da9560cSBryan Venteicher * not become usable again until DRIVER_OK in reinit complete. 4539da9560cSBryan Venteicher */ 4549da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK); 4559da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER); 4569da9560cSBryan Venteicher 4579da9560cSBryan Venteicher vtpci_legacy_negotiate_features(dev, features); 4589da9560cSBryan Venteicher 4599da9560cSBryan Venteicher error = vtpci_reinit(cn); 4609da9560cSBryan Venteicher if (error) 4619da9560cSBryan Venteicher return (error); 4629da9560cSBryan Venteicher 4639da9560cSBryan Venteicher return (0); 4649da9560cSBryan Venteicher } 4659da9560cSBryan Venteicher 4669da9560cSBryan Venteicher static void 4679da9560cSBryan Venteicher vtpci_legacy_reinit_complete(device_t dev) 4689da9560cSBryan Venteicher { 4699da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4709da9560cSBryan Venteicher 4719da9560cSBryan Venteicher sc = device_get_softc(dev); 4729da9560cSBryan Venteicher 4739da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER_OK); 4749da9560cSBryan Venteicher } 4759da9560cSBryan Venteicher 4769da9560cSBryan Venteicher static void 4779da9560cSBryan Venteicher vtpci_legacy_notify_vq(device_t dev, uint16_t queue, bus_size_t offset) 4789da9560cSBryan Venteicher { 4799da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 4809da9560cSBryan Venteicher 4819da9560cSBryan Venteicher sc = device_get_softc(dev); 4829da9560cSBryan Venteicher MPASS(offset == VIRTIO_PCI_QUEUE_NOTIFY); 4839da9560cSBryan Venteicher 4849da9560cSBryan Venteicher vtpci_legacy_write_header_2(sc, offset, queue); 4859da9560cSBryan Venteicher } 4869da9560cSBryan Venteicher 4879da9560cSBryan Venteicher static uint8_t 4889da9560cSBryan Venteicher vtpci_legacy_get_status(struct vtpci_legacy_softc *sc) 4899da9560cSBryan Venteicher { 4909da9560cSBryan Venteicher return (vtpci_legacy_read_config_1(sc, VIRTIO_PCI_STATUS)); 4919da9560cSBryan Venteicher } 4929da9560cSBryan Venteicher 4939da9560cSBryan Venteicher static void 4949da9560cSBryan Venteicher vtpci_legacy_set_status(struct vtpci_legacy_softc *sc, uint8_t status) 4959da9560cSBryan Venteicher { 4969da9560cSBryan Venteicher if (status != VIRTIO_CONFIG_STATUS_RESET) 4979da9560cSBryan Venteicher status |= vtpci_legacy_get_status(sc); 4989da9560cSBryan Venteicher 4999da9560cSBryan Venteicher vtpci_legacy_write_config_1(sc, VIRTIO_PCI_STATUS, status); 5009da9560cSBryan Venteicher } 5019da9560cSBryan Venteicher 5029da9560cSBryan Venteicher static void 5039da9560cSBryan Venteicher vtpci_legacy_read_dev_config(device_t dev, bus_size_t offset, 5049da9560cSBryan Venteicher void *dst, int length) 5059da9560cSBryan Venteicher { 5069da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 5079da9560cSBryan Venteicher bus_size_t off; 5089da9560cSBryan Venteicher uint8_t *d; 5099da9560cSBryan Venteicher int size; 5109da9560cSBryan Venteicher 5119da9560cSBryan Venteicher sc = device_get_softc(dev); 5129da9560cSBryan Venteicher off = VIRTIO_PCI_LEGACY_CONFIG(sc) + offset; 5139da9560cSBryan Venteicher 5149da9560cSBryan Venteicher for (d = dst; length > 0; d += size, off += size, length -= size) { 5159da9560cSBryan Venteicher if (length >= 4) { 5169da9560cSBryan Venteicher size = 4; 5179da9560cSBryan Venteicher *(uint32_t *)d = vtpci_legacy_read_config_4(sc, off); 5189da9560cSBryan Venteicher } else if (length >= 2) { 5199da9560cSBryan Venteicher size = 2; 5209da9560cSBryan Venteicher *(uint16_t *)d = vtpci_legacy_read_config_2(sc, off); 5219da9560cSBryan Venteicher } else { 5229da9560cSBryan Venteicher size = 1; 5239da9560cSBryan Venteicher *d = vtpci_legacy_read_config_1(sc, off); 5249da9560cSBryan Venteicher } 5259da9560cSBryan Venteicher } 5269da9560cSBryan Venteicher } 5279da9560cSBryan Venteicher 5289da9560cSBryan Venteicher static void 5299da9560cSBryan Venteicher vtpci_legacy_write_dev_config(device_t dev, bus_size_t offset, 5309da9560cSBryan Venteicher void *src, int length) 5319da9560cSBryan Venteicher { 5329da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 5339da9560cSBryan Venteicher bus_size_t off; 5349da9560cSBryan Venteicher uint8_t *s; 5359da9560cSBryan Venteicher int size; 5369da9560cSBryan Venteicher 5379da9560cSBryan Venteicher sc = device_get_softc(dev); 5389da9560cSBryan Venteicher off = VIRTIO_PCI_LEGACY_CONFIG(sc) + offset; 5399da9560cSBryan Venteicher 5409da9560cSBryan Venteicher for (s = src; length > 0; s += size, off += size, length -= size) { 5419da9560cSBryan Venteicher if (length >= 4) { 5429da9560cSBryan Venteicher size = 4; 5439da9560cSBryan Venteicher vtpci_legacy_write_config_4(sc, off, *(uint32_t *)s); 5449da9560cSBryan Venteicher } else if (length >= 2) { 5459da9560cSBryan Venteicher size = 2; 5469da9560cSBryan Venteicher vtpci_legacy_write_config_2(sc, off, *(uint16_t *)s); 5479da9560cSBryan Venteicher } else { 5489da9560cSBryan Venteicher size = 1; 5499da9560cSBryan Venteicher vtpci_legacy_write_config_1(sc, off, *s); 5509da9560cSBryan Venteicher } 5519da9560cSBryan Venteicher } 5529da9560cSBryan Venteicher } 5539da9560cSBryan Venteicher 554faf9a4e9SKa Ho Ng static bool 555faf9a4e9SKa Ho Ng vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc) 556faf9a4e9SKa Ho Ng { 557faf9a4e9SKa Ho Ng device_t dev; 558faf9a4e9SKa Ho Ng int rid, table_rid; 559faf9a4e9SKa Ho Ng 560faf9a4e9SKa Ho Ng dev = sc->vtpci_dev; 561faf9a4e9SKa Ho Ng 562faf9a4e9SKa Ho Ng rid = table_rid = pci_msix_table_bar(dev); 563faf9a4e9SKa Ho Ng if (rid != PCIR_BAR(0)) { 564faf9a4e9SKa Ho Ng sc->vtpci_msix_table_res = bus_alloc_resource_any( 565faf9a4e9SKa Ho Ng dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 566faf9a4e9SKa Ho Ng if (sc->vtpci_msix_table_res == NULL) 567faf9a4e9SKa Ho Ng return (false); 568faf9a4e9SKa Ho Ng } 569faf9a4e9SKa Ho Ng 570faf9a4e9SKa Ho Ng rid = pci_msix_pba_bar(dev); 571faf9a4e9SKa Ho Ng if (rid != table_rid && rid != PCIR_BAR(0)) { 572faf9a4e9SKa Ho Ng sc->vtpci_msix_pba_res = bus_alloc_resource_any( 573faf9a4e9SKa Ho Ng dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 574faf9a4e9SKa Ho Ng if (sc->vtpci_msix_pba_res == NULL) 575faf9a4e9SKa Ho Ng return (false); 576faf9a4e9SKa Ho Ng } 577faf9a4e9SKa Ho Ng 578faf9a4e9SKa Ho Ng return (true); 579faf9a4e9SKa Ho Ng } 580faf9a4e9SKa Ho Ng 581faf9a4e9SKa Ho Ng static void 582faf9a4e9SKa Ho Ng vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc) 583faf9a4e9SKa Ho Ng { 584faf9a4e9SKa Ho Ng device_t dev; 585faf9a4e9SKa Ho Ng 586faf9a4e9SKa Ho Ng dev = sc->vtpci_dev; 587faf9a4e9SKa Ho Ng 588faf9a4e9SKa Ho Ng if (sc->vtpci_msix_pba_res != NULL) { 589faf9a4e9SKa Ho Ng bus_release_resource(dev, SYS_RES_MEMORY, 590faf9a4e9SKa Ho Ng rman_get_rid(sc->vtpci_msix_pba_res), 591faf9a4e9SKa Ho Ng sc->vtpci_msix_pba_res); 592faf9a4e9SKa Ho Ng sc->vtpci_msix_pba_res = NULL; 593faf9a4e9SKa Ho Ng } 594faf9a4e9SKa Ho Ng if (sc->vtpci_msix_table_res != NULL) { 595faf9a4e9SKa Ho Ng bus_release_resource(dev, SYS_RES_MEMORY, 596faf9a4e9SKa Ho Ng rman_get_rid(sc->vtpci_msix_table_res), 597faf9a4e9SKa Ho Ng sc->vtpci_msix_table_res); 598faf9a4e9SKa Ho Ng sc->vtpci_msix_table_res = NULL; 599faf9a4e9SKa Ho Ng } 600faf9a4e9SKa Ho Ng } 601faf9a4e9SKa Ho Ng 6029da9560cSBryan Venteicher static int 6039da9560cSBryan Venteicher vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *sc) 6049da9560cSBryan Venteicher { 605cf5d1112SKa Ho Ng const int res_types[] = { SYS_RES_IOPORT, SYS_RES_MEMORY }; 6069da9560cSBryan Venteicher device_t dev; 607cf5d1112SKa Ho Ng int rid, i; 6089da9560cSBryan Venteicher 6099da9560cSBryan Venteicher dev = sc->vtpci_dev; 6109da9560cSBryan Venteicher 611cf5d1112SKa Ho Ng /* 612cf5d1112SKa Ho Ng * Most hypervisors export the common configuration structure in IO 613cf5d1112SKa Ho Ng * space, but some use memory space; try both. 614cf5d1112SKa Ho Ng */ 615cf5d1112SKa Ho Ng for (i = 0; nitems(res_types); i++) { 6169da9560cSBryan Venteicher rid = PCIR_BAR(0); 617cf5d1112SKa Ho Ng sc->vtpci_res_type = res_types[i]; 618cf5d1112SKa Ho Ng sc->vtpci_res = bus_alloc_resource_any(dev, res_types[i], &rid, 619cf5d1112SKa Ho Ng RF_ACTIVE); 620cf5d1112SKa Ho Ng if (sc->vtpci_res != NULL) 621cf5d1112SKa Ho Ng break; 622cf5d1112SKa Ho Ng } 623cf5d1112SKa Ho Ng if (sc->vtpci_res == NULL) 6249da9560cSBryan Venteicher return (ENXIO); 6259da9560cSBryan Venteicher 6269da9560cSBryan Venteicher return (0); 6279da9560cSBryan Venteicher } 6289da9560cSBryan Venteicher 6299da9560cSBryan Venteicher static void 6309da9560cSBryan Venteicher vtpci_legacy_free_resources(struct vtpci_legacy_softc *sc) 6319da9560cSBryan Venteicher { 6329da9560cSBryan Venteicher device_t dev; 6339da9560cSBryan Venteicher 6349da9560cSBryan Venteicher dev = sc->vtpci_dev; 6359da9560cSBryan Venteicher 6369da9560cSBryan Venteicher if (sc->vtpci_res != NULL) { 637cf5d1112SKa Ho Ng bus_release_resource(dev, sc->vtpci_res_type, PCIR_BAR(0), 6389da9560cSBryan Venteicher sc->vtpci_res); 6399da9560cSBryan Venteicher sc->vtpci_res = NULL; 6409da9560cSBryan Venteicher } 6419da9560cSBryan Venteicher } 6429da9560cSBryan Venteicher 6439da9560cSBryan Venteicher static void 6449da9560cSBryan Venteicher vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *sc) 6459da9560cSBryan Venteicher { 6469da9560cSBryan Venteicher device_t dev, child; 6479da9560cSBryan Venteicher 6489da9560cSBryan Venteicher dev = sc->vtpci_dev; 6499da9560cSBryan Venteicher child = vtpci_child_device(&sc->vtpci_common); 6509da9560cSBryan Venteicher 6519da9560cSBryan Venteicher if (child == NULL || device_get_state(child) != DS_NOTPRESENT) 6529da9560cSBryan Venteicher return; 6539da9560cSBryan Venteicher 6549da9560cSBryan Venteicher if (device_probe(child) != 0) 6559da9560cSBryan Venteicher return; 6569da9560cSBryan Venteicher 6579da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER); 6589da9560cSBryan Venteicher 6599da9560cSBryan Venteicher if (device_attach(child) != 0) { 6609da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_FAILED); 6619da9560cSBryan Venteicher /* Reset status for future attempt. */ 6629da9560cSBryan Venteicher vtpci_legacy_child_detached(dev, child); 6639da9560cSBryan Venteicher } else { 6649da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER_OK); 6659da9560cSBryan Venteicher VIRTIO_ATTACH_COMPLETED(child); 6669da9560cSBryan Venteicher } 6679da9560cSBryan Venteicher } 6689da9560cSBryan Venteicher 6699da9560cSBryan Venteicher static int 6709da9560cSBryan Venteicher vtpci_legacy_register_msix(struct vtpci_legacy_softc *sc, int offset, 6719da9560cSBryan Venteicher struct vtpci_interrupt *intr) 6729da9560cSBryan Venteicher { 6739da9560cSBryan Venteicher device_t dev; 6749da9560cSBryan Venteicher uint16_t vector; 6759da9560cSBryan Venteicher 6769da9560cSBryan Venteicher dev = sc->vtpci_dev; 6779da9560cSBryan Venteicher 6789da9560cSBryan Venteicher if (intr != NULL) { 6799da9560cSBryan Venteicher /* Map from guest rid to host vector. */ 6809da9560cSBryan Venteicher vector = intr->vti_rid - 1; 6819da9560cSBryan Venteicher } else 6829da9560cSBryan Venteicher vector = VIRTIO_MSI_NO_VECTOR; 6839da9560cSBryan Venteicher 6849da9560cSBryan Venteicher vtpci_legacy_write_header_2(sc, offset, vector); 6859da9560cSBryan Venteicher return (vtpci_legacy_read_header_2(sc, offset) == vector ? 0 : ENODEV); 6869da9560cSBryan Venteicher } 6879da9560cSBryan Venteicher 6889da9560cSBryan Venteicher static int 6899da9560cSBryan Venteicher vtpci_legacy_register_cfg_msix(device_t dev, struct vtpci_interrupt *intr) 6909da9560cSBryan Venteicher { 6919da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 6929da9560cSBryan Venteicher int error; 6939da9560cSBryan Venteicher 6949da9560cSBryan Venteicher sc = device_get_softc(dev); 6959da9560cSBryan Venteicher 6969da9560cSBryan Venteicher error = vtpci_legacy_register_msix(sc, VIRTIO_MSI_CONFIG_VECTOR, intr); 6979da9560cSBryan Venteicher if (error) { 6989da9560cSBryan Venteicher device_printf(dev, 6999da9560cSBryan Venteicher "unable to register config MSIX interrupt\n"); 7009da9560cSBryan Venteicher return (error); 7019da9560cSBryan Venteicher } 7029da9560cSBryan Venteicher 7039da9560cSBryan Venteicher return (0); 7049da9560cSBryan Venteicher } 7059da9560cSBryan Venteicher 7069da9560cSBryan Venteicher static int 7079da9560cSBryan Venteicher vtpci_legacy_register_vq_msix(device_t dev, int idx, 7089da9560cSBryan Venteicher struct vtpci_interrupt *intr) 7099da9560cSBryan Venteicher { 7109da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 7119da9560cSBryan Venteicher int error; 7129da9560cSBryan Venteicher 7139da9560cSBryan Venteicher sc = device_get_softc(dev); 7149da9560cSBryan Venteicher 7159da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(sc, idx); 7169da9560cSBryan Venteicher error = vtpci_legacy_register_msix(sc, VIRTIO_MSI_QUEUE_VECTOR, intr); 7179da9560cSBryan Venteicher if (error) { 7189da9560cSBryan Venteicher device_printf(dev, 7199da9560cSBryan Venteicher "unable to register virtqueue MSIX interrupt\n"); 7209da9560cSBryan Venteicher return (error); 7219da9560cSBryan Venteicher } 7229da9560cSBryan Venteicher 7239da9560cSBryan Venteicher return (0); 7249da9560cSBryan Venteicher } 7259da9560cSBryan Venteicher 7269da9560cSBryan Venteicher static void 7279da9560cSBryan Venteicher vtpci_legacy_reset(struct vtpci_legacy_softc *sc) 7289da9560cSBryan Venteicher { 7299da9560cSBryan Venteicher /* 7309da9560cSBryan Venteicher * Setting the status to RESET sets the host device to the 7319da9560cSBryan Venteicher * original, uninitialized state. 7329da9560cSBryan Venteicher */ 7339da9560cSBryan Venteicher vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_RESET); 7349da9560cSBryan Venteicher (void) vtpci_legacy_get_status(sc); 7359da9560cSBryan Venteicher } 7369da9560cSBryan Venteicher 7379da9560cSBryan Venteicher static void 7389da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *sc, int idx) 7399da9560cSBryan Venteicher { 7409da9560cSBryan Venteicher vtpci_legacy_write_header_2(sc, VIRTIO_PCI_QUEUE_SEL, idx); 7419da9560cSBryan Venteicher } 7429da9560cSBryan Venteicher 7439da9560cSBryan Venteicher static uint8_t 7449da9560cSBryan Venteicher vtpci_legacy_read_isr(device_t dev) 7459da9560cSBryan Venteicher { 7469da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 7479da9560cSBryan Venteicher 7489da9560cSBryan Venteicher sc = device_get_softc(dev); 7499da9560cSBryan Venteicher 7509da9560cSBryan Venteicher return (vtpci_legacy_read_config_1(sc, VIRTIO_PCI_ISR)); 7519da9560cSBryan Venteicher } 7529da9560cSBryan Venteicher 7539da9560cSBryan Venteicher static uint16_t 7549da9560cSBryan Venteicher vtpci_legacy_get_vq_size(device_t dev, int idx) 7559da9560cSBryan Venteicher { 7569da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 7579da9560cSBryan Venteicher 7589da9560cSBryan Venteicher sc = device_get_softc(dev); 7599da9560cSBryan Venteicher 7609da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(sc, idx); 7619da9560cSBryan Venteicher return (vtpci_legacy_read_header_2(sc, VIRTIO_PCI_QUEUE_NUM)); 7629da9560cSBryan Venteicher } 7639da9560cSBryan Venteicher 7649da9560cSBryan Venteicher static bus_size_t 7659da9560cSBryan Venteicher vtpci_legacy_get_vq_notify_off(device_t dev, int idx) 7669da9560cSBryan Venteicher { 7679da9560cSBryan Venteicher return (VIRTIO_PCI_QUEUE_NOTIFY); 7689da9560cSBryan Venteicher } 7699da9560cSBryan Venteicher 7709da9560cSBryan Venteicher static void 7719da9560cSBryan Venteicher vtpci_legacy_set_vq(device_t dev, struct virtqueue *vq) 7729da9560cSBryan Venteicher { 7739da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 7749da9560cSBryan Venteicher 7759da9560cSBryan Venteicher sc = device_get_softc(dev); 7769da9560cSBryan Venteicher 7779da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(sc, virtqueue_index(vq)); 7789da9560cSBryan Venteicher vtpci_legacy_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN, 7799da9560cSBryan Venteicher virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); 7809da9560cSBryan Venteicher } 7819da9560cSBryan Venteicher 7829da9560cSBryan Venteicher static void 7839da9560cSBryan Venteicher vtpci_legacy_disable_vq(device_t dev, int idx) 7849da9560cSBryan Venteicher { 7859da9560cSBryan Venteicher struct vtpci_legacy_softc *sc; 7869da9560cSBryan Venteicher 7879da9560cSBryan Venteicher sc = device_get_softc(dev); 7889da9560cSBryan Venteicher 7899da9560cSBryan Venteicher vtpci_legacy_select_virtqueue(sc, idx); 7909da9560cSBryan Venteicher vtpci_legacy_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN, 0); 7919da9560cSBryan Venteicher } 792