1f2521a76SDoug Ambrisko /*- 2f2521a76SDoug Ambrisko * SPDX-License-Identifier: BSD-2-Clause 3f2521a76SDoug Ambrisko * 4f2521a76SDoug Ambrisko * Copyright 2019 Cisco Systems, Inc. 5f2521a76SDoug Ambrisko * All rights reserved. 6f2521a76SDoug Ambrisko * 7f2521a76SDoug Ambrisko * Redistribution and use in source and binary forms, with or without 8f2521a76SDoug Ambrisko * modification, are permitted provided that the following conditions 9f2521a76SDoug Ambrisko * are met: 10f2521a76SDoug Ambrisko * 1. Redistributions of source code must retain the above copyright 11f2521a76SDoug Ambrisko * notice, this list of conditions and the following disclaimer. 12f2521a76SDoug Ambrisko * 2. Redistributions in binary form must reproduce the above copyright 13f2521a76SDoug Ambrisko * notice, this list of conditions and the following disclaimer in the 14f2521a76SDoug Ambrisko * documentation and/or other materials provided with the distribution. 15f2521a76SDoug Ambrisko * 16f2521a76SDoug Ambrisko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17f2521a76SDoug Ambrisko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18f2521a76SDoug Ambrisko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19f2521a76SDoug Ambrisko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20f2521a76SDoug Ambrisko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21f2521a76SDoug Ambrisko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22f2521a76SDoug Ambrisko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23f2521a76SDoug Ambrisko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24f2521a76SDoug Ambrisko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25f2521a76SDoug Ambrisko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26f2521a76SDoug Ambrisko * SUCH DAMAGE. 27f2521a76SDoug Ambrisko */ 28f2521a76SDoug Ambrisko 29f2521a76SDoug Ambrisko #include <sys/cdefs.h> 30f2521a76SDoug Ambrisko __FBSDID("$FreeBSD$"); 31f2521a76SDoug Ambrisko 32f2521a76SDoug Ambrisko #include <sys/types.h> 33f2521a76SDoug Ambrisko #include <sys/param.h> 34f2521a76SDoug Ambrisko #include <sys/bus.h> 35f2521a76SDoug Ambrisko #include <sys/conf.h> 36f2521a76SDoug Ambrisko #include <sys/kernel.h> 37f2521a76SDoug Ambrisko #include <sys/module.h> 38f2521a76SDoug Ambrisko #include <sys/systm.h> 39f2521a76SDoug Ambrisko #include <sys/malloc.h> 40f2521a76SDoug Ambrisko 41f2521a76SDoug Ambrisko #include <machine/bus.h> 42f2521a76SDoug Ambrisko #include <machine/resource.h> 43f2521a76SDoug Ambrisko #include <sys/rman.h> 44f2521a76SDoug Ambrisko #include <sys/lock.h> 45f2521a76SDoug Ambrisko #include <sys/mutex.h> 46f2521a76SDoug Ambrisko #include <sys/taskqueue.h> 47f2521a76SDoug Ambrisko 48f2521a76SDoug Ambrisko #include <sys/pciio.h> 49f2521a76SDoug Ambrisko #include <dev/pci/pcivar.h> 50f2521a76SDoug Ambrisko #include <dev/pci/pcireg.h> 51f2521a76SDoug Ambrisko #include <dev/pci/pci_private.h> 52f2521a76SDoug Ambrisko #include <dev/pci/pcib_private.h> 53f2521a76SDoug Ambrisko 54f2521a76SDoug Ambrisko #define TASK_QUEUE_INTR 1 55f2521a76SDoug Ambrisko #include <dev/vmd/vmd.h> 56f2521a76SDoug Ambrisko 57f2521a76SDoug Ambrisko #include "pcib_if.h" 58f2521a76SDoug Ambrisko #include "pci_if.h" 59f2521a76SDoug Ambrisko 60f2521a76SDoug Ambrisko struct vmd_type { 61f2521a76SDoug Ambrisko u_int16_t vmd_vid; 62f2521a76SDoug Ambrisko u_int16_t vmd_did; 63f2521a76SDoug Ambrisko char *vmd_name; 64*0c852bb9SDoug Ambrisko int flags; 65*0c852bb9SDoug Ambrisko #define BUS_RESTRICT 1 66f2521a76SDoug Ambrisko }; 67f2521a76SDoug Ambrisko 68f2521a76SDoug Ambrisko #define INTEL_VENDOR_ID 0x8086 69*0c852bb9SDoug Ambrisko #define INTEL_DEVICE_ID_201d 0x201d 70*0c852bb9SDoug Ambrisko #define INTEL_DEVICE_ID_28c0 0x28c0 71*0c852bb9SDoug Ambrisko #define INTEL_DEVICE_ID_467f 0x467f 72*0c852bb9SDoug Ambrisko #define INTEL_DEVICE_ID_4c3d 0x4c3d 73*0c852bb9SDoug Ambrisko #define INTEL_DEVICE_ID_9a0b 0x9a0b 74*0c852bb9SDoug Ambrisko 75*0c852bb9SDoug Ambrisko #define VMD_CAP 0x40 76*0c852bb9SDoug Ambrisko #define VMD_BUS_RESTRICT 0x1 77*0c852bb9SDoug Ambrisko 78*0c852bb9SDoug Ambrisko #define VMD_CONFIG 0x44 79*0c852bb9SDoug Ambrisko #define VMD_BUS_START(x) ((x >> 8) & 0x3) 80*0c852bb9SDoug Ambrisko 81*0c852bb9SDoug Ambrisko #define VMD_LOCK 0x70 82f2521a76SDoug Ambrisko 83f2521a76SDoug Ambrisko static struct vmd_type vmd_devs[] = { 84*0c852bb9SDoug Ambrisko { INTEL_VENDOR_ID, INTEL_DEVICE_ID_201d, "Intel Volume Management Device", 0 }, 85*0c852bb9SDoug Ambrisko { INTEL_VENDOR_ID, INTEL_DEVICE_ID_28c0, "Intel Volume Management Device", BUS_RESTRICT }, 86*0c852bb9SDoug Ambrisko { INTEL_VENDOR_ID, INTEL_DEVICE_ID_467f, "Intel Volume Management Device", BUS_RESTRICT }, 87*0c852bb9SDoug Ambrisko { INTEL_VENDOR_ID, INTEL_DEVICE_ID_4c3d, "Intel Volume Management Device", BUS_RESTRICT }, 88*0c852bb9SDoug Ambrisko { INTEL_VENDOR_ID, INTEL_DEVICE_ID_9a0b, "Intel Volume Management Device", BUS_RESTRICT }, 89*0c852bb9SDoug Ambrisko { 0, 0, NULL, 0 } 90f2521a76SDoug Ambrisko }; 91f2521a76SDoug Ambrisko 92f2521a76SDoug Ambrisko static int 93f2521a76SDoug Ambrisko vmd_probe(device_t dev) 94f2521a76SDoug Ambrisko { 95f2521a76SDoug Ambrisko struct vmd_type *t; 96f2521a76SDoug Ambrisko uint16_t vid, did; 97f2521a76SDoug Ambrisko 98f2521a76SDoug Ambrisko t = vmd_devs; 99f2521a76SDoug Ambrisko vid = pci_get_vendor(dev); 100f2521a76SDoug Ambrisko did = pci_get_device(dev); 101f2521a76SDoug Ambrisko 102f2521a76SDoug Ambrisko while (t->vmd_name != NULL) { 103f2521a76SDoug Ambrisko if (vid == t->vmd_vid && 104f2521a76SDoug Ambrisko did == t->vmd_did) { 105f2521a76SDoug Ambrisko device_set_desc(dev, t->vmd_name); 106f2521a76SDoug Ambrisko return (BUS_PROBE_DEFAULT); 107f2521a76SDoug Ambrisko } 108f2521a76SDoug Ambrisko t++; 109f2521a76SDoug Ambrisko } 110f2521a76SDoug Ambrisko 111f2521a76SDoug Ambrisko return (ENXIO); 112f2521a76SDoug Ambrisko } 113f2521a76SDoug Ambrisko 114f2521a76SDoug Ambrisko static void 115f2521a76SDoug Ambrisko vmd_free(struct vmd_softc *sc) 116f2521a76SDoug Ambrisko { 117f2521a76SDoug Ambrisko int i; 118f2521a76SDoug Ambrisko struct vmd_irq_handler *elm, *tmp; 119f2521a76SDoug Ambrisko 120e65e4e61SMark Johnston if (sc->vmd_bus.rman.rm_end != 0) 121e65e4e61SMark Johnston rman_fini(&sc->vmd_bus.rman); 122e65e4e61SMark Johnston 123f2521a76SDoug Ambrisko #ifdef TASK_QUEUE_INTR 124f2521a76SDoug Ambrisko if (sc->vmd_irq_tq != NULL) { 125f2521a76SDoug Ambrisko taskqueue_drain(sc->vmd_irq_tq, &sc->vmd_irq_task); 126f2521a76SDoug Ambrisko taskqueue_free(sc->vmd_irq_tq); 127f2521a76SDoug Ambrisko sc->vmd_irq_tq = NULL; 128f2521a76SDoug Ambrisko } 129f2521a76SDoug Ambrisko #endif 130f2521a76SDoug Ambrisko if (sc->vmd_irq != NULL) { 131f2521a76SDoug Ambrisko for (i = 0; i < sc->vmd_msix_count; i++) { 132f2521a76SDoug Ambrisko if (sc->vmd_irq[i].vmd_res != NULL) { 133f2521a76SDoug Ambrisko bus_teardown_intr(sc->vmd_dev, 134f2521a76SDoug Ambrisko sc->vmd_irq[i].vmd_res, 135f2521a76SDoug Ambrisko sc->vmd_irq[i].vmd_handle); 136f2521a76SDoug Ambrisko bus_release_resource(sc->vmd_dev, SYS_RES_IRQ, 137f2521a76SDoug Ambrisko sc->vmd_irq[i].vmd_rid, 138f2521a76SDoug Ambrisko sc->vmd_irq[i].vmd_res); 139f2521a76SDoug Ambrisko } 140f2521a76SDoug Ambrisko } 141f2521a76SDoug Ambrisko TAILQ_FOREACH_SAFE(elm, &sc->vmd_irq[0].vmd_list ,vmd_link, 142f2521a76SDoug Ambrisko tmp) { 143f2521a76SDoug Ambrisko TAILQ_REMOVE(&sc->vmd_irq[0].vmd_list, elm, vmd_link); 144f2521a76SDoug Ambrisko free(elm, M_DEVBUF); 145f2521a76SDoug Ambrisko } 146f2521a76SDoug Ambrisko } 147f2521a76SDoug Ambrisko free(sc->vmd_irq, M_DEVBUF); 148f2521a76SDoug Ambrisko sc->vmd_irq = NULL; 149f2521a76SDoug Ambrisko pci_release_msi(sc->vmd_dev); 150f2521a76SDoug Ambrisko for (i = 0; i < VMD_MAX_BAR; i++) { 151f2521a76SDoug Ambrisko if (sc->vmd_regs_resource[i] != NULL) 152f2521a76SDoug Ambrisko bus_release_resource(sc->vmd_dev, SYS_RES_MEMORY, 153f2521a76SDoug Ambrisko sc->vmd_regs_rid[i], 154f2521a76SDoug Ambrisko sc->vmd_regs_resource[i]); 155f2521a76SDoug Ambrisko } 156f2521a76SDoug Ambrisko if (sc->vmd_io_resource) 157f2521a76SDoug Ambrisko bus_release_resource(device_get_parent(sc->vmd_dev), 158f2521a76SDoug Ambrisko SYS_RES_IOPORT, sc->vmd_io_rid, sc->vmd_io_resource); 159f2521a76SDoug Ambrisko 160f2521a76SDoug Ambrisko #ifndef TASK_QUEUE_INTR 161f2521a76SDoug Ambrisko if (mtx_initialized(&sc->vmd_irq_lock)) { 162f2521a76SDoug Ambrisko mtx_destroy(&sc->vmd_irq_lock); 163f2521a76SDoug Ambrisko } 164f2521a76SDoug Ambrisko #endif 165f2521a76SDoug Ambrisko } 166f2521a76SDoug Ambrisko 167f2521a76SDoug Ambrisko /* Hidden PCI Roots are hidden in BAR(0). */ 168f2521a76SDoug Ambrisko 169f2521a76SDoug Ambrisko static uint32_t 170f2521a76SDoug Ambrisko vmd_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) 171f2521a76SDoug Ambrisko { 172f2521a76SDoug Ambrisko 173f2521a76SDoug Ambrisko struct vmd_softc *sc; 174f2521a76SDoug Ambrisko bus_addr_t offset; 175f2521a76SDoug Ambrisko 176f2521a76SDoug Ambrisko sc = device_get_softc(dev); 177*0c852bb9SDoug Ambrisko if (b < sc->vmd_bus_start) 178*0c852bb9SDoug Ambrisko return (0xffffffff); 179*0c852bb9SDoug Ambrisko 180*0c852bb9SDoug Ambrisko offset = ((b - sc->vmd_bus_start) << 20) + (s << 15) + (f << 12) + reg; 181*0c852bb9SDoug Ambrisko 182f2521a76SDoug Ambrisko switch(width) { 183f2521a76SDoug Ambrisko case 4: 184f2521a76SDoug Ambrisko return (bus_space_read_4(sc->vmd_btag, sc->vmd_bhandle, 185f2521a76SDoug Ambrisko offset)); 186f2521a76SDoug Ambrisko case 2: 187f2521a76SDoug Ambrisko return (bus_space_read_2(sc->vmd_btag, sc->vmd_bhandle, 188f2521a76SDoug Ambrisko offset)); 189f2521a76SDoug Ambrisko case 1: 190f2521a76SDoug Ambrisko return (bus_space_read_1(sc->vmd_btag, sc->vmd_bhandle, 191f2521a76SDoug Ambrisko offset)); 192f2521a76SDoug Ambrisko default: 193f2521a76SDoug Ambrisko KASSERT(1, ("Invalid width requested")); 194f2521a76SDoug Ambrisko return (0xffffffff); 195f2521a76SDoug Ambrisko } 196f2521a76SDoug Ambrisko } 197f2521a76SDoug Ambrisko 198f2521a76SDoug Ambrisko static void 199f2521a76SDoug Ambrisko vmd_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, 200f2521a76SDoug Ambrisko uint32_t val, int width) 201f2521a76SDoug Ambrisko { 202f2521a76SDoug Ambrisko 203f2521a76SDoug Ambrisko struct vmd_softc *sc; 204f2521a76SDoug Ambrisko bus_addr_t offset; 205f2521a76SDoug Ambrisko 206f2521a76SDoug Ambrisko sc = device_get_softc(dev); 207*0c852bb9SDoug Ambrisko if (b < sc->vmd_bus_start) 208*0c852bb9SDoug Ambrisko return; 209*0c852bb9SDoug Ambrisko 210*0c852bb9SDoug Ambrisko offset = ((b - sc->vmd_bus_start) << 20) + (s << 15) + (f << 12) + reg; 211f2521a76SDoug Ambrisko 212f2521a76SDoug Ambrisko switch(width) { 213f2521a76SDoug Ambrisko case 4: 214f2521a76SDoug Ambrisko return (bus_space_write_4(sc->vmd_btag, sc->vmd_bhandle, 215f2521a76SDoug Ambrisko offset, val)); 216f2521a76SDoug Ambrisko case 2: 217f2521a76SDoug Ambrisko return (bus_space_write_2(sc->vmd_btag, sc->vmd_bhandle, 218f2521a76SDoug Ambrisko offset, val)); 219f2521a76SDoug Ambrisko case 1: 220f2521a76SDoug Ambrisko return (bus_space_write_1(sc->vmd_btag, sc->vmd_bhandle, 221f2521a76SDoug Ambrisko offset, val)); 222f2521a76SDoug Ambrisko default: 223f2521a76SDoug Ambrisko panic("Failed to specific width"); 224f2521a76SDoug Ambrisko } 225f2521a76SDoug Ambrisko } 226f2521a76SDoug Ambrisko 227f2521a76SDoug Ambrisko static uint32_t 228f2521a76SDoug Ambrisko vmd_pci_read_config(device_t dev, device_t child, int reg, int width) 229f2521a76SDoug Ambrisko { 230f2521a76SDoug Ambrisko struct pci_devinfo *dinfo = device_get_ivars(child); 231f2521a76SDoug Ambrisko pcicfgregs *cfg = &dinfo->cfg; 232f2521a76SDoug Ambrisko 233f2521a76SDoug Ambrisko return vmd_read_config(dev, cfg->bus, cfg->slot, cfg->func, reg, width); 234f2521a76SDoug Ambrisko } 235f2521a76SDoug Ambrisko 236f2521a76SDoug Ambrisko static void 237f2521a76SDoug Ambrisko vmd_pci_write_config(device_t dev, device_t child, int reg, uint32_t val, 238f2521a76SDoug Ambrisko int width) 239f2521a76SDoug Ambrisko { 240f2521a76SDoug Ambrisko struct pci_devinfo *dinfo = device_get_ivars(child); 241f2521a76SDoug Ambrisko pcicfgregs *cfg = &dinfo->cfg; 242f2521a76SDoug Ambrisko 243f2521a76SDoug Ambrisko vmd_write_config(dev, cfg->bus, cfg->slot, cfg->func, reg, val, width); 244f2521a76SDoug Ambrisko } 245f2521a76SDoug Ambrisko 246f2521a76SDoug Ambrisko static struct pci_devinfo * 247f2521a76SDoug Ambrisko vmd_alloc_devinfo(device_t dev) 248f2521a76SDoug Ambrisko { 249f2521a76SDoug Ambrisko struct pci_devinfo *dinfo; 250f2521a76SDoug Ambrisko 251f2521a76SDoug Ambrisko dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); 252f2521a76SDoug Ambrisko return (dinfo); 253f2521a76SDoug Ambrisko } 254f2521a76SDoug Ambrisko 255f2521a76SDoug Ambrisko static void 256f2521a76SDoug Ambrisko vmd_intr(void *arg) 257f2521a76SDoug Ambrisko { 258f2521a76SDoug Ambrisko struct vmd_irq *irq; 259f2521a76SDoug Ambrisko struct vmd_softc *sc; 260f2521a76SDoug Ambrisko #ifndef TASK_QUEUE_INTR 261f2521a76SDoug Ambrisko struct vmd_irq_handler *elm, *tmp_elm; 262f2521a76SDoug Ambrisko #endif 263f2521a76SDoug Ambrisko 264f2521a76SDoug Ambrisko irq = (struct vmd_irq *)arg; 265f2521a76SDoug Ambrisko sc = irq->vmd_sc; 266f2521a76SDoug Ambrisko #ifdef TASK_QUEUE_INTR 267f2521a76SDoug Ambrisko taskqueue_enqueue(sc->vmd_irq_tq, &sc->vmd_irq_task); 268f2521a76SDoug Ambrisko #else 269f2521a76SDoug Ambrisko mtx_lock(&sc->vmd_irq_lock); 270f2521a76SDoug Ambrisko TAILQ_FOREACH_SAFE(elm, &sc->vmd_irq[0].vmd_list, vmd_link, tmp_elm) { 271f2521a76SDoug Ambrisko (elm->vmd_intr)(elm->vmd_arg); 272f2521a76SDoug Ambrisko } 273f2521a76SDoug Ambrisko mtx_unlock(&sc->vmd_irq_lock); 274f2521a76SDoug Ambrisko #endif 275f2521a76SDoug Ambrisko } 276f2521a76SDoug Ambrisko 277f2521a76SDoug Ambrisko #ifdef TASK_QUEUE_INTR 278f2521a76SDoug Ambrisko static void 279f2521a76SDoug Ambrisko vmd_handle_irq(void *context, int pending) 280f2521a76SDoug Ambrisko { 281f2521a76SDoug Ambrisko struct vmd_irq_handler *elm, *tmp_elm; 282f2521a76SDoug Ambrisko struct vmd_softc *sc; 283f2521a76SDoug Ambrisko 284f2521a76SDoug Ambrisko sc = context; 285f2521a76SDoug Ambrisko 286f2521a76SDoug Ambrisko TAILQ_FOREACH_SAFE(elm, &sc->vmd_irq[0].vmd_list, vmd_link, tmp_elm) { 287f2521a76SDoug Ambrisko (elm->vmd_intr)(elm->vmd_arg); 288f2521a76SDoug Ambrisko } 289f2521a76SDoug Ambrisko } 290f2521a76SDoug Ambrisko #endif 291f2521a76SDoug Ambrisko 292f2521a76SDoug Ambrisko static int 293f2521a76SDoug Ambrisko vmd_attach(device_t dev) 294f2521a76SDoug Ambrisko { 295f2521a76SDoug Ambrisko struct vmd_softc *sc; 296f2521a76SDoug Ambrisko struct pcib_secbus *bus; 297*0c852bb9SDoug Ambrisko struct vmd_type *t; 298*0c852bb9SDoug Ambrisko uint16_t vid, did; 299f2521a76SDoug Ambrisko uint32_t bar; 300f2521a76SDoug Ambrisko int i, j, error; 301f2521a76SDoug Ambrisko int rid, sec_reg; 302f2521a76SDoug Ambrisko static int b; 303f2521a76SDoug Ambrisko static int s; 304f2521a76SDoug Ambrisko static int f; 305f2521a76SDoug Ambrisko int min_count = 1; 306f2521a76SDoug Ambrisko char buf[64]; 307f2521a76SDoug Ambrisko 308f2521a76SDoug Ambrisko sc = device_get_softc(dev); 309f2521a76SDoug Ambrisko bzero(sc, sizeof(*sc)); 310f2521a76SDoug Ambrisko sc->vmd_dev = dev; 311f2521a76SDoug Ambrisko b = s = f = 0; 312f2521a76SDoug Ambrisko 313f2521a76SDoug Ambrisko pci_enable_busmaster(dev); 314f2521a76SDoug Ambrisko 315f2521a76SDoug Ambrisko #ifdef TASK_QUEUE_INTR 316f2521a76SDoug Ambrisko sc->vmd_irq_tq = taskqueue_create_fast("vmd_taskq", M_NOWAIT, 317f2521a76SDoug Ambrisko taskqueue_thread_enqueue, &sc->vmd_irq_tq); 318f2521a76SDoug Ambrisko taskqueue_start_threads(&sc->vmd_irq_tq, 1, PI_DISK, "%s taskq", 319f2521a76SDoug Ambrisko device_get_nameunit(sc->vmd_dev)); 320f2521a76SDoug Ambrisko TASK_INIT(&sc->vmd_irq_task, 0, vmd_handle_irq, sc); 321f2521a76SDoug Ambrisko #else 322f2521a76SDoug Ambrisko mtx_init(&sc->vmd_irq_lock, "VMD IRQ lock", NULL, MTX_DEF); 323f2521a76SDoug Ambrisko #endif 324f2521a76SDoug Ambrisko for (i = 0, j = 0; i < VMD_MAX_BAR; i++, j++ ) { 325f2521a76SDoug Ambrisko sc->vmd_regs_rid[i] = PCIR_BAR(j); 326f2521a76SDoug Ambrisko bar = pci_read_config(dev, PCIR_BAR(0), 4); 327f2521a76SDoug Ambrisko if (PCI_BAR_MEM(bar) && (bar & PCIM_BAR_MEM_TYPE) == 328f2521a76SDoug Ambrisko PCIM_BAR_MEM_64) 329f2521a76SDoug Ambrisko j++; 330f2521a76SDoug Ambrisko if ((sc->vmd_regs_resource[i] = bus_alloc_resource_any( 331f2521a76SDoug Ambrisko sc->vmd_dev, SYS_RES_MEMORY, &sc->vmd_regs_rid[i], 332f2521a76SDoug Ambrisko RF_ACTIVE)) == NULL) { 333f2521a76SDoug Ambrisko device_printf(dev, "Cannot allocate resources\n"); 334f2521a76SDoug Ambrisko goto fail; 335f2521a76SDoug Ambrisko } 336f2521a76SDoug Ambrisko } 337f2521a76SDoug Ambrisko 338f2521a76SDoug Ambrisko sc->vmd_io_rid = PCIR_IOBASEL_1; 339f2521a76SDoug Ambrisko sc->vmd_io_resource = bus_alloc_resource_any( 340f2521a76SDoug Ambrisko device_get_parent(sc->vmd_dev), SYS_RES_IOPORT, &sc->vmd_io_rid, 341f2521a76SDoug Ambrisko RF_ACTIVE); 342f2521a76SDoug Ambrisko if (sc->vmd_io_resource == NULL) { 343f2521a76SDoug Ambrisko device_printf(dev, "Cannot allocate IO\n"); 344f2521a76SDoug Ambrisko goto fail; 345f2521a76SDoug Ambrisko } 346f2521a76SDoug Ambrisko 347f2521a76SDoug Ambrisko sc->vmd_btag = rman_get_bustag(sc->vmd_regs_resource[0]); 348f2521a76SDoug Ambrisko sc->vmd_bhandle = rman_get_bushandle(sc->vmd_regs_resource[0]); 349f2521a76SDoug Ambrisko 350f2521a76SDoug Ambrisko pci_write_config(dev, PCIR_PRIBUS_2, 351f2521a76SDoug Ambrisko pcib_get_bus(device_get_parent(dev)), 1); 352f2521a76SDoug Ambrisko 353*0c852bb9SDoug Ambrisko t = vmd_devs; 354*0c852bb9SDoug Ambrisko vid = pci_get_vendor(dev); 355*0c852bb9SDoug Ambrisko did = pci_get_device(dev); 356*0c852bb9SDoug Ambrisko 357*0c852bb9SDoug Ambrisko sc->vmd_bus_start = 0; 358*0c852bb9SDoug Ambrisko while (t->vmd_name != NULL) { 359*0c852bb9SDoug Ambrisko if (vid == t->vmd_vid && 360*0c852bb9SDoug Ambrisko did == t->vmd_did) { 361*0c852bb9SDoug Ambrisko if (t->flags == BUS_RESTRICT) { 362*0c852bb9SDoug Ambrisko if (pci_read_config(dev, VMD_CAP, 2) & 363*0c852bb9SDoug Ambrisko VMD_BUS_RESTRICT) 364*0c852bb9SDoug Ambrisko switch (VMD_BUS_START(pci_read_config( 365*0c852bb9SDoug Ambrisko dev, VMD_CONFIG, 2))) { 366*0c852bb9SDoug Ambrisko case 1: 367*0c852bb9SDoug Ambrisko sc->vmd_bus_start = 128; 368*0c852bb9SDoug Ambrisko break; 369*0c852bb9SDoug Ambrisko case 2: 370*0c852bb9SDoug Ambrisko sc->vmd_bus_start = 224; 371*0c852bb9SDoug Ambrisko break; 372*0c852bb9SDoug Ambrisko case 3: 373*0c852bb9SDoug Ambrisko device_printf(dev, 374*0c852bb9SDoug Ambrisko "Unknown bug offset\n"); 375*0c852bb9SDoug Ambrisko goto fail; 376*0c852bb9SDoug Ambrisko break; 377*0c852bb9SDoug Ambrisko } 378*0c852bb9SDoug Ambrisko } 379*0c852bb9SDoug Ambrisko } 380*0c852bb9SDoug Ambrisko t++; 381*0c852bb9SDoug Ambrisko } 382*0c852bb9SDoug Ambrisko 383*0c852bb9SDoug Ambrisko device_printf(dev, "VMD bus starts at %d\n", sc->vmd_bus_start); 384*0c852bb9SDoug Ambrisko 385f2521a76SDoug Ambrisko sec_reg = PCIR_SECBUS_1; 386f2521a76SDoug Ambrisko bus = &sc->vmd_bus; 387f2521a76SDoug Ambrisko bus->sub_reg = PCIR_SUBBUS_1; 388f2521a76SDoug Ambrisko bus->sec = vmd_read_config(dev, b, s, f, sec_reg, 1); 389f2521a76SDoug Ambrisko bus->sub = vmd_read_config(dev, b, s, f, bus->sub_reg, 1); 390f2521a76SDoug Ambrisko bus->dev = dev; 391*0c852bb9SDoug Ambrisko bus->rman.rm_start = sc->vmd_bus_start; 392f2521a76SDoug Ambrisko bus->rman.rm_end = PCI_BUSMAX; 393f2521a76SDoug Ambrisko bus->rman.rm_type = RMAN_ARRAY; 394f2521a76SDoug Ambrisko snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev)); 395f2521a76SDoug Ambrisko bus->rman.rm_descr = strdup(buf, M_DEVBUF); 396f2521a76SDoug Ambrisko error = rman_init(&bus->rman); 397f2521a76SDoug Ambrisko if (error) { 398f2521a76SDoug Ambrisko device_printf(dev, "Failed to initialize %s bus number rman\n", 399f2521a76SDoug Ambrisko device_get_nameunit(dev)); 400e65e4e61SMark Johnston bus->rman.rm_end = 0; 401f2521a76SDoug Ambrisko goto fail; 402f2521a76SDoug Ambrisko } 403f2521a76SDoug Ambrisko 404f2521a76SDoug Ambrisko /* 405f2521a76SDoug Ambrisko * Allocate a bus range. This will return an existing bus range 406f2521a76SDoug Ambrisko * if one exists, or a new bus range if one does not. 407f2521a76SDoug Ambrisko */ 408f2521a76SDoug Ambrisko rid = 0; 409f2521a76SDoug Ambrisko bus->res = bus_alloc_resource_anywhere(dev, PCI_RES_BUS, &rid, 410f2521a76SDoug Ambrisko min_count, 0); 411f2521a76SDoug Ambrisko if (bus->res == NULL) { 412f2521a76SDoug Ambrisko /* 413f2521a76SDoug Ambrisko * Fall back to just allocating a range of a single bus 414f2521a76SDoug Ambrisko * number. 415f2521a76SDoug Ambrisko */ 416f2521a76SDoug Ambrisko bus->res = bus_alloc_resource_anywhere(dev, PCI_RES_BUS, &rid, 417f2521a76SDoug Ambrisko 1, 0); 418f2521a76SDoug Ambrisko } else if (rman_get_size(bus->res) < min_count) { 419f2521a76SDoug Ambrisko /* 420f2521a76SDoug Ambrisko * Attempt to grow the existing range to satisfy the 421f2521a76SDoug Ambrisko * minimum desired count. 422f2521a76SDoug Ambrisko */ 423f2521a76SDoug Ambrisko (void)bus_adjust_resource(dev, PCI_RES_BUS, bus->res, 424f2521a76SDoug Ambrisko rman_get_start(bus->res), rman_get_start(bus->res) + 425f2521a76SDoug Ambrisko min_count - 1); 426f2521a76SDoug Ambrisko } 427f2521a76SDoug Ambrisko 428f2521a76SDoug Ambrisko /* 429f2521a76SDoug Ambrisko * Add the initial resource to the rman. 430f2521a76SDoug Ambrisko */ 431f2521a76SDoug Ambrisko if (bus->res != NULL) { 432f2521a76SDoug Ambrisko error = rman_manage_region(&bus->rman, rman_get_start(bus->res), 433f2521a76SDoug Ambrisko rman_get_end(bus->res)); 434f2521a76SDoug Ambrisko if (error) { 435f2521a76SDoug Ambrisko device_printf(dev, "Failed to add resource to rman\n"); 436f2521a76SDoug Ambrisko goto fail; 437f2521a76SDoug Ambrisko } 438f2521a76SDoug Ambrisko bus->sec = rman_get_start(bus->res); 439f2521a76SDoug Ambrisko bus->sub = rman_get_end(bus->res); 440f2521a76SDoug Ambrisko } 441f2521a76SDoug Ambrisko 442f2521a76SDoug Ambrisko sc->vmd_msix_count = pci_msix_count(dev); 443f2521a76SDoug Ambrisko if (pci_alloc_msix(dev, &sc->vmd_msix_count) == 0) { 444f2521a76SDoug Ambrisko sc->vmd_irq = malloc(sizeof(struct vmd_irq) * 445f2521a76SDoug Ambrisko sc->vmd_msix_count, 446f2521a76SDoug Ambrisko M_DEVBUF, M_WAITOK | M_ZERO); 447f2521a76SDoug Ambrisko 448f2521a76SDoug Ambrisko for (i = 0; i < sc->vmd_msix_count; i++) { 449f2521a76SDoug Ambrisko sc->vmd_irq[i].vmd_rid = i + 1; 450f2521a76SDoug Ambrisko sc->vmd_irq[i].vmd_sc = sc; 451f2521a76SDoug Ambrisko sc->vmd_irq[i].vmd_instance = i; 452f2521a76SDoug Ambrisko sc->vmd_irq[i].vmd_res = bus_alloc_resource_any(dev, 453f2521a76SDoug Ambrisko SYS_RES_IRQ, &sc->vmd_irq[i].vmd_rid, 454f2521a76SDoug Ambrisko RF_ACTIVE); 455f2521a76SDoug Ambrisko if (sc->vmd_irq[i].vmd_res == NULL) { 456f2521a76SDoug Ambrisko device_printf(dev,"Failed to alloc irq\n"); 457f2521a76SDoug Ambrisko goto fail; 458f2521a76SDoug Ambrisko } 459f2521a76SDoug Ambrisko 460f2521a76SDoug Ambrisko TAILQ_INIT(&sc->vmd_irq[i].vmd_list); 461f2521a76SDoug Ambrisko if (bus_setup_intr(dev, sc->vmd_irq[i].vmd_res, 462f2521a76SDoug Ambrisko INTR_TYPE_MISC | INTR_MPSAFE, NULL, vmd_intr, 463f2521a76SDoug Ambrisko &sc->vmd_irq[i], &sc->vmd_irq[i].vmd_handle)) { 464f2521a76SDoug Ambrisko device_printf(sc->vmd_dev, 465f2521a76SDoug Ambrisko "Cannot set up interrupt\n"); 466f2521a76SDoug Ambrisko sc->vmd_irq[i].vmd_res = NULL; 467f2521a76SDoug Ambrisko goto fail; 468f2521a76SDoug Ambrisko } 469f2521a76SDoug Ambrisko } 470f2521a76SDoug Ambrisko } 471f2521a76SDoug Ambrisko 472f2521a76SDoug Ambrisko sc->vmd_child = device_add_child(dev, NULL, -1); 473f2521a76SDoug Ambrisko if (sc->vmd_child == NULL) { 474f2521a76SDoug Ambrisko device_printf(dev, "Failed to attach child\n"); 475f2521a76SDoug Ambrisko goto fail; 476f2521a76SDoug Ambrisko } 477f2521a76SDoug Ambrisko 478f2521a76SDoug Ambrisko error = device_probe_and_attach(sc->vmd_child); 479f2521a76SDoug Ambrisko if (error) { 480e65e4e61SMark Johnston device_printf(dev, "Failed to add probe child: %d\n", error); 481e65e4e61SMark Johnston (void)device_delete_child(dev, sc->vmd_child); 482f2521a76SDoug Ambrisko goto fail; 483f2521a76SDoug Ambrisko } 484f2521a76SDoug Ambrisko 485f2521a76SDoug Ambrisko return (0); 486f2521a76SDoug Ambrisko 487f2521a76SDoug Ambrisko fail: 488f2521a76SDoug Ambrisko vmd_free(sc); 489f2521a76SDoug Ambrisko return (ENXIO); 490f2521a76SDoug Ambrisko } 491f2521a76SDoug Ambrisko 492f2521a76SDoug Ambrisko static int 493f2521a76SDoug Ambrisko vmd_detach(device_t dev) 494f2521a76SDoug Ambrisko { 495f2521a76SDoug Ambrisko struct vmd_softc *sc; 496f2521a76SDoug Ambrisko int err; 497f2521a76SDoug Ambrisko 498f2521a76SDoug Ambrisko sc = device_get_softc(dev); 499f2521a76SDoug Ambrisko if (sc->vmd_child != NULL) { 500f2521a76SDoug Ambrisko err = bus_generic_detach(sc->vmd_child); 501f2521a76SDoug Ambrisko if (err) 502f2521a76SDoug Ambrisko return (err); 503f2521a76SDoug Ambrisko err = device_delete_child(dev, sc->vmd_child); 504f2521a76SDoug Ambrisko if (err) 505f2521a76SDoug Ambrisko return (err); 506f2521a76SDoug Ambrisko } 507f2521a76SDoug Ambrisko vmd_free(sc); 508f2521a76SDoug Ambrisko return (0); 509f2521a76SDoug Ambrisko } 510f2521a76SDoug Ambrisko 511f2521a76SDoug Ambrisko /* Pass request to alloc an MSI-X message up to the parent bridge. */ 512f2521a76SDoug Ambrisko static int 513f2521a76SDoug Ambrisko vmd_alloc_msix(device_t pcib, device_t dev, int *irq) 514f2521a76SDoug Ambrisko { 515f2521a76SDoug Ambrisko struct vmd_softc *sc = device_get_softc(pcib); 516f2521a76SDoug Ambrisko device_t bus; 517f2521a76SDoug Ambrisko int ret; 518f2521a76SDoug Ambrisko 519f2521a76SDoug Ambrisko if (sc->vmd_flags & PCIB_DISABLE_MSIX) 520f2521a76SDoug Ambrisko return (ENXIO); 521f2521a76SDoug Ambrisko bus = device_get_parent(pcib); 522f2521a76SDoug Ambrisko ret = PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq); 523f2521a76SDoug Ambrisko return (ret); 524f2521a76SDoug Ambrisko } 525f2521a76SDoug Ambrisko 526f2521a76SDoug Ambrisko static struct resource * 527f2521a76SDoug Ambrisko vmd_alloc_resource(device_t dev, device_t child, int type, int *rid, 528f2521a76SDoug Ambrisko rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 529f2521a76SDoug Ambrisko { 530f2521a76SDoug Ambrisko /* Start at max PCI vmd_domain and work down */ 531f2521a76SDoug Ambrisko if (type == PCI_RES_BUS) { 532f2521a76SDoug Ambrisko return (pci_domain_alloc_bus(PCI_DOMAINMAX - 533f2521a76SDoug Ambrisko device_get_unit(dev), child, rid, start, end, 534f2521a76SDoug Ambrisko count, flags)); 535f2521a76SDoug Ambrisko } 536f2521a76SDoug Ambrisko 537f2521a76SDoug Ambrisko return (pcib_alloc_resource(dev, child, type, rid, start, end, 538f2521a76SDoug Ambrisko count, flags)); 539f2521a76SDoug Ambrisko } 540f2521a76SDoug Ambrisko 541f2521a76SDoug Ambrisko static int 542f2521a76SDoug Ambrisko vmd_adjust_resource(device_t dev, device_t child, int type, 543f2521a76SDoug Ambrisko struct resource *r, rman_res_t start, rman_res_t end) 544f2521a76SDoug Ambrisko { 545f2521a76SDoug Ambrisko struct resource *res = r; 546f2521a76SDoug Ambrisko 547f2521a76SDoug Ambrisko if (type == PCI_RES_BUS) 548f2521a76SDoug Ambrisko return (pci_domain_adjust_bus(PCI_DOMAINMAX - 549f2521a76SDoug Ambrisko device_get_unit(dev), child, res, start, end)); 550f2521a76SDoug Ambrisko return (pcib_adjust_resource(dev, child, type, res, start, end)); 551f2521a76SDoug Ambrisko } 552f2521a76SDoug Ambrisko 553f2521a76SDoug Ambrisko static int 554f2521a76SDoug Ambrisko vmd_release_resource(device_t dev, device_t child, int type, int rid, 555f2521a76SDoug Ambrisko struct resource *r) 556f2521a76SDoug Ambrisko { 557f2521a76SDoug Ambrisko if (type == PCI_RES_BUS) 558f2521a76SDoug Ambrisko return (pci_domain_release_bus(PCI_DOMAINMAX - 559f2521a76SDoug Ambrisko device_get_unit(dev), child, rid, r)); 560f2521a76SDoug Ambrisko return (pcib_release_resource(dev, child, type, rid, r)); 561f2521a76SDoug Ambrisko } 562f2521a76SDoug Ambrisko 563f2521a76SDoug Ambrisko static int 564f2521a76SDoug Ambrisko vmd_shutdown(device_t dev) 565f2521a76SDoug Ambrisko { 566f2521a76SDoug Ambrisko return (0); 567f2521a76SDoug Ambrisko } 568f2521a76SDoug Ambrisko 569f2521a76SDoug Ambrisko static int 570f2521a76SDoug Ambrisko vmd_pcib_route_interrupt(device_t pcib, device_t dev, int pin) 571f2521a76SDoug Ambrisko { 572f2521a76SDoug Ambrisko return (pcib_route_interrupt(pcib, dev, pin)); 573f2521a76SDoug Ambrisko } 574f2521a76SDoug Ambrisko 575f2521a76SDoug Ambrisko static int 576f2521a76SDoug Ambrisko vmd_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, 577f2521a76SDoug Ambrisko int *irqs) 578f2521a76SDoug Ambrisko { 579f2521a76SDoug Ambrisko return (pcib_alloc_msi(pcib, dev, count, maxcount, irqs)); 580f2521a76SDoug Ambrisko } 581f2521a76SDoug Ambrisko 582f2521a76SDoug Ambrisko static int 583f2521a76SDoug Ambrisko vmd_pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) 584f2521a76SDoug Ambrisko { 585f2521a76SDoug Ambrisko 586f2521a76SDoug Ambrisko return (pcib_release_msi(pcib, dev, count, irqs)); 587f2521a76SDoug Ambrisko } 588f2521a76SDoug Ambrisko 589f2521a76SDoug Ambrisko static int 590f2521a76SDoug Ambrisko vmd_pcib_release_msix(device_t pcib, device_t dev, int irq) { 591f2521a76SDoug Ambrisko return pcib_release_msix(pcib, dev, irq); 592f2521a76SDoug Ambrisko } 593f2521a76SDoug Ambrisko 594f2521a76SDoug Ambrisko static int 595f2521a76SDoug Ambrisko vmd_setup_intr(device_t dev, device_t child, struct resource *irq, 596f2521a76SDoug Ambrisko int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg, 597f2521a76SDoug Ambrisko void **cookiep) 598f2521a76SDoug Ambrisko { 599f2521a76SDoug Ambrisko struct vmd_irq_handler *elm; 600f2521a76SDoug Ambrisko struct vmd_softc *sc; 601f2521a76SDoug Ambrisko int i; 602f2521a76SDoug Ambrisko 603f2521a76SDoug Ambrisko sc = device_get_softc(dev); 604f2521a76SDoug Ambrisko 605f2521a76SDoug Ambrisko /* 606f2521a76SDoug Ambrisko * There appears to be no steering of VMD interrupts from device 607f2521a76SDoug Ambrisko * to VMD interrupt 608f2521a76SDoug Ambrisko */ 609f2521a76SDoug Ambrisko 610f2521a76SDoug Ambrisko i = 0; 611f2521a76SDoug Ambrisko elm = malloc(sizeof(*elm), M_DEVBUF, M_NOWAIT|M_ZERO); 612f2521a76SDoug Ambrisko elm->vmd_child = child; 613f2521a76SDoug Ambrisko elm->vmd_intr = intr; 614f2521a76SDoug Ambrisko elm->vmd_rid = rman_get_rid(irq); 615f2521a76SDoug Ambrisko elm->vmd_arg = arg; 616f2521a76SDoug Ambrisko TAILQ_INSERT_TAIL(&sc->vmd_irq[i].vmd_list, elm, vmd_link); 617f2521a76SDoug Ambrisko 618f2521a76SDoug Ambrisko return (bus_generic_setup_intr(dev, child, irq, flags, filter, intr, 619f2521a76SDoug Ambrisko arg, cookiep)); 620f2521a76SDoug Ambrisko } 621f2521a76SDoug Ambrisko 622f2521a76SDoug Ambrisko static int 623f2521a76SDoug Ambrisko vmd_teardown_intr(device_t dev, device_t child, struct resource *irq, 624f2521a76SDoug Ambrisko void *cookie) 625f2521a76SDoug Ambrisko { 626f2521a76SDoug Ambrisko struct vmd_irq_handler *elm, *tmp;; 627f2521a76SDoug Ambrisko struct vmd_softc *sc; 628f2521a76SDoug Ambrisko 629f2521a76SDoug Ambrisko sc = device_get_softc(dev); 630f2521a76SDoug Ambrisko TAILQ_FOREACH_SAFE(elm, &sc->vmd_irq[0].vmd_list, vmd_link, tmp) { 631f2521a76SDoug Ambrisko if (elm->vmd_child == child && 632f2521a76SDoug Ambrisko elm->vmd_rid == rman_get_rid(irq)) { 633f2521a76SDoug Ambrisko TAILQ_REMOVE(&sc->vmd_irq[0].vmd_list, elm, vmd_link); 634f2521a76SDoug Ambrisko free(elm, M_DEVBUF); 635f2521a76SDoug Ambrisko } 636f2521a76SDoug Ambrisko } 637f2521a76SDoug Ambrisko 638f2521a76SDoug Ambrisko return (bus_generic_teardown_intr(dev, child, irq, cookie)); 639f2521a76SDoug Ambrisko } 640f2521a76SDoug Ambrisko 641f2521a76SDoug Ambrisko static device_method_t vmd_pci_methods[] = { 642f2521a76SDoug Ambrisko /* Device interface */ 643f2521a76SDoug Ambrisko DEVMETHOD(device_probe, vmd_probe), 644f2521a76SDoug Ambrisko DEVMETHOD(device_attach, vmd_attach), 645f2521a76SDoug Ambrisko DEVMETHOD(device_detach, vmd_detach), 646f2521a76SDoug Ambrisko DEVMETHOD(device_shutdown, vmd_shutdown), 647f2521a76SDoug Ambrisko 648f2521a76SDoug Ambrisko /* Bus interface */ 649f2521a76SDoug Ambrisko DEVMETHOD(bus_read_ivar, pcib_read_ivar), 650f2521a76SDoug Ambrisko DEVMETHOD(bus_write_ivar, pcib_write_ivar), 651f2521a76SDoug Ambrisko DEVMETHOD(bus_alloc_resource, vmd_alloc_resource), 652f2521a76SDoug Ambrisko DEVMETHOD(bus_adjust_resource, vmd_adjust_resource), 653f2521a76SDoug Ambrisko DEVMETHOD(bus_release_resource, vmd_release_resource), 654f2521a76SDoug Ambrisko DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 655f2521a76SDoug Ambrisko DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 656f2521a76SDoug Ambrisko DEVMETHOD(bus_setup_intr, vmd_setup_intr), 657f2521a76SDoug Ambrisko DEVMETHOD(bus_teardown_intr, vmd_teardown_intr), 658f2521a76SDoug Ambrisko 659f2521a76SDoug Ambrisko /* pci interface */ 660f2521a76SDoug Ambrisko DEVMETHOD(pci_read_config, vmd_pci_read_config), 661f2521a76SDoug Ambrisko DEVMETHOD(pci_write_config, vmd_pci_write_config), 662f2521a76SDoug Ambrisko DEVMETHOD(pci_alloc_devinfo, vmd_alloc_devinfo), 663f2521a76SDoug Ambrisko 664f2521a76SDoug Ambrisko /* pcib interface */ 665f2521a76SDoug Ambrisko DEVMETHOD(pcib_maxslots, pcib_maxslots), 666f2521a76SDoug Ambrisko DEVMETHOD(pcib_read_config, vmd_read_config), 667f2521a76SDoug Ambrisko DEVMETHOD(pcib_write_config, vmd_write_config), 668f2521a76SDoug Ambrisko DEVMETHOD(pcib_route_interrupt, vmd_pcib_route_interrupt), 669f2521a76SDoug Ambrisko DEVMETHOD(pcib_alloc_msi, vmd_pcib_alloc_msi), 670f2521a76SDoug Ambrisko DEVMETHOD(pcib_release_msi, vmd_pcib_release_msi), 671f2521a76SDoug Ambrisko DEVMETHOD(pcib_alloc_msix, vmd_alloc_msix), 672f2521a76SDoug Ambrisko DEVMETHOD(pcib_release_msix, vmd_pcib_release_msix), 673f2521a76SDoug Ambrisko DEVMETHOD(pcib_map_msi, pcib_map_msi), 674f2521a76SDoug Ambrisko 675f2521a76SDoug Ambrisko DEVMETHOD_END 676f2521a76SDoug Ambrisko }; 677f2521a76SDoug Ambrisko 678f2521a76SDoug Ambrisko static devclass_t vmd_devclass; 679f2521a76SDoug Ambrisko 680f2521a76SDoug Ambrisko DEFINE_CLASS_0(vmd, vmd_pci_driver, vmd_pci_methods, sizeof(struct vmd_softc)); 681f2521a76SDoug Ambrisko DRIVER_MODULE(vmd, pci, vmd_pci_driver, vmd_devclass, NULL, NULL); 682f2521a76SDoug Ambrisko MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, vmd, 683f2521a76SDoug Ambrisko vmd_devs, nitems(vmd_devs) - 1); 684f2521a76SDoug Ambrisko MODULE_DEPEND(vmd, vmd_bus, 1, 1, 1); 685