1*10b59a9bSPeter Grehan /*- 2*10b59a9bSPeter Grehan * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.org> 3*10b59a9bSPeter Grehan * All rights reserved. 4*10b59a9bSPeter Grehan * 5*10b59a9bSPeter Grehan * Redistribution and use in source and binary forms, with or without 6*10b59a9bSPeter Grehan * modification, are permitted provided that the following conditions 7*10b59a9bSPeter Grehan * are met: 8*10b59a9bSPeter Grehan * 1. Redistributions of source code must retain the above copyright 9*10b59a9bSPeter Grehan * notice unmodified, this list of conditions, and the following 10*10b59a9bSPeter Grehan * disclaimer. 11*10b59a9bSPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 12*10b59a9bSPeter Grehan * notice, this list of conditions and the following disclaimer in the 13*10b59a9bSPeter Grehan * documentation and/or other materials provided with the distribution. 14*10b59a9bSPeter Grehan * 15*10b59a9bSPeter Grehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16*10b59a9bSPeter Grehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*10b59a9bSPeter Grehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*10b59a9bSPeter Grehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19*10b59a9bSPeter Grehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20*10b59a9bSPeter Grehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21*10b59a9bSPeter Grehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22*10b59a9bSPeter Grehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23*10b59a9bSPeter Grehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24*10b59a9bSPeter Grehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*10b59a9bSPeter Grehan */ 26*10b59a9bSPeter Grehan 27*10b59a9bSPeter Grehan /* Driver for the VirtIO PCI interface. */ 28*10b59a9bSPeter Grehan 29*10b59a9bSPeter Grehan #include <sys/cdefs.h> 30*10b59a9bSPeter Grehan __FBSDID("$FreeBSD$"); 31*10b59a9bSPeter Grehan 32*10b59a9bSPeter Grehan #include <sys/param.h> 33*10b59a9bSPeter Grehan #include <sys/systm.h> 34*10b59a9bSPeter Grehan #include <sys/bus.h> 35*10b59a9bSPeter Grehan #include <sys/kernel.h> 36*10b59a9bSPeter Grehan #include <sys/module.h> 37*10b59a9bSPeter Grehan #include <sys/malloc.h> 38*10b59a9bSPeter Grehan 39*10b59a9bSPeter Grehan #include <machine/bus.h> 40*10b59a9bSPeter Grehan #include <machine/resource.h> 41*10b59a9bSPeter Grehan #include <sys/bus.h> 42*10b59a9bSPeter Grehan #include <sys/rman.h> 43*10b59a9bSPeter Grehan 44*10b59a9bSPeter Grehan #include <dev/pci/pcivar.h> 45*10b59a9bSPeter Grehan #include <dev/pci/pcireg.h> 46*10b59a9bSPeter Grehan 47*10b59a9bSPeter Grehan #include <dev/virtio/virtio.h> 48*10b59a9bSPeter Grehan #include <dev/virtio/virtqueue.h> 49*10b59a9bSPeter Grehan #include <dev/virtio/pci/virtio_pci.h> 50*10b59a9bSPeter Grehan 51*10b59a9bSPeter Grehan #include "virtio_bus_if.h" 52*10b59a9bSPeter Grehan #include "virtio_if.h" 53*10b59a9bSPeter Grehan 54*10b59a9bSPeter Grehan struct vtpci_softc { 55*10b59a9bSPeter Grehan device_t vtpci_dev; 56*10b59a9bSPeter Grehan struct resource *vtpci_res; 57*10b59a9bSPeter Grehan struct resource *vtpci_msix_res; 58*10b59a9bSPeter Grehan uint64_t vtpci_features; 59*10b59a9bSPeter Grehan uint32_t vtpci_flags; 60*10b59a9bSPeter Grehan #define VIRTIO_PCI_FLAG_NO_MSI 0x0001 61*10b59a9bSPeter Grehan #define VIRTIO_PCI_FLAG_MSI 0x0002 62*10b59a9bSPeter Grehan #define VIRTIO_PCI_FLAG_NO_MSIX 0x0010 63*10b59a9bSPeter Grehan #define VIRTIO_PCI_FLAG_MSIX 0x0020 64*10b59a9bSPeter Grehan #define VIRTIO_PCI_FLAG_SHARED_MSIX 0x0040 65*10b59a9bSPeter Grehan 66*10b59a9bSPeter Grehan device_t vtpci_child_dev; 67*10b59a9bSPeter Grehan struct virtio_feature_desc *vtpci_child_feat_desc; 68*10b59a9bSPeter Grehan 69*10b59a9bSPeter Grehan /* 70*10b59a9bSPeter Grehan * Ideally, each virtqueue that the driver provides a callback for 71*10b59a9bSPeter Grehan * will receive its own MSIX vector. If there are not sufficient 72*10b59a9bSPeter Grehan * vectors available, we will then attempt to have all the VQs 73*10b59a9bSPeter Grehan * share one vector. Note that when using MSIX, the configuration 74*10b59a9bSPeter Grehan * changed notifications must be on their own vector. 75*10b59a9bSPeter Grehan * 76*10b59a9bSPeter Grehan * If MSIX is not available, we will attempt to have the whole 77*10b59a9bSPeter Grehan * device share one MSI vector, and then, finally, one legacy 78*10b59a9bSPeter Grehan * interrupt. 79*10b59a9bSPeter Grehan */ 80*10b59a9bSPeter Grehan int vtpci_nvqs; 81*10b59a9bSPeter Grehan struct vtpci_virtqueue { 82*10b59a9bSPeter Grehan struct virtqueue *vq; 83*10b59a9bSPeter Grehan 84*10b59a9bSPeter Grehan /* Index into vtpci_intr_res[] below. Unused, then -1. */ 85*10b59a9bSPeter Grehan int ires_idx; 86*10b59a9bSPeter Grehan } vtpci_vqx[VIRTIO_MAX_VIRTQUEUES]; 87*10b59a9bSPeter Grehan 88*10b59a9bSPeter Grehan /* 89*10b59a9bSPeter Grehan * When using MSIX interrupts, the first element of vtpci_intr_res[] 90*10b59a9bSPeter Grehan * is always the configuration changed notifications. The remaining 91*10b59a9bSPeter Grehan * element(s) are used for the virtqueues. 92*10b59a9bSPeter Grehan * 93*10b59a9bSPeter Grehan * With MSI and legacy interrupts, only the first element of 94*10b59a9bSPeter Grehan * vtpci_intr_res[] is used. 95*10b59a9bSPeter Grehan */ 96*10b59a9bSPeter Grehan int vtpci_nintr_res; 97*10b59a9bSPeter Grehan struct vtpci_intr_resource { 98*10b59a9bSPeter Grehan struct resource *irq; 99*10b59a9bSPeter Grehan int rid; 100*10b59a9bSPeter Grehan void *intrhand; 101*10b59a9bSPeter Grehan } vtpci_intr_res[1 + VIRTIO_MAX_VIRTQUEUES]; 102*10b59a9bSPeter Grehan }; 103*10b59a9bSPeter Grehan 104*10b59a9bSPeter Grehan static int vtpci_probe(device_t); 105*10b59a9bSPeter Grehan static int vtpci_attach(device_t); 106*10b59a9bSPeter Grehan static int vtpci_detach(device_t); 107*10b59a9bSPeter Grehan static int vtpci_suspend(device_t); 108*10b59a9bSPeter Grehan static int vtpci_resume(device_t); 109*10b59a9bSPeter Grehan static int vtpci_shutdown(device_t); 110*10b59a9bSPeter Grehan static void vtpci_driver_added(device_t, driver_t *); 111*10b59a9bSPeter Grehan static void vtpci_child_detached(device_t, device_t); 112*10b59a9bSPeter Grehan static int vtpci_read_ivar(device_t, device_t, int, uintptr_t *); 113*10b59a9bSPeter Grehan static int vtpci_write_ivar(device_t, device_t, int, uintptr_t); 114*10b59a9bSPeter Grehan 115*10b59a9bSPeter Grehan static uint64_t vtpci_negotiate_features(device_t, uint64_t); 116*10b59a9bSPeter Grehan static int vtpci_with_feature(device_t, uint64_t); 117*10b59a9bSPeter Grehan static int vtpci_alloc_virtqueues(device_t, int, int, 118*10b59a9bSPeter Grehan struct vq_alloc_info *); 119*10b59a9bSPeter Grehan static int vtpci_setup_intr(device_t, enum intr_type); 120*10b59a9bSPeter Grehan static void vtpci_stop(device_t); 121*10b59a9bSPeter Grehan static int vtpci_reinit(device_t, uint64_t); 122*10b59a9bSPeter Grehan static void vtpci_reinit_complete(device_t); 123*10b59a9bSPeter Grehan static void vtpci_notify_virtqueue(device_t, uint16_t); 124*10b59a9bSPeter Grehan static uint8_t vtpci_get_status(device_t); 125*10b59a9bSPeter Grehan static void vtpci_set_status(device_t, uint8_t); 126*10b59a9bSPeter Grehan static void vtpci_read_dev_config(device_t, bus_size_t, void *, int); 127*10b59a9bSPeter Grehan static void vtpci_write_dev_config(device_t, bus_size_t, void *, int); 128*10b59a9bSPeter Grehan 129*10b59a9bSPeter Grehan static void vtpci_describe_features(struct vtpci_softc *, const char *, 130*10b59a9bSPeter Grehan uint64_t); 131*10b59a9bSPeter Grehan static void vtpci_probe_and_attach_child(struct vtpci_softc *); 132*10b59a9bSPeter Grehan 133*10b59a9bSPeter Grehan static int vtpci_alloc_interrupts(struct vtpci_softc *, int, int, 134*10b59a9bSPeter Grehan struct vq_alloc_info *); 135*10b59a9bSPeter Grehan static int vtpci_alloc_intr_resources(struct vtpci_softc *, int, 136*10b59a9bSPeter Grehan struct vq_alloc_info *); 137*10b59a9bSPeter Grehan static int vtpci_alloc_msi(struct vtpci_softc *); 138*10b59a9bSPeter Grehan static int vtpci_alloc_msix(struct vtpci_softc *, int); 139*10b59a9bSPeter Grehan static int vtpci_register_msix_vector(struct vtpci_softc *, int, int); 140*10b59a9bSPeter Grehan 141*10b59a9bSPeter Grehan static void vtpci_free_interrupts(struct vtpci_softc *); 142*10b59a9bSPeter Grehan static void vtpci_free_virtqueues(struct vtpci_softc *); 143*10b59a9bSPeter Grehan static void vtpci_release_child_resources(struct vtpci_softc *); 144*10b59a9bSPeter Grehan static void vtpci_reset(struct vtpci_softc *); 145*10b59a9bSPeter Grehan 146*10b59a9bSPeter Grehan static int vtpci_legacy_intr(void *); 147*10b59a9bSPeter Grehan static int vtpci_vq_shared_intr(void *); 148*10b59a9bSPeter Grehan static int vtpci_vq_intr(void *); 149*10b59a9bSPeter Grehan static int vtpci_config_intr(void *); 150*10b59a9bSPeter Grehan 151*10b59a9bSPeter Grehan /* 152*10b59a9bSPeter Grehan * I/O port read/write wrappers. 153*10b59a9bSPeter Grehan */ 154*10b59a9bSPeter Grehan #define vtpci_read_config_1(sc, o) bus_read_1((sc)->vtpci_res, (o)) 155*10b59a9bSPeter Grehan #define vtpci_read_config_2(sc, o) bus_read_2((sc)->vtpci_res, (o)) 156*10b59a9bSPeter Grehan #define vtpci_read_config_4(sc, o) bus_read_4((sc)->vtpci_res, (o)) 157*10b59a9bSPeter Grehan #define vtpci_write_config_1(sc, o, v) bus_write_1((sc)->vtpci_res, (o), (v)) 158*10b59a9bSPeter Grehan #define vtpci_write_config_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (v)) 159*10b59a9bSPeter Grehan #define vtpci_write_config_4(sc, o, v) bus_write_4((sc)->vtpci_res, (o), (v)) 160*10b59a9bSPeter Grehan 161*10b59a9bSPeter Grehan /* Tunables. */ 162*10b59a9bSPeter Grehan static int vtpci_disable_msix = 0; 163*10b59a9bSPeter Grehan TUNABLE_INT("hw.virtio.pci.disable_msix", &vtpci_disable_msix); 164*10b59a9bSPeter Grehan 165*10b59a9bSPeter Grehan static device_method_t vtpci_methods[] = { 166*10b59a9bSPeter Grehan /* Device interface. */ 167*10b59a9bSPeter Grehan DEVMETHOD(device_probe, vtpci_probe), 168*10b59a9bSPeter Grehan DEVMETHOD(device_attach, vtpci_attach), 169*10b59a9bSPeter Grehan DEVMETHOD(device_detach, vtpci_detach), 170*10b59a9bSPeter Grehan DEVMETHOD(device_suspend, vtpci_suspend), 171*10b59a9bSPeter Grehan DEVMETHOD(device_resume, vtpci_resume), 172*10b59a9bSPeter Grehan DEVMETHOD(device_shutdown, vtpci_shutdown), 173*10b59a9bSPeter Grehan 174*10b59a9bSPeter Grehan /* Bus interface. */ 175*10b59a9bSPeter Grehan DEVMETHOD(bus_driver_added, vtpci_driver_added), 176*10b59a9bSPeter Grehan DEVMETHOD(bus_child_detached, vtpci_child_detached), 177*10b59a9bSPeter Grehan DEVMETHOD(bus_read_ivar, vtpci_read_ivar), 178*10b59a9bSPeter Grehan DEVMETHOD(bus_write_ivar, vtpci_write_ivar), 179*10b59a9bSPeter Grehan 180*10b59a9bSPeter Grehan /* VirtIO bus interface. */ 181*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_negotiate_features, vtpci_negotiate_features), 182*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_with_feature, vtpci_with_feature), 183*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_alloc_virtqueues, vtpci_alloc_virtqueues), 184*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_setup_intr, vtpci_setup_intr), 185*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_stop, vtpci_stop), 186*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_reinit, vtpci_reinit), 187*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_reinit_complete, vtpci_reinit_complete), 188*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_notify_vq, vtpci_notify_virtqueue), 189*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_read_device_config, vtpci_read_dev_config), 190*10b59a9bSPeter Grehan DEVMETHOD(virtio_bus_write_device_config, vtpci_write_dev_config), 191*10b59a9bSPeter Grehan 192*10b59a9bSPeter Grehan { 0, 0 } 193*10b59a9bSPeter Grehan }; 194*10b59a9bSPeter Grehan 195*10b59a9bSPeter Grehan static driver_t vtpci_driver = { 196*10b59a9bSPeter Grehan "virtio_pci", 197*10b59a9bSPeter Grehan vtpci_methods, 198*10b59a9bSPeter Grehan sizeof(struct vtpci_softc) 199*10b59a9bSPeter Grehan }; 200*10b59a9bSPeter Grehan 201*10b59a9bSPeter Grehan devclass_t vtpci_devclass; 202*10b59a9bSPeter Grehan 203*10b59a9bSPeter Grehan DRIVER_MODULE(virtio_pci, pci, vtpci_driver, vtpci_devclass, 0, 0); 204*10b59a9bSPeter Grehan MODULE_VERSION(virtio_pci, 1); 205*10b59a9bSPeter Grehan MODULE_DEPEND(virtio_pci, pci, 1, 1, 1); 206*10b59a9bSPeter Grehan MODULE_DEPEND(virtio_pci, virtio, 1, 1, 1); 207*10b59a9bSPeter Grehan 208*10b59a9bSPeter Grehan static int 209*10b59a9bSPeter Grehan vtpci_probe(device_t dev) 210*10b59a9bSPeter Grehan { 211*10b59a9bSPeter Grehan char desc[36]; 212*10b59a9bSPeter Grehan const char *name; 213*10b59a9bSPeter Grehan 214*10b59a9bSPeter Grehan if (pci_get_vendor(dev) != VIRTIO_PCI_VENDORID) 215*10b59a9bSPeter Grehan return (ENXIO); 216*10b59a9bSPeter Grehan 217*10b59a9bSPeter Grehan if (pci_get_device(dev) < VIRTIO_PCI_DEVICEID_MIN || 218*10b59a9bSPeter Grehan pci_get_device(dev) > VIRTIO_PCI_DEVICEID_MAX) 219*10b59a9bSPeter Grehan return (ENXIO); 220*10b59a9bSPeter Grehan 221*10b59a9bSPeter Grehan if (pci_get_revid(dev) != VIRTIO_PCI_ABI_VERSION) 222*10b59a9bSPeter Grehan return (ENXIO); 223*10b59a9bSPeter Grehan 224*10b59a9bSPeter Grehan name = virtio_device_name(pci_get_subdevice(dev)); 225*10b59a9bSPeter Grehan if (name == NULL) 226*10b59a9bSPeter Grehan name = "Unknown"; 227*10b59a9bSPeter Grehan 228*10b59a9bSPeter Grehan snprintf(desc, sizeof(desc), "VirtIO PCI %s adapter", name); 229*10b59a9bSPeter Grehan device_set_desc_copy(dev, desc); 230*10b59a9bSPeter Grehan 231*10b59a9bSPeter Grehan return (BUS_PROBE_DEFAULT); 232*10b59a9bSPeter Grehan } 233*10b59a9bSPeter Grehan 234*10b59a9bSPeter Grehan static int 235*10b59a9bSPeter Grehan vtpci_attach(device_t dev) 236*10b59a9bSPeter Grehan { 237*10b59a9bSPeter Grehan struct vtpci_softc *sc; 238*10b59a9bSPeter Grehan device_t child; 239*10b59a9bSPeter Grehan int rid; 240*10b59a9bSPeter Grehan 241*10b59a9bSPeter Grehan sc = device_get_softc(dev); 242*10b59a9bSPeter Grehan sc->vtpci_dev = dev; 243*10b59a9bSPeter Grehan 244*10b59a9bSPeter Grehan pci_enable_busmaster(dev); 245*10b59a9bSPeter Grehan 246*10b59a9bSPeter Grehan rid = PCIR_BAR(0); 247*10b59a9bSPeter Grehan sc->vtpci_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 248*10b59a9bSPeter Grehan RF_ACTIVE); 249*10b59a9bSPeter Grehan if (sc->vtpci_res == NULL) { 250*10b59a9bSPeter Grehan device_printf(dev, "cannot map I/O space\n"); 251*10b59a9bSPeter Grehan return (ENXIO); 252*10b59a9bSPeter Grehan } 253*10b59a9bSPeter Grehan 254*10b59a9bSPeter Grehan if (pci_find_extcap(dev, PCIY_MSI, NULL) != 0) 255*10b59a9bSPeter Grehan sc->vtpci_flags |= VIRTIO_PCI_FLAG_NO_MSI; 256*10b59a9bSPeter Grehan 257*10b59a9bSPeter Grehan if (pci_find_extcap(dev, PCIY_MSIX, NULL) == 0) { 258*10b59a9bSPeter Grehan rid = PCIR_BAR(1); 259*10b59a9bSPeter Grehan sc->vtpci_msix_res = bus_alloc_resource_any(dev, 260*10b59a9bSPeter Grehan SYS_RES_MEMORY, &rid, RF_ACTIVE); 261*10b59a9bSPeter Grehan } 262*10b59a9bSPeter Grehan 263*10b59a9bSPeter Grehan if (sc->vtpci_msix_res == NULL) 264*10b59a9bSPeter Grehan sc->vtpci_flags |= VIRTIO_PCI_FLAG_NO_MSIX; 265*10b59a9bSPeter Grehan 266*10b59a9bSPeter Grehan vtpci_reset(sc); 267*10b59a9bSPeter Grehan 268*10b59a9bSPeter Grehan /* Tell the host we've noticed this device. */ 269*10b59a9bSPeter Grehan vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); 270*10b59a9bSPeter Grehan 271*10b59a9bSPeter Grehan if ((child = device_add_child(dev, NULL, -1)) == NULL) { 272*10b59a9bSPeter Grehan device_printf(dev, "cannot create child device\n"); 273*10b59a9bSPeter Grehan vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED); 274*10b59a9bSPeter Grehan vtpci_detach(dev); 275*10b59a9bSPeter Grehan return (ENOMEM); 276*10b59a9bSPeter Grehan } 277*10b59a9bSPeter Grehan 278*10b59a9bSPeter Grehan sc->vtpci_child_dev = child; 279*10b59a9bSPeter Grehan vtpci_probe_and_attach_child(sc); 280*10b59a9bSPeter Grehan 281*10b59a9bSPeter Grehan return (0); 282*10b59a9bSPeter Grehan } 283*10b59a9bSPeter Grehan 284*10b59a9bSPeter Grehan static int 285*10b59a9bSPeter Grehan vtpci_detach(device_t dev) 286*10b59a9bSPeter Grehan { 287*10b59a9bSPeter Grehan struct vtpci_softc *sc; 288*10b59a9bSPeter Grehan device_t child; 289*10b59a9bSPeter Grehan int error; 290*10b59a9bSPeter Grehan 291*10b59a9bSPeter Grehan sc = device_get_softc(dev); 292*10b59a9bSPeter Grehan 293*10b59a9bSPeter Grehan if ((child = sc->vtpci_child_dev) != NULL) { 294*10b59a9bSPeter Grehan error = device_delete_child(dev, child); 295*10b59a9bSPeter Grehan if (error) 296*10b59a9bSPeter Grehan return (error); 297*10b59a9bSPeter Grehan sc->vtpci_child_dev = NULL; 298*10b59a9bSPeter Grehan } 299*10b59a9bSPeter Grehan 300*10b59a9bSPeter Grehan vtpci_reset(sc); 301*10b59a9bSPeter Grehan 302*10b59a9bSPeter Grehan if (sc->vtpci_msix_res != NULL) { 303*10b59a9bSPeter Grehan bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(1), 304*10b59a9bSPeter Grehan sc->vtpci_msix_res); 305*10b59a9bSPeter Grehan sc->vtpci_msix_res = NULL; 306*10b59a9bSPeter Grehan } 307*10b59a9bSPeter Grehan 308*10b59a9bSPeter Grehan if (sc->vtpci_res != NULL) { 309*10b59a9bSPeter Grehan bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), 310*10b59a9bSPeter Grehan sc->vtpci_res); 311*10b59a9bSPeter Grehan sc->vtpci_res = NULL; 312*10b59a9bSPeter Grehan } 313*10b59a9bSPeter Grehan 314*10b59a9bSPeter Grehan return (0); 315*10b59a9bSPeter Grehan } 316*10b59a9bSPeter Grehan 317*10b59a9bSPeter Grehan static int 318*10b59a9bSPeter Grehan vtpci_suspend(device_t dev) 319*10b59a9bSPeter Grehan { 320*10b59a9bSPeter Grehan 321*10b59a9bSPeter Grehan return (bus_generic_suspend(dev)); 322*10b59a9bSPeter Grehan } 323*10b59a9bSPeter Grehan 324*10b59a9bSPeter Grehan static int 325*10b59a9bSPeter Grehan vtpci_resume(device_t dev) 326*10b59a9bSPeter Grehan { 327*10b59a9bSPeter Grehan 328*10b59a9bSPeter Grehan return (bus_generic_resume(dev)); 329*10b59a9bSPeter Grehan } 330*10b59a9bSPeter Grehan 331*10b59a9bSPeter Grehan static int 332*10b59a9bSPeter Grehan vtpci_shutdown(device_t dev) 333*10b59a9bSPeter Grehan { 334*10b59a9bSPeter Grehan 335*10b59a9bSPeter Grehan (void) bus_generic_shutdown(dev); 336*10b59a9bSPeter Grehan /* Forcibly stop the host device. */ 337*10b59a9bSPeter Grehan vtpci_stop(dev); 338*10b59a9bSPeter Grehan 339*10b59a9bSPeter Grehan return (0); 340*10b59a9bSPeter Grehan } 341*10b59a9bSPeter Grehan 342*10b59a9bSPeter Grehan static void 343*10b59a9bSPeter Grehan vtpci_driver_added(device_t dev, driver_t *driver) 344*10b59a9bSPeter Grehan { 345*10b59a9bSPeter Grehan struct vtpci_softc *sc; 346*10b59a9bSPeter Grehan 347*10b59a9bSPeter Grehan sc = device_get_softc(dev); 348*10b59a9bSPeter Grehan 349*10b59a9bSPeter Grehan vtpci_probe_and_attach_child(sc); 350*10b59a9bSPeter Grehan } 351*10b59a9bSPeter Grehan 352*10b59a9bSPeter Grehan static void 353*10b59a9bSPeter Grehan vtpci_child_detached(device_t dev, device_t child) 354*10b59a9bSPeter Grehan { 355*10b59a9bSPeter Grehan struct vtpci_softc *sc; 356*10b59a9bSPeter Grehan 357*10b59a9bSPeter Grehan sc = device_get_softc(dev); 358*10b59a9bSPeter Grehan 359*10b59a9bSPeter Grehan vtpci_reset(sc); 360*10b59a9bSPeter Grehan vtpci_release_child_resources(sc); 361*10b59a9bSPeter Grehan } 362*10b59a9bSPeter Grehan 363*10b59a9bSPeter Grehan static int 364*10b59a9bSPeter Grehan vtpci_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 365*10b59a9bSPeter Grehan { 366*10b59a9bSPeter Grehan struct vtpci_softc *sc; 367*10b59a9bSPeter Grehan 368*10b59a9bSPeter Grehan sc = device_get_softc(dev); 369*10b59a9bSPeter Grehan 370*10b59a9bSPeter Grehan if (sc->vtpci_child_dev != child) 371*10b59a9bSPeter Grehan return (ENOENT); 372*10b59a9bSPeter Grehan 373*10b59a9bSPeter Grehan switch (index) { 374*10b59a9bSPeter Grehan case VIRTIO_IVAR_DEVTYPE: 375*10b59a9bSPeter Grehan *result = pci_get_subdevice(dev); 376*10b59a9bSPeter Grehan break; 377*10b59a9bSPeter Grehan default: 378*10b59a9bSPeter Grehan return (ENOENT); 379*10b59a9bSPeter Grehan } 380*10b59a9bSPeter Grehan 381*10b59a9bSPeter Grehan return (0); 382*10b59a9bSPeter Grehan } 383*10b59a9bSPeter Grehan 384*10b59a9bSPeter Grehan static int 385*10b59a9bSPeter Grehan vtpci_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 386*10b59a9bSPeter Grehan { 387*10b59a9bSPeter Grehan struct vtpci_softc *sc; 388*10b59a9bSPeter Grehan 389*10b59a9bSPeter Grehan sc = device_get_softc(dev); 390*10b59a9bSPeter Grehan 391*10b59a9bSPeter Grehan if (sc->vtpci_child_dev != child) 392*10b59a9bSPeter Grehan return (ENOENT); 393*10b59a9bSPeter Grehan 394*10b59a9bSPeter Grehan switch (index) { 395*10b59a9bSPeter Grehan case VIRTIO_IVAR_FEATURE_DESC: 396*10b59a9bSPeter Grehan sc->vtpci_child_feat_desc = (void *) value; 397*10b59a9bSPeter Grehan break; 398*10b59a9bSPeter Grehan default: 399*10b59a9bSPeter Grehan return (ENOENT); 400*10b59a9bSPeter Grehan } 401*10b59a9bSPeter Grehan 402*10b59a9bSPeter Grehan return (0); 403*10b59a9bSPeter Grehan } 404*10b59a9bSPeter Grehan 405*10b59a9bSPeter Grehan static uint64_t 406*10b59a9bSPeter Grehan vtpci_negotiate_features(device_t dev, uint64_t child_features) 407*10b59a9bSPeter Grehan { 408*10b59a9bSPeter Grehan struct vtpci_softc *sc; 409*10b59a9bSPeter Grehan uint64_t host_features, features; 410*10b59a9bSPeter Grehan 411*10b59a9bSPeter Grehan sc = device_get_softc(dev); 412*10b59a9bSPeter Grehan 413*10b59a9bSPeter Grehan host_features = vtpci_read_config_4(sc, VIRTIO_PCI_HOST_FEATURES); 414*10b59a9bSPeter Grehan vtpci_describe_features(sc, "host", host_features); 415*10b59a9bSPeter Grehan 416*10b59a9bSPeter Grehan /* 417*10b59a9bSPeter Grehan * Limit negotiated features to what the driver, virtqueue, and 418*10b59a9bSPeter Grehan * host all support. 419*10b59a9bSPeter Grehan */ 420*10b59a9bSPeter Grehan features = host_features & child_features; 421*10b59a9bSPeter Grehan features = virtqueue_filter_features(features); 422*10b59a9bSPeter Grehan sc->vtpci_features = features; 423*10b59a9bSPeter Grehan 424*10b59a9bSPeter Grehan vtpci_describe_features(sc, "negotiated", features); 425*10b59a9bSPeter Grehan vtpci_write_config_4(sc, VIRTIO_PCI_GUEST_FEATURES, features); 426*10b59a9bSPeter Grehan 427*10b59a9bSPeter Grehan return (features); 428*10b59a9bSPeter Grehan } 429*10b59a9bSPeter Grehan 430*10b59a9bSPeter Grehan static int 431*10b59a9bSPeter Grehan vtpci_with_feature(device_t dev, uint64_t feature) 432*10b59a9bSPeter Grehan { 433*10b59a9bSPeter Grehan struct vtpci_softc *sc; 434*10b59a9bSPeter Grehan 435*10b59a9bSPeter Grehan sc = device_get_softc(dev); 436*10b59a9bSPeter Grehan 437*10b59a9bSPeter Grehan return ((sc->vtpci_features & feature) != 0); 438*10b59a9bSPeter Grehan } 439*10b59a9bSPeter Grehan 440*10b59a9bSPeter Grehan static int 441*10b59a9bSPeter Grehan vtpci_alloc_virtqueues(device_t dev, int flags, int nvqs, 442*10b59a9bSPeter Grehan struct vq_alloc_info *vq_info) 443*10b59a9bSPeter Grehan { 444*10b59a9bSPeter Grehan struct vtpci_softc *sc; 445*10b59a9bSPeter Grehan struct vtpci_virtqueue *vqx; 446*10b59a9bSPeter Grehan struct vq_alloc_info *info; 447*10b59a9bSPeter Grehan int queue, error; 448*10b59a9bSPeter Grehan uint16_t vq_size; 449*10b59a9bSPeter Grehan 450*10b59a9bSPeter Grehan sc = device_get_softc(dev); 451*10b59a9bSPeter Grehan 452*10b59a9bSPeter Grehan if (sc->vtpci_nvqs != 0 || nvqs <= 0 || 453*10b59a9bSPeter Grehan nvqs > VIRTIO_MAX_VIRTQUEUES) 454*10b59a9bSPeter Grehan return (EINVAL); 455*10b59a9bSPeter Grehan 456*10b59a9bSPeter Grehan error = vtpci_alloc_interrupts(sc, flags, nvqs, vq_info); 457*10b59a9bSPeter Grehan if (error) { 458*10b59a9bSPeter Grehan device_printf(dev, "cannot allocate interrupts\n"); 459*10b59a9bSPeter Grehan return (error); 460*10b59a9bSPeter Grehan } 461*10b59a9bSPeter Grehan 462*10b59a9bSPeter Grehan if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 463*10b59a9bSPeter Grehan error = vtpci_register_msix_vector(sc, 464*10b59a9bSPeter Grehan VIRTIO_MSI_CONFIG_VECTOR, 0); 465*10b59a9bSPeter Grehan if (error) 466*10b59a9bSPeter Grehan return (error); 467*10b59a9bSPeter Grehan } 468*10b59a9bSPeter Grehan 469*10b59a9bSPeter Grehan for (queue = 0; queue < nvqs; queue++) { 470*10b59a9bSPeter Grehan vqx = &sc->vtpci_vqx[queue]; 471*10b59a9bSPeter Grehan info = &vq_info[queue]; 472*10b59a9bSPeter Grehan 473*10b59a9bSPeter Grehan vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, queue); 474*10b59a9bSPeter Grehan 475*10b59a9bSPeter Grehan vq_size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); 476*10b59a9bSPeter Grehan error = virtqueue_alloc(dev, queue, vq_size, 477*10b59a9bSPeter Grehan VIRTIO_PCI_VRING_ALIGN, 0xFFFFFFFFUL, info, &vqx->vq); 478*10b59a9bSPeter Grehan if (error) 479*10b59a9bSPeter Grehan return (error); 480*10b59a9bSPeter Grehan 481*10b59a9bSPeter Grehan if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 482*10b59a9bSPeter Grehan error = vtpci_register_msix_vector(sc, 483*10b59a9bSPeter Grehan VIRTIO_MSI_QUEUE_VECTOR, vqx->ires_idx); 484*10b59a9bSPeter Grehan if (error) 485*10b59a9bSPeter Grehan return (error); 486*10b59a9bSPeter Grehan } 487*10b59a9bSPeter Grehan 488*10b59a9bSPeter Grehan vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, 489*10b59a9bSPeter Grehan virtqueue_paddr(vqx->vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); 490*10b59a9bSPeter Grehan 491*10b59a9bSPeter Grehan *info->vqai_vq = vqx->vq; 492*10b59a9bSPeter Grehan sc->vtpci_nvqs++; 493*10b59a9bSPeter Grehan } 494*10b59a9bSPeter Grehan 495*10b59a9bSPeter Grehan return (0); 496*10b59a9bSPeter Grehan } 497*10b59a9bSPeter Grehan 498*10b59a9bSPeter Grehan static int 499*10b59a9bSPeter Grehan vtpci_setup_intr(device_t dev, enum intr_type type) 500*10b59a9bSPeter Grehan { 501*10b59a9bSPeter Grehan struct vtpci_softc *sc; 502*10b59a9bSPeter Grehan struct vtpci_intr_resource *ires; 503*10b59a9bSPeter Grehan struct vtpci_virtqueue *vqx; 504*10b59a9bSPeter Grehan int i, flags, error; 505*10b59a9bSPeter Grehan 506*10b59a9bSPeter Grehan sc = device_get_softc(dev); 507*10b59a9bSPeter Grehan flags = type | INTR_MPSAFE; 508*10b59a9bSPeter Grehan ires = &sc->vtpci_intr_res[0]; 509*10b59a9bSPeter Grehan 510*10b59a9bSPeter Grehan if ((sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) == 0) { 511*10b59a9bSPeter Grehan error = bus_setup_intr(dev, ires->irq, flags, 512*10b59a9bSPeter Grehan vtpci_legacy_intr, NULL, sc, &ires->intrhand); 513*10b59a9bSPeter Grehan 514*10b59a9bSPeter Grehan return (error); 515*10b59a9bSPeter Grehan } 516*10b59a9bSPeter Grehan 517*10b59a9bSPeter Grehan error = bus_setup_intr(dev, ires->irq, flags, vtpci_config_intr, 518*10b59a9bSPeter Grehan NULL, sc, &ires->intrhand); 519*10b59a9bSPeter Grehan if (error) 520*10b59a9bSPeter Grehan return (error); 521*10b59a9bSPeter Grehan 522*10b59a9bSPeter Grehan if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX) { 523*10b59a9bSPeter Grehan ires = &sc->vtpci_intr_res[1]; 524*10b59a9bSPeter Grehan error = bus_setup_intr(dev, ires->irq, flags, 525*10b59a9bSPeter Grehan vtpci_vq_shared_intr, NULL, sc, &ires->intrhand); 526*10b59a9bSPeter Grehan 527*10b59a9bSPeter Grehan return (error); 528*10b59a9bSPeter Grehan } 529*10b59a9bSPeter Grehan 530*10b59a9bSPeter Grehan /* Setup an interrupt handler for each virtqueue. */ 531*10b59a9bSPeter Grehan for (i = 0; i < sc->vtpci_nvqs; i++) { 532*10b59a9bSPeter Grehan vqx = &sc->vtpci_vqx[i]; 533*10b59a9bSPeter Grehan if (vqx->ires_idx < 1) 534*10b59a9bSPeter Grehan continue; 535*10b59a9bSPeter Grehan 536*10b59a9bSPeter Grehan ires = &sc->vtpci_intr_res[vqx->ires_idx]; 537*10b59a9bSPeter Grehan error = bus_setup_intr(dev, ires->irq, flags, 538*10b59a9bSPeter Grehan vtpci_vq_intr, NULL, vqx->vq, &ires->intrhand); 539*10b59a9bSPeter Grehan if (error) 540*10b59a9bSPeter Grehan return (error); 541*10b59a9bSPeter Grehan } 542*10b59a9bSPeter Grehan 543*10b59a9bSPeter Grehan return (0); 544*10b59a9bSPeter Grehan } 545*10b59a9bSPeter Grehan 546*10b59a9bSPeter Grehan static void 547*10b59a9bSPeter Grehan vtpci_stop(device_t dev) 548*10b59a9bSPeter Grehan { 549*10b59a9bSPeter Grehan 550*10b59a9bSPeter Grehan vtpci_reset(device_get_softc(dev)); 551*10b59a9bSPeter Grehan } 552*10b59a9bSPeter Grehan 553*10b59a9bSPeter Grehan static int 554*10b59a9bSPeter Grehan vtpci_reinit(device_t dev, uint64_t features) 555*10b59a9bSPeter Grehan { 556*10b59a9bSPeter Grehan struct vtpci_softc *sc; 557*10b59a9bSPeter Grehan struct vtpci_virtqueue *vqx; 558*10b59a9bSPeter Grehan struct virtqueue *vq; 559*10b59a9bSPeter Grehan int queue, error; 560*10b59a9bSPeter Grehan uint16_t vq_size; 561*10b59a9bSPeter Grehan 562*10b59a9bSPeter Grehan sc = device_get_softc(dev); 563*10b59a9bSPeter Grehan 564*10b59a9bSPeter Grehan /* 565*10b59a9bSPeter Grehan * Redrive the device initialization. This is a bit of an abuse 566*10b59a9bSPeter Grehan * of the specification, but both VirtualBox and QEMU/KVM seem 567*10b59a9bSPeter Grehan * to play nice. We do not allow the host device to change from 568*10b59a9bSPeter Grehan * what was originally negotiated beyond what the guest driver 569*10b59a9bSPeter Grehan * changed (MSIX state should not change, number of virtqueues 570*10b59a9bSPeter Grehan * and their size remain the same, etc). 571*10b59a9bSPeter Grehan */ 572*10b59a9bSPeter Grehan 573*10b59a9bSPeter Grehan if (vtpci_get_status(dev) != VIRTIO_CONFIG_STATUS_RESET) 574*10b59a9bSPeter Grehan vtpci_stop(dev); 575*10b59a9bSPeter Grehan 576*10b59a9bSPeter Grehan /* 577*10b59a9bSPeter Grehan * Quickly drive the status through ACK and DRIVER. The device 578*10b59a9bSPeter Grehan * does not become usable again until vtpci_reinit_complete(). 579*10b59a9bSPeter Grehan */ 580*10b59a9bSPeter Grehan vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); 581*10b59a9bSPeter Grehan vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER); 582*10b59a9bSPeter Grehan 583*10b59a9bSPeter Grehan vtpci_negotiate_features(dev, features); 584*10b59a9bSPeter Grehan 585*10b59a9bSPeter Grehan if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 586*10b59a9bSPeter Grehan error = vtpci_register_msix_vector(sc, 587*10b59a9bSPeter Grehan VIRTIO_MSI_CONFIG_VECTOR, 0); 588*10b59a9bSPeter Grehan if (error) 589*10b59a9bSPeter Grehan return (error); 590*10b59a9bSPeter Grehan } 591*10b59a9bSPeter Grehan 592*10b59a9bSPeter Grehan for (queue = 0; queue < sc->vtpci_nvqs; queue++) { 593*10b59a9bSPeter Grehan vqx = &sc->vtpci_vqx[queue]; 594*10b59a9bSPeter Grehan vq = vqx->vq; 595*10b59a9bSPeter Grehan 596*10b59a9bSPeter Grehan KASSERT(vq != NULL, ("vq %d not allocated", queue)); 597*10b59a9bSPeter Grehan vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, queue); 598*10b59a9bSPeter Grehan 599*10b59a9bSPeter Grehan vq_size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); 600*10b59a9bSPeter Grehan error = virtqueue_reinit(vq, vq_size); 601*10b59a9bSPeter Grehan if (error) 602*10b59a9bSPeter Grehan return (error); 603*10b59a9bSPeter Grehan 604*10b59a9bSPeter Grehan if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 605*10b59a9bSPeter Grehan error = vtpci_register_msix_vector(sc, 606*10b59a9bSPeter Grehan VIRTIO_MSI_QUEUE_VECTOR, vqx->ires_idx); 607*10b59a9bSPeter Grehan if (error) 608*10b59a9bSPeter Grehan return (error); 609*10b59a9bSPeter Grehan } 610*10b59a9bSPeter Grehan 611*10b59a9bSPeter Grehan vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, 612*10b59a9bSPeter Grehan virtqueue_paddr(vqx->vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); 613*10b59a9bSPeter Grehan } 614*10b59a9bSPeter Grehan 615*10b59a9bSPeter Grehan return (0); 616*10b59a9bSPeter Grehan } 617*10b59a9bSPeter Grehan 618*10b59a9bSPeter Grehan static void 619*10b59a9bSPeter Grehan vtpci_reinit_complete(device_t dev) 620*10b59a9bSPeter Grehan { 621*10b59a9bSPeter Grehan 622*10b59a9bSPeter Grehan vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER_OK); 623*10b59a9bSPeter Grehan } 624*10b59a9bSPeter Grehan 625*10b59a9bSPeter Grehan static void 626*10b59a9bSPeter Grehan vtpci_notify_virtqueue(device_t dev, uint16_t queue) 627*10b59a9bSPeter Grehan { 628*10b59a9bSPeter Grehan struct vtpci_softc *sc; 629*10b59a9bSPeter Grehan 630*10b59a9bSPeter Grehan sc = device_get_softc(dev); 631*10b59a9bSPeter Grehan 632*10b59a9bSPeter Grehan vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_NOTIFY, queue); 633*10b59a9bSPeter Grehan } 634*10b59a9bSPeter Grehan 635*10b59a9bSPeter Grehan static uint8_t 636*10b59a9bSPeter Grehan vtpci_get_status(device_t dev) 637*10b59a9bSPeter Grehan { 638*10b59a9bSPeter Grehan struct vtpci_softc *sc; 639*10b59a9bSPeter Grehan 640*10b59a9bSPeter Grehan sc = device_get_softc(dev); 641*10b59a9bSPeter Grehan 642*10b59a9bSPeter Grehan return (vtpci_read_config_1(sc, VIRTIO_PCI_STATUS)); 643*10b59a9bSPeter Grehan } 644*10b59a9bSPeter Grehan 645*10b59a9bSPeter Grehan static void 646*10b59a9bSPeter Grehan vtpci_set_status(device_t dev, uint8_t status) 647*10b59a9bSPeter Grehan { 648*10b59a9bSPeter Grehan struct vtpci_softc *sc; 649*10b59a9bSPeter Grehan 650*10b59a9bSPeter Grehan sc = device_get_softc(dev); 651*10b59a9bSPeter Grehan 652*10b59a9bSPeter Grehan if (status != VIRTIO_CONFIG_STATUS_RESET) 653*10b59a9bSPeter Grehan status |= vtpci_get_status(dev); 654*10b59a9bSPeter Grehan 655*10b59a9bSPeter Grehan vtpci_write_config_1(sc, VIRTIO_PCI_STATUS, status); 656*10b59a9bSPeter Grehan } 657*10b59a9bSPeter Grehan 658*10b59a9bSPeter Grehan static void 659*10b59a9bSPeter Grehan vtpci_read_dev_config(device_t dev, bus_size_t offset, 660*10b59a9bSPeter Grehan void *dst, int length) 661*10b59a9bSPeter Grehan { 662*10b59a9bSPeter Grehan struct vtpci_softc *sc; 663*10b59a9bSPeter Grehan bus_size_t off; 664*10b59a9bSPeter Grehan uint8_t *d; 665*10b59a9bSPeter Grehan int size; 666*10b59a9bSPeter Grehan 667*10b59a9bSPeter Grehan sc = device_get_softc(dev); 668*10b59a9bSPeter Grehan off = VIRTIO_PCI_CONFIG(sc) + offset; 669*10b59a9bSPeter Grehan 670*10b59a9bSPeter Grehan for (d = dst; length > 0; d += size, off += size, length -= size) { 671*10b59a9bSPeter Grehan if (length >= 4) { 672*10b59a9bSPeter Grehan size = 4; 673*10b59a9bSPeter Grehan *(uint32_t *)d = vtpci_read_config_4(sc, off); 674*10b59a9bSPeter Grehan } else if (length >= 2) { 675*10b59a9bSPeter Grehan size = 2; 676*10b59a9bSPeter Grehan *(uint16_t *)d = vtpci_read_config_2(sc, off); 677*10b59a9bSPeter Grehan } else { 678*10b59a9bSPeter Grehan size = 1; 679*10b59a9bSPeter Grehan *d = vtpci_read_config_1(sc, off); 680*10b59a9bSPeter Grehan } 681*10b59a9bSPeter Grehan } 682*10b59a9bSPeter Grehan } 683*10b59a9bSPeter Grehan 684*10b59a9bSPeter Grehan static void 685*10b59a9bSPeter Grehan vtpci_write_dev_config(device_t dev, bus_size_t offset, 686*10b59a9bSPeter Grehan void *src, int length) 687*10b59a9bSPeter Grehan { 688*10b59a9bSPeter Grehan struct vtpci_softc *sc; 689*10b59a9bSPeter Grehan bus_size_t off; 690*10b59a9bSPeter Grehan uint8_t *s; 691*10b59a9bSPeter Grehan int size; 692*10b59a9bSPeter Grehan 693*10b59a9bSPeter Grehan sc = device_get_softc(dev); 694*10b59a9bSPeter Grehan off = VIRTIO_PCI_CONFIG(sc) + offset; 695*10b59a9bSPeter Grehan 696*10b59a9bSPeter Grehan for (s = src; length > 0; s += size, off += size, length -= size) { 697*10b59a9bSPeter Grehan if (length >= 4) { 698*10b59a9bSPeter Grehan size = 4; 699*10b59a9bSPeter Grehan vtpci_write_config_4(sc, off, *(uint32_t *)s); 700*10b59a9bSPeter Grehan } else if (length >= 2) { 701*10b59a9bSPeter Grehan size = 2; 702*10b59a9bSPeter Grehan vtpci_write_config_2(sc, off, *(uint16_t *)s); 703*10b59a9bSPeter Grehan } else { 704*10b59a9bSPeter Grehan size = 1; 705*10b59a9bSPeter Grehan vtpci_write_config_1(sc, off, *s); 706*10b59a9bSPeter Grehan } 707*10b59a9bSPeter Grehan } 708*10b59a9bSPeter Grehan } 709*10b59a9bSPeter Grehan 710*10b59a9bSPeter Grehan static void 711*10b59a9bSPeter Grehan vtpci_describe_features(struct vtpci_softc *sc, const char *msg, 712*10b59a9bSPeter Grehan uint64_t features) 713*10b59a9bSPeter Grehan { 714*10b59a9bSPeter Grehan device_t dev, child; 715*10b59a9bSPeter Grehan 716*10b59a9bSPeter Grehan dev = sc->vtpci_dev; 717*10b59a9bSPeter Grehan child = sc->vtpci_child_dev; 718*10b59a9bSPeter Grehan 719*10b59a9bSPeter Grehan if (device_is_attached(child) && bootverbose == 0) 720*10b59a9bSPeter Grehan return; 721*10b59a9bSPeter Grehan 722*10b59a9bSPeter Grehan virtio_describe(dev, msg, features, sc->vtpci_child_feat_desc); 723*10b59a9bSPeter Grehan } 724*10b59a9bSPeter Grehan 725*10b59a9bSPeter Grehan static void 726*10b59a9bSPeter Grehan vtpci_probe_and_attach_child(struct vtpci_softc *sc) 727*10b59a9bSPeter Grehan { 728*10b59a9bSPeter Grehan device_t dev, child; 729*10b59a9bSPeter Grehan 730*10b59a9bSPeter Grehan dev = sc->vtpci_dev; 731*10b59a9bSPeter Grehan child = sc->vtpci_child_dev; 732*10b59a9bSPeter Grehan 733*10b59a9bSPeter Grehan if (child == NULL) 734*10b59a9bSPeter Grehan return; 735*10b59a9bSPeter Grehan 736*10b59a9bSPeter Grehan if (device_get_state(child) != DS_NOTPRESENT) 737*10b59a9bSPeter Grehan return; 738*10b59a9bSPeter Grehan 739*10b59a9bSPeter Grehan if (device_probe(child) != 0) 740*10b59a9bSPeter Grehan return; 741*10b59a9bSPeter Grehan 742*10b59a9bSPeter Grehan vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER); 743*10b59a9bSPeter Grehan if (device_attach(child) != 0) { 744*10b59a9bSPeter Grehan vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED); 745*10b59a9bSPeter Grehan vtpci_reset(sc); 746*10b59a9bSPeter Grehan vtpci_release_child_resources(sc); 747*10b59a9bSPeter Grehan 748*10b59a9bSPeter Grehan /* Reset status for future attempt. */ 749*10b59a9bSPeter Grehan vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); 750*10b59a9bSPeter Grehan } else 751*10b59a9bSPeter Grehan vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER_OK); 752*10b59a9bSPeter Grehan } 753*10b59a9bSPeter Grehan 754*10b59a9bSPeter Grehan static int 755*10b59a9bSPeter Grehan vtpci_alloc_interrupts(struct vtpci_softc *sc, int flags, int nvqs, 756*10b59a9bSPeter Grehan struct vq_alloc_info *vq_info) 757*10b59a9bSPeter Grehan { 758*10b59a9bSPeter Grehan int i, nvectors, error; 759*10b59a9bSPeter Grehan 760*10b59a9bSPeter Grehan /* 761*10b59a9bSPeter Grehan * Only allocate a vector for virtqueues that are actually 762*10b59a9bSPeter Grehan * expecting an interrupt. 763*10b59a9bSPeter Grehan */ 764*10b59a9bSPeter Grehan for (nvectors = 0, i = 0; i < nvqs; i++) 765*10b59a9bSPeter Grehan if (vq_info[i].vqai_intr != NULL) 766*10b59a9bSPeter Grehan nvectors++; 767*10b59a9bSPeter Grehan 768*10b59a9bSPeter Grehan if (vtpci_disable_msix != 0 || 769*10b59a9bSPeter Grehan sc->vtpci_flags & VIRTIO_PCI_FLAG_NO_MSIX || 770*10b59a9bSPeter Grehan flags & VIRTIO_ALLOC_VQS_DISABLE_MSIX || 771*10b59a9bSPeter Grehan vtpci_alloc_msix(sc, nvectors) != 0) { 772*10b59a9bSPeter Grehan /* 773*10b59a9bSPeter Grehan * Use MSI interrupts if available. Otherwise, we fallback 774*10b59a9bSPeter Grehan * to legacy interrupts. 775*10b59a9bSPeter Grehan */ 776*10b59a9bSPeter Grehan if ((sc->vtpci_flags & VIRTIO_PCI_FLAG_NO_MSI) == 0 && 777*10b59a9bSPeter Grehan vtpci_alloc_msi(sc) == 0) 778*10b59a9bSPeter Grehan sc->vtpci_flags |= VIRTIO_PCI_FLAG_MSI; 779*10b59a9bSPeter Grehan 780*10b59a9bSPeter Grehan sc->vtpci_nintr_res = 1; 781*10b59a9bSPeter Grehan } 782*10b59a9bSPeter Grehan 783*10b59a9bSPeter Grehan error = vtpci_alloc_intr_resources(sc, nvqs, vq_info); 784*10b59a9bSPeter Grehan 785*10b59a9bSPeter Grehan return (error); 786*10b59a9bSPeter Grehan } 787*10b59a9bSPeter Grehan 788*10b59a9bSPeter Grehan static int 789*10b59a9bSPeter Grehan vtpci_alloc_intr_resources(struct vtpci_softc *sc, int nvqs, 790*10b59a9bSPeter Grehan struct vq_alloc_info *vq_info) 791*10b59a9bSPeter Grehan { 792*10b59a9bSPeter Grehan device_t dev; 793*10b59a9bSPeter Grehan struct resource *irq; 794*10b59a9bSPeter Grehan struct vtpci_virtqueue *vqx; 795*10b59a9bSPeter Grehan int i, rid, flags, res_idx; 796*10b59a9bSPeter Grehan 797*10b59a9bSPeter Grehan dev = sc->vtpci_dev; 798*10b59a9bSPeter Grehan flags = RF_ACTIVE; 799*10b59a9bSPeter Grehan 800*10b59a9bSPeter Grehan if ((sc->vtpci_flags & 801*10b59a9bSPeter Grehan (VIRTIO_PCI_FLAG_MSI | VIRTIO_PCI_FLAG_MSIX)) == 0) { 802*10b59a9bSPeter Grehan rid = 0; 803*10b59a9bSPeter Grehan flags |= RF_SHAREABLE; 804*10b59a9bSPeter Grehan } else 805*10b59a9bSPeter Grehan rid = 1; 806*10b59a9bSPeter Grehan 807*10b59a9bSPeter Grehan for (i = 0; i < sc->vtpci_nintr_res; i++) { 808*10b59a9bSPeter Grehan irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, flags); 809*10b59a9bSPeter Grehan if (irq == NULL) 810*10b59a9bSPeter Grehan return (ENXIO); 811*10b59a9bSPeter Grehan 812*10b59a9bSPeter Grehan sc->vtpci_intr_res[i].irq = irq; 813*10b59a9bSPeter Grehan sc->vtpci_intr_res[i].rid = rid++; 814*10b59a9bSPeter Grehan } 815*10b59a9bSPeter Grehan 816*10b59a9bSPeter Grehan /* 817*10b59a9bSPeter Grehan * Map the virtqueue into the correct index in vq_intr_res[]. Note the 818*10b59a9bSPeter Grehan * first index is reserved for configuration changes notifications. 819*10b59a9bSPeter Grehan */ 820*10b59a9bSPeter Grehan for (i = 0, res_idx = 1; i < nvqs; i++) { 821*10b59a9bSPeter Grehan vqx = &sc->vtpci_vqx[i]; 822*10b59a9bSPeter Grehan 823*10b59a9bSPeter Grehan if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 824*10b59a9bSPeter Grehan if (vq_info[i].vqai_intr == NULL) 825*10b59a9bSPeter Grehan vqx->ires_idx = -1; 826*10b59a9bSPeter Grehan else if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX) 827*10b59a9bSPeter Grehan vqx->ires_idx = res_idx; 828*10b59a9bSPeter Grehan else 829*10b59a9bSPeter Grehan vqx->ires_idx = res_idx++; 830*10b59a9bSPeter Grehan } else 831*10b59a9bSPeter Grehan vqx->ires_idx = -1; 832*10b59a9bSPeter Grehan } 833*10b59a9bSPeter Grehan 834*10b59a9bSPeter Grehan return (0); 835*10b59a9bSPeter Grehan } 836*10b59a9bSPeter Grehan 837*10b59a9bSPeter Grehan static int 838*10b59a9bSPeter Grehan vtpci_alloc_msi(struct vtpci_softc *sc) 839*10b59a9bSPeter Grehan { 840*10b59a9bSPeter Grehan device_t dev; 841*10b59a9bSPeter Grehan int nmsi, cnt; 842*10b59a9bSPeter Grehan 843*10b59a9bSPeter Grehan dev = sc->vtpci_dev; 844*10b59a9bSPeter Grehan nmsi = pci_msi_count(dev); 845*10b59a9bSPeter Grehan 846*10b59a9bSPeter Grehan if (nmsi < 1) 847*10b59a9bSPeter Grehan return (1); 848*10b59a9bSPeter Grehan 849*10b59a9bSPeter Grehan cnt = 1; 850*10b59a9bSPeter Grehan if (pci_alloc_msi(dev, &cnt) == 0 && cnt == 1) 851*10b59a9bSPeter Grehan return (0); 852*10b59a9bSPeter Grehan 853*10b59a9bSPeter Grehan return (1); 854*10b59a9bSPeter Grehan } 855*10b59a9bSPeter Grehan 856*10b59a9bSPeter Grehan static int 857*10b59a9bSPeter Grehan vtpci_alloc_msix(struct vtpci_softc *sc, int nvectors) 858*10b59a9bSPeter Grehan { 859*10b59a9bSPeter Grehan device_t dev; 860*10b59a9bSPeter Grehan int nmsix, cnt, required; 861*10b59a9bSPeter Grehan 862*10b59a9bSPeter Grehan dev = sc->vtpci_dev; 863*10b59a9bSPeter Grehan 864*10b59a9bSPeter Grehan nmsix = pci_msix_count(dev); 865*10b59a9bSPeter Grehan if (nmsix < 1) 866*10b59a9bSPeter Grehan return (1); 867*10b59a9bSPeter Grehan 868*10b59a9bSPeter Grehan /* An additional vector is needed for the config changes. */ 869*10b59a9bSPeter Grehan required = nvectors + 1; 870*10b59a9bSPeter Grehan if (nmsix >= required) { 871*10b59a9bSPeter Grehan cnt = required; 872*10b59a9bSPeter Grehan if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) 873*10b59a9bSPeter Grehan goto out; 874*10b59a9bSPeter Grehan 875*10b59a9bSPeter Grehan pci_release_msi(dev); 876*10b59a9bSPeter Grehan } 877*10b59a9bSPeter Grehan 878*10b59a9bSPeter Grehan /* Attempt shared MSIX configuration. */ 879*10b59a9bSPeter Grehan required = 2; 880*10b59a9bSPeter Grehan if (nmsix >= required) { 881*10b59a9bSPeter Grehan cnt = required; 882*10b59a9bSPeter Grehan if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) { 883*10b59a9bSPeter Grehan sc->vtpci_flags |= VIRTIO_PCI_FLAG_SHARED_MSIX; 884*10b59a9bSPeter Grehan goto out; 885*10b59a9bSPeter Grehan } 886*10b59a9bSPeter Grehan 887*10b59a9bSPeter Grehan pci_release_msi(dev); 888*10b59a9bSPeter Grehan } 889*10b59a9bSPeter Grehan 890*10b59a9bSPeter Grehan return (1); 891*10b59a9bSPeter Grehan 892*10b59a9bSPeter Grehan out: 893*10b59a9bSPeter Grehan sc->vtpci_nintr_res = required; 894*10b59a9bSPeter Grehan sc->vtpci_flags |= VIRTIO_PCI_FLAG_MSIX; 895*10b59a9bSPeter Grehan 896*10b59a9bSPeter Grehan if (bootverbose) { 897*10b59a9bSPeter Grehan if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX) 898*10b59a9bSPeter Grehan device_printf(dev, "using shared virtqueue MSIX\n"); 899*10b59a9bSPeter Grehan else 900*10b59a9bSPeter Grehan device_printf(dev, "using per virtqueue MSIX\n"); 901*10b59a9bSPeter Grehan } 902*10b59a9bSPeter Grehan 903*10b59a9bSPeter Grehan return (0); 904*10b59a9bSPeter Grehan } 905*10b59a9bSPeter Grehan 906*10b59a9bSPeter Grehan static int 907*10b59a9bSPeter Grehan vtpci_register_msix_vector(struct vtpci_softc *sc, int offset, int res_idx) 908*10b59a9bSPeter Grehan { 909*10b59a9bSPeter Grehan device_t dev; 910*10b59a9bSPeter Grehan uint16_t vector; 911*10b59a9bSPeter Grehan 912*10b59a9bSPeter Grehan dev = sc->vtpci_dev; 913*10b59a9bSPeter Grehan 914*10b59a9bSPeter Grehan if (offset != VIRTIO_MSI_CONFIG_VECTOR && 915*10b59a9bSPeter Grehan offset != VIRTIO_MSI_QUEUE_VECTOR) 916*10b59a9bSPeter Grehan return (EINVAL); 917*10b59a9bSPeter Grehan 918*10b59a9bSPeter Grehan if (res_idx != -1) { 919*10b59a9bSPeter Grehan /* Map from rid to host vector. */ 920*10b59a9bSPeter Grehan vector = sc->vtpci_intr_res[res_idx].rid - 1; 921*10b59a9bSPeter Grehan } else 922*10b59a9bSPeter Grehan vector = VIRTIO_MSI_NO_VECTOR; 923*10b59a9bSPeter Grehan 924*10b59a9bSPeter Grehan /* The first resource is special; make sure it is used correctly. */ 925*10b59a9bSPeter Grehan if (res_idx == 0) { 926*10b59a9bSPeter Grehan KASSERT(vector == 0, ("unexpected config vector")); 927*10b59a9bSPeter Grehan KASSERT(offset == VIRTIO_MSI_CONFIG_VECTOR, 928*10b59a9bSPeter Grehan ("unexpected config offset")); 929*10b59a9bSPeter Grehan } 930*10b59a9bSPeter Grehan 931*10b59a9bSPeter Grehan vtpci_write_config_2(sc, offset, vector); 932*10b59a9bSPeter Grehan 933*10b59a9bSPeter Grehan if (vtpci_read_config_2(sc, offset) != vector) { 934*10b59a9bSPeter Grehan device_printf(dev, "insufficient host resources for " 935*10b59a9bSPeter Grehan "MSIX interrupts\n"); 936*10b59a9bSPeter Grehan return (ENODEV); 937*10b59a9bSPeter Grehan } 938*10b59a9bSPeter Grehan 939*10b59a9bSPeter Grehan return (0); 940*10b59a9bSPeter Grehan } 941*10b59a9bSPeter Grehan 942*10b59a9bSPeter Grehan static void 943*10b59a9bSPeter Grehan vtpci_free_interrupts(struct vtpci_softc *sc) 944*10b59a9bSPeter Grehan { 945*10b59a9bSPeter Grehan device_t dev; 946*10b59a9bSPeter Grehan struct vtpci_intr_resource *ires; 947*10b59a9bSPeter Grehan int i; 948*10b59a9bSPeter Grehan 949*10b59a9bSPeter Grehan dev = sc->vtpci_dev; 950*10b59a9bSPeter Grehan sc->vtpci_nintr_res = 0; 951*10b59a9bSPeter Grehan 952*10b59a9bSPeter Grehan if (sc->vtpci_flags & (VIRTIO_PCI_FLAG_MSI | VIRTIO_PCI_FLAG_MSIX)) { 953*10b59a9bSPeter Grehan pci_release_msi(dev); 954*10b59a9bSPeter Grehan sc->vtpci_flags &= ~(VIRTIO_PCI_FLAG_MSI | 955*10b59a9bSPeter Grehan VIRTIO_PCI_FLAG_MSIX | VIRTIO_PCI_FLAG_SHARED_MSIX); 956*10b59a9bSPeter Grehan } 957*10b59a9bSPeter Grehan 958*10b59a9bSPeter Grehan for (i = 0; i < 1 + VIRTIO_MAX_VIRTQUEUES; i++) { 959*10b59a9bSPeter Grehan ires = &sc->vtpci_intr_res[i]; 960*10b59a9bSPeter Grehan 961*10b59a9bSPeter Grehan if (ires->intrhand != NULL) { 962*10b59a9bSPeter Grehan bus_teardown_intr(dev, ires->irq, ires->intrhand); 963*10b59a9bSPeter Grehan ires->intrhand = NULL; 964*10b59a9bSPeter Grehan } 965*10b59a9bSPeter Grehan 966*10b59a9bSPeter Grehan if (ires->irq != NULL) { 967*10b59a9bSPeter Grehan bus_release_resource(dev, SYS_RES_IRQ, ires->rid, 968*10b59a9bSPeter Grehan ires->irq); 969*10b59a9bSPeter Grehan ires->irq = NULL; 970*10b59a9bSPeter Grehan } 971*10b59a9bSPeter Grehan 972*10b59a9bSPeter Grehan ires->rid = -1; 973*10b59a9bSPeter Grehan } 974*10b59a9bSPeter Grehan } 975*10b59a9bSPeter Grehan 976*10b59a9bSPeter Grehan static void 977*10b59a9bSPeter Grehan vtpci_free_virtqueues(struct vtpci_softc *sc) 978*10b59a9bSPeter Grehan { 979*10b59a9bSPeter Grehan struct vtpci_virtqueue *vqx; 980*10b59a9bSPeter Grehan int i; 981*10b59a9bSPeter Grehan 982*10b59a9bSPeter Grehan sc->vtpci_nvqs = 0; 983*10b59a9bSPeter Grehan 984*10b59a9bSPeter Grehan for (i = 0; i < VIRTIO_MAX_VIRTQUEUES; i++) { 985*10b59a9bSPeter Grehan vqx = &sc->vtpci_vqx[i]; 986*10b59a9bSPeter Grehan 987*10b59a9bSPeter Grehan if (vqx->vq != NULL) { 988*10b59a9bSPeter Grehan virtqueue_free(vqx->vq); 989*10b59a9bSPeter Grehan vqx->vq = NULL; 990*10b59a9bSPeter Grehan } 991*10b59a9bSPeter Grehan } 992*10b59a9bSPeter Grehan } 993*10b59a9bSPeter Grehan 994*10b59a9bSPeter Grehan static void 995*10b59a9bSPeter Grehan vtpci_release_child_resources(struct vtpci_softc *sc) 996*10b59a9bSPeter Grehan { 997*10b59a9bSPeter Grehan 998*10b59a9bSPeter Grehan vtpci_free_interrupts(sc); 999*10b59a9bSPeter Grehan vtpci_free_virtqueues(sc); 1000*10b59a9bSPeter Grehan } 1001*10b59a9bSPeter Grehan 1002*10b59a9bSPeter Grehan static void 1003*10b59a9bSPeter Grehan vtpci_reset(struct vtpci_softc *sc) 1004*10b59a9bSPeter Grehan { 1005*10b59a9bSPeter Grehan 1006*10b59a9bSPeter Grehan /* 1007*10b59a9bSPeter Grehan * Setting the status to RESET sets the host device to 1008*10b59a9bSPeter Grehan * the original, uninitialized state. 1009*10b59a9bSPeter Grehan */ 1010*10b59a9bSPeter Grehan vtpci_set_status(sc->vtpci_dev, VIRTIO_CONFIG_STATUS_RESET); 1011*10b59a9bSPeter Grehan } 1012*10b59a9bSPeter Grehan 1013*10b59a9bSPeter Grehan static int 1014*10b59a9bSPeter Grehan vtpci_legacy_intr(void *xsc) 1015*10b59a9bSPeter Grehan { 1016*10b59a9bSPeter Grehan struct vtpci_softc *sc; 1017*10b59a9bSPeter Grehan struct vtpci_virtqueue *vqx; 1018*10b59a9bSPeter Grehan int i; 1019*10b59a9bSPeter Grehan uint8_t isr; 1020*10b59a9bSPeter Grehan 1021*10b59a9bSPeter Grehan sc = xsc; 1022*10b59a9bSPeter Grehan vqx = &sc->vtpci_vqx[0]; 1023*10b59a9bSPeter Grehan 1024*10b59a9bSPeter Grehan /* Reading the ISR also clears it. */ 1025*10b59a9bSPeter Grehan isr = vtpci_read_config_1(sc, VIRTIO_PCI_ISR); 1026*10b59a9bSPeter Grehan 1027*10b59a9bSPeter Grehan if (isr & VIRTIO_PCI_ISR_CONFIG) 1028*10b59a9bSPeter Grehan vtpci_config_intr(sc); 1029*10b59a9bSPeter Grehan 1030*10b59a9bSPeter Grehan if (isr & VIRTIO_PCI_ISR_INTR) 1031*10b59a9bSPeter Grehan for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) 1032*10b59a9bSPeter Grehan virtqueue_intr(vqx->vq); 1033*10b59a9bSPeter Grehan 1034*10b59a9bSPeter Grehan return (isr ? FILTER_HANDLED : FILTER_STRAY); 1035*10b59a9bSPeter Grehan } 1036*10b59a9bSPeter Grehan 1037*10b59a9bSPeter Grehan static int 1038*10b59a9bSPeter Grehan vtpci_vq_shared_intr(void *xsc) 1039*10b59a9bSPeter Grehan { 1040*10b59a9bSPeter Grehan struct vtpci_softc *sc; 1041*10b59a9bSPeter Grehan struct vtpci_virtqueue *vqx; 1042*10b59a9bSPeter Grehan int i, rc; 1043*10b59a9bSPeter Grehan 1044*10b59a9bSPeter Grehan rc = 0; 1045*10b59a9bSPeter Grehan sc = xsc; 1046*10b59a9bSPeter Grehan vqx = &sc->vtpci_vqx[0]; 1047*10b59a9bSPeter Grehan 1048*10b59a9bSPeter Grehan for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) 1049*10b59a9bSPeter Grehan rc |= virtqueue_intr(vqx->vq); 1050*10b59a9bSPeter Grehan 1051*10b59a9bSPeter Grehan return (rc ? FILTER_HANDLED : FILTER_STRAY); 1052*10b59a9bSPeter Grehan } 1053*10b59a9bSPeter Grehan 1054*10b59a9bSPeter Grehan static int 1055*10b59a9bSPeter Grehan vtpci_vq_intr(void *xvq) 1056*10b59a9bSPeter Grehan { 1057*10b59a9bSPeter Grehan struct virtqueue *vq; 1058*10b59a9bSPeter Grehan int rc; 1059*10b59a9bSPeter Grehan 1060*10b59a9bSPeter Grehan vq = xvq; 1061*10b59a9bSPeter Grehan rc = virtqueue_intr(vq); 1062*10b59a9bSPeter Grehan 1063*10b59a9bSPeter Grehan return (rc ? FILTER_HANDLED : FILTER_STRAY); 1064*10b59a9bSPeter Grehan } 1065*10b59a9bSPeter Grehan 1066*10b59a9bSPeter Grehan static int 1067*10b59a9bSPeter Grehan vtpci_config_intr(void *xsc) 1068*10b59a9bSPeter Grehan { 1069*10b59a9bSPeter Grehan struct vtpci_softc *sc; 1070*10b59a9bSPeter Grehan device_t child; 1071*10b59a9bSPeter Grehan int rc; 1072*10b59a9bSPeter Grehan 1073*10b59a9bSPeter Grehan rc = 0; 1074*10b59a9bSPeter Grehan sc = xsc; 1075*10b59a9bSPeter Grehan child = sc->vtpci_child_dev; 1076*10b59a9bSPeter Grehan 1077*10b59a9bSPeter Grehan if (child != NULL) 1078*10b59a9bSPeter Grehan rc = VIRTIO_CONFIG_CHANGE(child); 1079*10b59a9bSPeter Grehan 1080*10b59a9bSPeter Grehan return (rc ? FILTER_HANDLED : FILTER_STRAY); 1081*10b59a9bSPeter Grehan } 1082