1f2521a76SDoug Ambrisko /*- 2f2521a76SDoug Ambrisko * SPDX-License-Identifier: BSD-2-Clause 3f2521a76SDoug Ambrisko * 47af4475aSAlexander Motin * Copyright (c) 2021 Alexander Motin <mav@FreeBSD.org> 5f2521a76SDoug Ambrisko * Copyright 2019 Cisco Systems, Inc. 6f2521a76SDoug Ambrisko * All rights reserved. 7f2521a76SDoug Ambrisko * 8f2521a76SDoug Ambrisko * Redistribution and use in source and binary forms, with or without 9f2521a76SDoug Ambrisko * modification, are permitted provided that the following conditions 10f2521a76SDoug Ambrisko * are met: 11f2521a76SDoug Ambrisko * 1. Redistributions of source code must retain the above copyright 12f2521a76SDoug Ambrisko * notice, this list of conditions and the following disclaimer. 13f2521a76SDoug Ambrisko * 2. Redistributions in binary form must reproduce the above copyright 14f2521a76SDoug Ambrisko * notice, this list of conditions and the following disclaimer in the 15f2521a76SDoug Ambrisko * documentation and/or other materials provided with the distribution. 16f2521a76SDoug Ambrisko * 17f2521a76SDoug Ambrisko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18f2521a76SDoug Ambrisko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19f2521a76SDoug Ambrisko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20f2521a76SDoug Ambrisko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21f2521a76SDoug Ambrisko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22f2521a76SDoug Ambrisko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23f2521a76SDoug Ambrisko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24f2521a76SDoug Ambrisko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25f2521a76SDoug Ambrisko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26f2521a76SDoug Ambrisko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27f2521a76SDoug Ambrisko * SUCH DAMAGE. 28f2521a76SDoug Ambrisko */ 29f2521a76SDoug Ambrisko 30f2521a76SDoug Ambrisko #include <sys/types.h> 31f2521a76SDoug Ambrisko #include <sys/param.h> 32f2521a76SDoug Ambrisko #include <sys/bus.h> 33f2521a76SDoug Ambrisko #include <sys/conf.h> 34f2521a76SDoug Ambrisko #include <sys/kernel.h> 357af4475aSAlexander Motin #include <sys/limits.h> 36f2521a76SDoug Ambrisko #include <sys/module.h> 377af4475aSAlexander Motin #include <sys/sysctl.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> 437af4475aSAlexander Motin #include <machine/intr_machdep.h> 44f2521a76SDoug Ambrisko #include <sys/rman.h> 45f2521a76SDoug Ambrisko #include <sys/lock.h> 46f2521a76SDoug Ambrisko #include <sys/mutex.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 #include <dev/vmd/vmd.h> 55f2521a76SDoug Ambrisko 56f2521a76SDoug Ambrisko #include "pcib_if.h" 57f2521a76SDoug Ambrisko 58f2521a76SDoug Ambrisko struct vmd_type { 59f2521a76SDoug Ambrisko u_int16_t vmd_vid; 60f2521a76SDoug Ambrisko u_int16_t vmd_did; 61f2521a76SDoug Ambrisko char *vmd_name; 620c852bb9SDoug Ambrisko int flags; 630c852bb9SDoug Ambrisko #define BUS_RESTRICT 1 647af4475aSAlexander Motin #define VECTOR_OFFSET 2 65c28220d8SAlexander Motin #define CAN_BYPASS_MSI 4 66f2521a76SDoug Ambrisko }; 67f2521a76SDoug Ambrisko 680c852bb9SDoug Ambrisko #define VMD_CAP 0x40 690c852bb9SDoug Ambrisko #define VMD_BUS_RESTRICT 0x1 700c852bb9SDoug Ambrisko 710c852bb9SDoug Ambrisko #define VMD_CONFIG 0x44 72c28220d8SAlexander Motin #define VMD_BYPASS_MSI 0x2 730c852bb9SDoug Ambrisko #define VMD_BUS_START(x) ((x >> 8) & 0x3) 740c852bb9SDoug Ambrisko 750c852bb9SDoug Ambrisko #define VMD_LOCK 0x70 76f2521a76SDoug Ambrisko 777af4475aSAlexander Motin SYSCTL_NODE(_hw, OID_AUTO, vmd, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 787af4475aSAlexander Motin "Intel Volume Management Device tuning parameters"); 797af4475aSAlexander Motin 807af4475aSAlexander Motin /* 81c28220d8SAlexander Motin * By default all VMD devices remap children MSI/MSI-X interrupts into their 82c28220d8SAlexander Motin * own. It creates additional isolation, but also complicates things due to 83c28220d8SAlexander Motin * sharing, etc. Fortunately some VMD devices can bypass the remapping. 84c28220d8SAlexander Motin */ 85c28220d8SAlexander Motin static int vmd_bypass_msi = 1; 86c28220d8SAlexander Motin SYSCTL_INT(_hw_vmd, OID_AUTO, bypass_msi, CTLFLAG_RWTUN, &vmd_bypass_msi, 0, 87c28220d8SAlexander Motin "Bypass MSI remapping on capable hardware"); 88c28220d8SAlexander Motin 89c28220d8SAlexander Motin /* 907af4475aSAlexander Motin * All MSIs within a group share address, so VMD can't distinguish them. 917af4475aSAlexander Motin * It makes no sense to use more than one per device, only if required by 927af4475aSAlexander Motin * some specific device drivers. 937af4475aSAlexander Motin */ 947af4475aSAlexander Motin static int vmd_max_msi = 1; 957af4475aSAlexander Motin SYSCTL_INT(_hw_vmd, OID_AUTO, max_msi, CTLFLAG_RWTUN, &vmd_max_msi, 0, 967af4475aSAlexander Motin "Maximum number of MSI vectors per device"); 977af4475aSAlexander Motin 987af4475aSAlexander Motin /* 997af4475aSAlexander Motin * MSI-X can use different addresses, but we have limited number of MSI-X 1007af4475aSAlexander Motin * we can route to, so use conservative default to try to avoid sharing. 1017af4475aSAlexander Motin */ 1027af4475aSAlexander Motin static int vmd_max_msix = 3; 1037af4475aSAlexander Motin SYSCTL_INT(_hw_vmd, OID_AUTO, max_msix, CTLFLAG_RWTUN, &vmd_max_msix, 0, 1047af4475aSAlexander Motin "Maximum number of MSI-X vectors per device"); 1057af4475aSAlexander Motin 106f2521a76SDoug Ambrisko static struct vmd_type vmd_devs[] = { 1077af4475aSAlexander Motin { 0x8086, 0x201d, "Intel Volume Management Device", 0 }, 108c28220d8SAlexander Motin { 0x8086, 0x28c0, "Intel Volume Management Device", BUS_RESTRICT | CAN_BYPASS_MSI }, 1097af4475aSAlexander Motin { 0x8086, 0x467f, "Intel Volume Management Device", BUS_RESTRICT | VECTOR_OFFSET }, 1107af4475aSAlexander Motin { 0x8086, 0x4c3d, "Intel Volume Management Device", BUS_RESTRICT | VECTOR_OFFSET }, 1119bce1141SAlexander Motin { 0x8086, 0x7d0b, "Intel Volume Management Device", BUS_RESTRICT | VECTOR_OFFSET }, 1127af4475aSAlexander Motin { 0x8086, 0x9a0b, "Intel Volume Management Device", BUS_RESTRICT | VECTOR_OFFSET }, 113b07a48d4SNeel Chauhan { 0x8086, 0xa77f, "Intel Volume Management Device", BUS_RESTRICT | VECTOR_OFFSET }, 1149bce1141SAlexander Motin { 0x8086, 0xad0b, "Intel Volume Management Device", BUS_RESTRICT | VECTOR_OFFSET }, 1150c852bb9SDoug Ambrisko { 0, 0, NULL, 0 } 116f2521a76SDoug Ambrisko }; 117f2521a76SDoug Ambrisko 118f2521a76SDoug Ambrisko static int 119f2521a76SDoug Ambrisko vmd_probe(device_t dev) 120f2521a76SDoug Ambrisko { 121f2521a76SDoug Ambrisko struct vmd_type *t; 122f2521a76SDoug Ambrisko uint16_t vid, did; 123f2521a76SDoug Ambrisko 124f2521a76SDoug Ambrisko vid = pci_get_vendor(dev); 125f2521a76SDoug Ambrisko did = pci_get_device(dev); 1267af4475aSAlexander Motin for (t = vmd_devs; t->vmd_name != NULL; t++) { 1277af4475aSAlexander Motin if (vid == t->vmd_vid && did == t->vmd_did) { 128f2521a76SDoug Ambrisko device_set_desc(dev, t->vmd_name); 129f2521a76SDoug Ambrisko return (BUS_PROBE_DEFAULT); 130f2521a76SDoug Ambrisko } 131f2521a76SDoug Ambrisko } 132f2521a76SDoug Ambrisko return (ENXIO); 133f2521a76SDoug Ambrisko } 134f2521a76SDoug Ambrisko 135f2521a76SDoug Ambrisko static void 136f2521a76SDoug Ambrisko vmd_free(struct vmd_softc *sc) 137f2521a76SDoug Ambrisko { 1387af4475aSAlexander Motin struct vmd_irq *vi; 1397af4475aSAlexander Motin struct vmd_irq_user *u; 140f2521a76SDoug Ambrisko int i; 141f2521a76SDoug Ambrisko 1427af4475aSAlexander Motin if (sc->psc.bus.rman.rm_end != 0) 1437af4475aSAlexander Motin rman_fini(&sc->psc.bus.rman); 1447af4475aSAlexander Motin if (sc->psc.mem.rman.rm_end != 0) 1457af4475aSAlexander Motin rman_fini(&sc->psc.mem.rman); 1467af4475aSAlexander Motin while ((u = LIST_FIRST(&sc->vmd_users)) != NULL) { 1477af4475aSAlexander Motin LIST_REMOVE(u, viu_link); 1487af4475aSAlexander Motin free(u, M_DEVBUF); 149f2521a76SDoug Ambrisko } 150f2521a76SDoug Ambrisko if (sc->vmd_irq != NULL) { 151f2521a76SDoug Ambrisko for (i = 0; i < sc->vmd_msix_count; i++) { 1527af4475aSAlexander Motin vi = &sc->vmd_irq[i]; 1537af4475aSAlexander Motin if (vi->vi_res == NULL) 1547af4475aSAlexander Motin continue; 1557af4475aSAlexander Motin bus_teardown_intr(sc->psc.dev, vi->vi_res, 1567af4475aSAlexander Motin vi->vi_handle); 1577af4475aSAlexander Motin bus_release_resource(sc->psc.dev, SYS_RES_IRQ, 1587af4475aSAlexander Motin vi->vi_rid, vi->vi_res); 159f2521a76SDoug Ambrisko } 160f2521a76SDoug Ambrisko } 161f2521a76SDoug Ambrisko free(sc->vmd_irq, M_DEVBUF); 162f2521a76SDoug Ambrisko sc->vmd_irq = NULL; 1637af4475aSAlexander Motin pci_release_msi(sc->psc.dev); 164f2521a76SDoug Ambrisko for (i = 0; i < VMD_MAX_BAR; i++) { 1657af4475aSAlexander Motin if (sc->vmd_regs_res[i] != NULL) 1667af4475aSAlexander Motin bus_release_resource(sc->psc.dev, SYS_RES_MEMORY, 1677af4475aSAlexander Motin sc->vmd_regs_rid[i], sc->vmd_regs_res[i]); 168f2521a76SDoug Ambrisko } 169f2521a76SDoug Ambrisko } 170f2521a76SDoug Ambrisko 171f2521a76SDoug Ambrisko /* Hidden PCI Roots are hidden in BAR(0). */ 172f2521a76SDoug Ambrisko 173f2521a76SDoug Ambrisko static uint32_t 174f2521a76SDoug Ambrisko vmd_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) 175f2521a76SDoug Ambrisko { 176f2521a76SDoug Ambrisko struct vmd_softc *sc; 177f2521a76SDoug Ambrisko bus_addr_t offset; 178f2521a76SDoug Ambrisko 179f2521a76SDoug Ambrisko sc = device_get_softc(dev); 1807af4475aSAlexander Motin if (b < sc->vmd_bus_start || b > sc->vmd_bus_end) 1810c852bb9SDoug Ambrisko return (0xffffffff); 1820c852bb9SDoug Ambrisko 1830c852bb9SDoug Ambrisko offset = ((b - sc->vmd_bus_start) << 20) + (s << 15) + (f << 12) + reg; 1840c852bb9SDoug Ambrisko 185f2521a76SDoug Ambrisko switch (width) { 186f2521a76SDoug Ambrisko case 4: 18776c67868SJohn Baldwin return (bus_read_4(sc->vmd_regs_res[0], offset)); 188f2521a76SDoug Ambrisko case 2: 18976c67868SJohn Baldwin return (bus_read_2(sc->vmd_regs_res[0], offset)); 190f2521a76SDoug Ambrisko case 1: 19176c67868SJohn Baldwin return (bus_read_1(sc->vmd_regs_res[0], offset)); 192f2521a76SDoug Ambrisko default: 1937af4475aSAlexander Motin __assert_unreachable(); 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 struct vmd_softc *sc; 203f2521a76SDoug Ambrisko bus_addr_t offset; 204f2521a76SDoug Ambrisko 205f2521a76SDoug Ambrisko sc = device_get_softc(dev); 2067af4475aSAlexander Motin if (b < sc->vmd_bus_start || b > sc->vmd_bus_end) 2070c852bb9SDoug Ambrisko return; 2080c852bb9SDoug Ambrisko 2090c852bb9SDoug Ambrisko offset = ((b - sc->vmd_bus_start) << 20) + (s << 15) + (f << 12) + reg; 210f2521a76SDoug Ambrisko 211f2521a76SDoug Ambrisko switch (width) { 212f2521a76SDoug Ambrisko case 4: 21376c67868SJohn Baldwin return (bus_write_4(sc->vmd_regs_res[0], offset, val)); 214f2521a76SDoug Ambrisko case 2: 21576c67868SJohn Baldwin return (bus_write_2(sc->vmd_regs_res[0], offset, val)); 216f2521a76SDoug Ambrisko case 1: 21776c67868SJohn Baldwin return (bus_write_1(sc->vmd_regs_res[0], offset, val)); 218f2521a76SDoug Ambrisko default: 2197af4475aSAlexander Motin __assert_unreachable(); 220f2521a76SDoug Ambrisko } 221f2521a76SDoug Ambrisko } 222f2521a76SDoug Ambrisko 223c28220d8SAlexander Motin static void 224c28220d8SAlexander Motin vmd_set_msi_bypass(device_t dev, bool enable) 225c28220d8SAlexander Motin { 226c28220d8SAlexander Motin uint16_t val; 227c28220d8SAlexander Motin 228c28220d8SAlexander Motin val = pci_read_config(dev, VMD_CONFIG, 2); 229c28220d8SAlexander Motin if (enable) 230c28220d8SAlexander Motin val |= VMD_BYPASS_MSI; 231c28220d8SAlexander Motin else 232c28220d8SAlexander Motin val &= ~VMD_BYPASS_MSI; 233c28220d8SAlexander Motin pci_write_config(dev, VMD_CONFIG, val, 2); 234c28220d8SAlexander Motin } 235c28220d8SAlexander Motin 2367af4475aSAlexander Motin static int 237f2521a76SDoug Ambrisko vmd_intr(void *arg) 238f2521a76SDoug Ambrisko { 2397af4475aSAlexander Motin /* 2407af4475aSAlexander Motin * We have nothing to do here, but we have to register some interrupt 2417af4475aSAlexander Motin * handler to make PCI code setup and enable the MSI-X vector. 2427af4475aSAlexander Motin */ 2437af4475aSAlexander Motin return (FILTER_STRAY); 244f2521a76SDoug Ambrisko } 245f2521a76SDoug Ambrisko 246f2521a76SDoug Ambrisko static int 247f2521a76SDoug Ambrisko vmd_attach(device_t dev) 248f2521a76SDoug Ambrisko { 249f2521a76SDoug Ambrisko struct vmd_softc *sc; 250f2521a76SDoug Ambrisko struct pcib_secbus *bus; 2517af4475aSAlexander Motin struct pcib_window *w; 2520c852bb9SDoug Ambrisko struct vmd_type *t; 2537af4475aSAlexander Motin struct vmd_irq *vi; 2540c852bb9SDoug Ambrisko uint16_t vid, did; 255f2521a76SDoug Ambrisko uint32_t bar; 256f2521a76SDoug Ambrisko int i, j, error; 257f2521a76SDoug Ambrisko char buf[64]; 258f2521a76SDoug Ambrisko 259f2521a76SDoug Ambrisko sc = device_get_softc(dev); 260f2521a76SDoug Ambrisko bzero(sc, sizeof(*sc)); 2617af4475aSAlexander Motin sc->psc.dev = dev; 2627af4475aSAlexander Motin sc->psc.domain = PCI_DOMAINMAX - device_get_unit(dev); 263f2521a76SDoug Ambrisko 264f2521a76SDoug Ambrisko pci_enable_busmaster(dev); 265f2521a76SDoug Ambrisko 266f2521a76SDoug Ambrisko for (i = 0, j = 0; i < VMD_MAX_BAR; i++, j++) { 267f2521a76SDoug Ambrisko sc->vmd_regs_rid[i] = PCIR_BAR(j); 268f2521a76SDoug Ambrisko bar = pci_read_config(dev, PCIR_BAR(0), 4); 269f2521a76SDoug Ambrisko if (PCI_BAR_MEM(bar) && (bar & PCIM_BAR_MEM_TYPE) == 270f2521a76SDoug Ambrisko PCIM_BAR_MEM_64) 271f2521a76SDoug Ambrisko j++; 2727af4475aSAlexander Motin if ((sc->vmd_regs_res[i] = bus_alloc_resource_any(dev, 2737af4475aSAlexander Motin SYS_RES_MEMORY, &sc->vmd_regs_rid[i], RF_ACTIVE)) == NULL) { 274f2521a76SDoug Ambrisko device_printf(dev, "Cannot allocate resources\n"); 275f2521a76SDoug Ambrisko goto fail; 276f2521a76SDoug Ambrisko } 277f2521a76SDoug Ambrisko } 278f2521a76SDoug Ambrisko 2790c852bb9SDoug Ambrisko vid = pci_get_vendor(dev); 2800c852bb9SDoug Ambrisko did = pci_get_device(dev); 2817af4475aSAlexander Motin for (t = vmd_devs; t->vmd_name != NULL; t++) { 2827af4475aSAlexander Motin if (vid == t->vmd_vid && did == t->vmd_did) 2837af4475aSAlexander Motin break; 2847af4475aSAlexander Motin } 2850c852bb9SDoug Ambrisko 2860c852bb9SDoug Ambrisko sc->vmd_bus_start = 0; 2877af4475aSAlexander Motin if ((t->flags & BUS_RESTRICT) && 2887af4475aSAlexander Motin (pci_read_config(dev, VMD_CAP, 2) & VMD_BUS_RESTRICT)) { 2897af4475aSAlexander Motin switch (VMD_BUS_START(pci_read_config(dev, VMD_CONFIG, 2))) { 2907af4475aSAlexander Motin case 0: 2917af4475aSAlexander Motin sc->vmd_bus_start = 0; 2927af4475aSAlexander Motin break; 2930c852bb9SDoug Ambrisko case 1: 2940c852bb9SDoug Ambrisko sc->vmd_bus_start = 128; 2950c852bb9SDoug Ambrisko break; 2960c852bb9SDoug Ambrisko case 2: 2970c852bb9SDoug Ambrisko sc->vmd_bus_start = 224; 2980c852bb9SDoug Ambrisko break; 2997af4475aSAlexander Motin default: 3007af4475aSAlexander Motin device_printf(dev, "Unknown bus offset\n"); 3010c852bb9SDoug Ambrisko goto fail; 3020c852bb9SDoug Ambrisko } 3030c852bb9SDoug Ambrisko } 3047af4475aSAlexander Motin sc->vmd_bus_end = MIN(PCI_BUSMAX, sc->vmd_bus_start + 3057af4475aSAlexander Motin (rman_get_size(sc->vmd_regs_res[0]) >> 20) - 1); 3060c852bb9SDoug Ambrisko 3077af4475aSAlexander Motin bus = &sc->psc.bus; 3087af4475aSAlexander Motin bus->sec = sc->vmd_bus_start; 3097af4475aSAlexander Motin bus->sub = sc->vmd_bus_end; 310f2521a76SDoug Ambrisko bus->dev = dev; 3117af4475aSAlexander Motin bus->rman.rm_start = 0; 312f2521a76SDoug Ambrisko bus->rman.rm_end = PCI_BUSMAX; 313f2521a76SDoug Ambrisko bus->rman.rm_type = RMAN_ARRAY; 314f2521a76SDoug Ambrisko snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev)); 315f2521a76SDoug Ambrisko bus->rman.rm_descr = strdup(buf, M_DEVBUF); 316f2521a76SDoug Ambrisko error = rman_init(&bus->rman); 317f2521a76SDoug Ambrisko if (error) { 3187af4475aSAlexander Motin device_printf(dev, "Failed to initialize bus rman\n"); 319e65e4e61SMark Johnston bus->rman.rm_end = 0; 320f2521a76SDoug Ambrisko goto fail; 321f2521a76SDoug Ambrisko } 3227af4475aSAlexander Motin error = rman_manage_region(&bus->rman, sc->vmd_bus_start, 3237af4475aSAlexander Motin sc->vmd_bus_end); 324f2521a76SDoug Ambrisko if (error) { 3257af4475aSAlexander Motin device_printf(dev, "Failed to add resource to bus rman\n"); 326f2521a76SDoug Ambrisko goto fail; 327f2521a76SDoug Ambrisko } 3287af4475aSAlexander Motin 3297af4475aSAlexander Motin w = &sc->psc.mem; 3307af4475aSAlexander Motin w->rman.rm_type = RMAN_ARRAY; 3317af4475aSAlexander Motin snprintf(buf, sizeof(buf), "%s memory window", device_get_nameunit(dev)); 3327af4475aSAlexander Motin w->rman.rm_descr = strdup(buf, M_DEVBUF); 3337af4475aSAlexander Motin error = rman_init(&w->rman); 3347af4475aSAlexander Motin if (error) { 3357af4475aSAlexander Motin device_printf(dev, "Failed to initialize memory rman\n"); 3367af4475aSAlexander Motin w->rman.rm_end = 0; 3377af4475aSAlexander Motin goto fail; 3387af4475aSAlexander Motin } 3397af4475aSAlexander Motin error = rman_manage_region(&w->rman, 3407af4475aSAlexander Motin rman_get_start(sc->vmd_regs_res[1]), 3417af4475aSAlexander Motin rman_get_end(sc->vmd_regs_res[1])); 3427af4475aSAlexander Motin if (error) { 3437af4475aSAlexander Motin device_printf(dev, "Failed to add resource to memory rman\n"); 3447af4475aSAlexander Motin goto fail; 3457af4475aSAlexander Motin } 3467af4475aSAlexander Motin error = rman_manage_region(&w->rman, 3477af4475aSAlexander Motin rman_get_start(sc->vmd_regs_res[2]) + 0x2000, 3487af4475aSAlexander Motin rman_get_end(sc->vmd_regs_res[2])); 3497af4475aSAlexander Motin if (error) { 3507af4475aSAlexander Motin device_printf(dev, "Failed to add resource to memory rman\n"); 3517af4475aSAlexander Motin goto fail; 352f2521a76SDoug Ambrisko } 353f2521a76SDoug Ambrisko 3547af4475aSAlexander Motin LIST_INIT(&sc->vmd_users); 3557af4475aSAlexander Motin sc->vmd_fist_vector = (t->flags & VECTOR_OFFSET) ? 1 : 0; 356f2521a76SDoug Ambrisko sc->vmd_msix_count = pci_msix_count(dev); 357c28220d8SAlexander Motin if (vmd_bypass_msi && (t->flags & CAN_BYPASS_MSI)) { 358c28220d8SAlexander Motin sc->vmd_msix_count = 0; 359c28220d8SAlexander Motin vmd_set_msi_bypass(dev, true); 360c28220d8SAlexander Motin } else if (pci_alloc_msix(dev, &sc->vmd_msix_count) == 0) { 361f2521a76SDoug Ambrisko sc->vmd_irq = malloc(sizeof(struct vmd_irq) * 3627af4475aSAlexander Motin sc->vmd_msix_count, M_DEVBUF, M_WAITOK | M_ZERO); 363f2521a76SDoug Ambrisko for (i = 0; i < sc->vmd_msix_count; i++) { 3647af4475aSAlexander Motin vi = &sc->vmd_irq[i]; 3657af4475aSAlexander Motin vi->vi_rid = i + 1; 3667af4475aSAlexander Motin vi->vi_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 3677af4475aSAlexander Motin &vi->vi_rid, RF_ACTIVE | RF_SHAREABLE); 3687af4475aSAlexander Motin if (vi->vi_res == NULL) { 3697af4475aSAlexander Motin device_printf(dev, "Failed to allocate irq\n"); 370f2521a76SDoug Ambrisko goto fail; 371f2521a76SDoug Ambrisko } 3727af4475aSAlexander Motin vi->vi_irq = rman_get_start(vi->vi_res); 3737af4475aSAlexander Motin if (bus_setup_intr(dev, vi->vi_res, INTR_TYPE_MISC | 3747af4475aSAlexander Motin INTR_MPSAFE, vmd_intr, NULL, vi, &vi->vi_handle)) { 3757af4475aSAlexander Motin device_printf(dev, "Can't set up interrupt\n"); 3767af4475aSAlexander Motin bus_release_resource(dev, SYS_RES_IRQ, 3777af4475aSAlexander Motin vi->vi_rid, vi->vi_res); 3787af4475aSAlexander Motin vi->vi_res = NULL; 379f2521a76SDoug Ambrisko goto fail; 380f2521a76SDoug Ambrisko } 381f2521a76SDoug Ambrisko } 382c28220d8SAlexander Motin vmd_set_msi_bypass(dev, false); 383f2521a76SDoug Ambrisko } 384f2521a76SDoug Ambrisko 3857af4475aSAlexander Motin sc->vmd_dma_tag = bus_get_dma_tag(dev); 386f2521a76SDoug Ambrisko 3877af4475aSAlexander Motin sc->psc.child = device_add_child(dev, "pci", -1); 3887af4475aSAlexander Motin return (bus_generic_attach(dev)); 389f2521a76SDoug Ambrisko 390f2521a76SDoug Ambrisko fail: 391f2521a76SDoug Ambrisko vmd_free(sc); 392f2521a76SDoug Ambrisko return (ENXIO); 393f2521a76SDoug Ambrisko } 394f2521a76SDoug Ambrisko 395f2521a76SDoug Ambrisko static int 396f2521a76SDoug Ambrisko vmd_detach(device_t dev) 397f2521a76SDoug Ambrisko { 3987af4475aSAlexander Motin struct vmd_softc *sc = device_get_softc(dev); 3997af4475aSAlexander Motin int error; 400f2521a76SDoug Ambrisko 4017af4475aSAlexander Motin error = bus_generic_detach(dev); 4027af4475aSAlexander Motin if (error) 4037af4475aSAlexander Motin return (error); 4047af4475aSAlexander Motin error = device_delete_children(dev); 4057af4475aSAlexander Motin if (error) 4067af4475aSAlexander Motin return (error); 407c28220d8SAlexander Motin if (sc->vmd_msix_count == 0) 408c28220d8SAlexander Motin vmd_set_msi_bypass(dev, false); 409f2521a76SDoug Ambrisko vmd_free(sc); 410f2521a76SDoug Ambrisko return (0); 411f2521a76SDoug Ambrisko } 412f2521a76SDoug Ambrisko 4137af4475aSAlexander Motin static bus_dma_tag_t 4147af4475aSAlexander Motin vmd_get_dma_tag(device_t dev, device_t child) 415f2521a76SDoug Ambrisko { 4167af4475aSAlexander Motin struct vmd_softc *sc = device_get_softc(dev); 417f2521a76SDoug Ambrisko 4187af4475aSAlexander Motin return (sc->vmd_dma_tag); 419f2521a76SDoug Ambrisko } 420f2521a76SDoug Ambrisko 421d714e73fSJohn Baldwin static struct rman * 422d714e73fSJohn Baldwin vmd_get_rman(device_t dev, int type, u_int flags) 423d714e73fSJohn Baldwin { 424d714e73fSJohn Baldwin struct vmd_softc *sc = device_get_softc(dev); 425d714e73fSJohn Baldwin 426d714e73fSJohn Baldwin switch (type) { 427d714e73fSJohn Baldwin case SYS_RES_MEMORY: 428d714e73fSJohn Baldwin return (&sc->psc.mem.rman); 429d714e73fSJohn Baldwin case PCI_RES_BUS: 430d714e73fSJohn Baldwin return (&sc->psc.bus.rman); 431d714e73fSJohn Baldwin default: 432d714e73fSJohn Baldwin /* VMD hardware does not support I/O ports. */ 433d714e73fSJohn Baldwin return (NULL); 434d714e73fSJohn Baldwin } 435d714e73fSJohn Baldwin } 436d714e73fSJohn Baldwin 437f2521a76SDoug Ambrisko static struct resource * 438f2521a76SDoug Ambrisko vmd_alloc_resource(device_t dev, device_t child, int type, int *rid, 439f2521a76SDoug Ambrisko rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 440f2521a76SDoug Ambrisko { 4417af4475aSAlexander Motin struct resource *res; 442f2521a76SDoug Ambrisko 443d714e73fSJohn Baldwin if (type == SYS_RES_IRQ) { 444b2c48aa4SGordon Bergling /* VMD hardware does not support legacy interrupts. */ 4457af4475aSAlexander Motin if (*rid == 0) 4467af4475aSAlexander Motin return (NULL); 4477af4475aSAlexander Motin return (bus_generic_alloc_resource(dev, child, type, rid, 4487af4475aSAlexander Motin start, end, count, flags | RF_SHAREABLE)); 449d714e73fSJohn Baldwin } 450d714e73fSJohn Baldwin res = bus_generic_rman_alloc_resource(dev, child, type, rid, start, 451d714e73fSJohn Baldwin end, count, flags); 452d714e73fSJohn Baldwin if (bootverbose && res != NULL) { 453d714e73fSJohn Baldwin switch (type) { 4547af4475aSAlexander Motin case SYS_RES_MEMORY: 4557af4475aSAlexander Motin device_printf(dev, 4567af4475aSAlexander Motin "allocated memory range (%#jx-%#jx) for rid %d of %s\n", 4577af4475aSAlexander Motin rman_get_start(res), rman_get_end(res), *rid, 4587af4475aSAlexander Motin pcib_child_name(child)); 4597af4475aSAlexander Motin break; 4607af4475aSAlexander Motin case PCI_RES_BUS: 4617af4475aSAlexander Motin device_printf(dev, 4627af4475aSAlexander Motin "allocated bus range (%ju-%ju) for rid %d of %s\n", 4637af4475aSAlexander Motin rman_get_start(res), rman_get_end(res), *rid, 4647af4475aSAlexander Motin pcib_child_name(child)); 4657af4475aSAlexander Motin break; 4667af4475aSAlexander Motin } 467d714e73fSJohn Baldwin } 4687af4475aSAlexander Motin return (res); 469f2521a76SDoug Ambrisko } 470f2521a76SDoug Ambrisko 471f2521a76SDoug Ambrisko static int 472fef01f04SJohn Baldwin vmd_adjust_resource(device_t dev, device_t child, 473f2521a76SDoug Ambrisko struct resource *r, rman_res_t start, rman_res_t end) 474f2521a76SDoug Ambrisko { 475f2521a76SDoug Ambrisko 476fef01f04SJohn Baldwin if (rman_get_type(r) == SYS_RES_IRQ) { 477fef01f04SJohn Baldwin return (bus_generic_adjust_resource(dev, child, r, start, end)); 4787af4475aSAlexander Motin } 479fef01f04SJohn Baldwin return (bus_generic_rman_adjust_resource(dev, child, r, start, end)); 480f2521a76SDoug Ambrisko } 481f2521a76SDoug Ambrisko 482f2521a76SDoug Ambrisko static int 483f2521a76SDoug Ambrisko vmd_release_resource(device_t dev, device_t child, int type, int rid, 484f2521a76SDoug Ambrisko struct resource *r) 485f2521a76SDoug Ambrisko { 4867af4475aSAlexander Motin 4877af4475aSAlexander Motin if (type == SYS_RES_IRQ) { 4887af4475aSAlexander Motin return (bus_generic_release_resource(dev, child, type, rid, 4897af4475aSAlexander Motin r)); 4907af4475aSAlexander Motin } 491d714e73fSJohn Baldwin return (bus_generic_rman_release_resource(dev, child, type, rid, r)); 492d714e73fSJohn Baldwin } 493d714e73fSJohn Baldwin 494d714e73fSJohn Baldwin static int 495*2baed46eSJohn Baldwin vmd_activate_resource(device_t dev, device_t child, struct resource *r) 496d714e73fSJohn Baldwin { 497*2baed46eSJohn Baldwin if (rman_get_type(r) == SYS_RES_IRQ) { 498*2baed46eSJohn Baldwin return (bus_generic_activate_resource(dev, child, r)); 499d714e73fSJohn Baldwin } 500*2baed46eSJohn Baldwin return (bus_generic_rman_activate_resource(dev, child, r)); 501d714e73fSJohn Baldwin } 502d714e73fSJohn Baldwin 503d714e73fSJohn Baldwin static int 504*2baed46eSJohn Baldwin vmd_deactivate_resource(device_t dev, device_t child, struct resource *r) 505d714e73fSJohn Baldwin { 506*2baed46eSJohn Baldwin if (rman_get_type(r) == SYS_RES_IRQ) { 507*2baed46eSJohn Baldwin return (bus_generic_deactivate_resource(dev, child, r)); 508d714e73fSJohn Baldwin } 509*2baed46eSJohn Baldwin return (bus_generic_rman_deactivate_resource(dev, child, r)); 510d714e73fSJohn Baldwin } 511d714e73fSJohn Baldwin 512d714e73fSJohn Baldwin static struct resource * 513d714e73fSJohn Baldwin vmd_find_parent_resource(struct vmd_softc *sc, struct resource *r) 514d714e73fSJohn Baldwin { 515d714e73fSJohn Baldwin for (int i = 1; i < 3; i++) { 516d714e73fSJohn Baldwin if (rman_get_start(sc->vmd_regs_res[i]) <= rman_get_start(r) && 517d714e73fSJohn Baldwin rman_get_end(sc->vmd_regs_res[i]) >= rman_get_end(r)) 518d714e73fSJohn Baldwin return (sc->vmd_regs_res[i]); 519d714e73fSJohn Baldwin } 520d714e73fSJohn Baldwin return (NULL); 521d714e73fSJohn Baldwin } 522d714e73fSJohn Baldwin 523d714e73fSJohn Baldwin static int 524d77f2092SJohn Baldwin vmd_map_resource(device_t dev, device_t child, struct resource *r, 525d714e73fSJohn Baldwin struct resource_map_request *argsp, struct resource_map *map) 526d714e73fSJohn Baldwin { 527d714e73fSJohn Baldwin struct vmd_softc *sc = device_get_softc(dev); 528d714e73fSJohn Baldwin struct resource_map_request args; 529d714e73fSJohn Baldwin struct resource *pres; 530d714e73fSJohn Baldwin rman_res_t length, start; 531d714e73fSJohn Baldwin int error; 532d714e73fSJohn Baldwin 533d714e73fSJohn Baldwin /* Resources must be active to be mapped. */ 534d714e73fSJohn Baldwin if (!(rman_get_flags(r) & RF_ACTIVE)) 535d714e73fSJohn Baldwin return (ENXIO); 536d714e73fSJohn Baldwin 537d714e73fSJohn Baldwin resource_init_map_request(&args); 538d714e73fSJohn Baldwin error = resource_validate_map_request(r, argsp, &args, &start, &length); 539d714e73fSJohn Baldwin if (error) 540d714e73fSJohn Baldwin return (error); 541d714e73fSJohn Baldwin 542d714e73fSJohn Baldwin pres = vmd_find_parent_resource(sc, r); 543d714e73fSJohn Baldwin if (pres == NULL) 544d714e73fSJohn Baldwin return (ENOENT); 545d714e73fSJohn Baldwin 546d714e73fSJohn Baldwin args.offset = start - rman_get_start(pres); 547d714e73fSJohn Baldwin args.length = length; 548d77f2092SJohn Baldwin return (bus_generic_map_resource(dev, child, pres, &args, map)); 549d714e73fSJohn Baldwin } 550d714e73fSJohn Baldwin 551d714e73fSJohn Baldwin static int 552d77f2092SJohn Baldwin vmd_unmap_resource(device_t dev, device_t child, struct resource *r, 553d714e73fSJohn Baldwin struct resource_map *map) 554d714e73fSJohn Baldwin { 555d714e73fSJohn Baldwin struct vmd_softc *sc = device_get_softc(dev); 556d714e73fSJohn Baldwin 557d714e73fSJohn Baldwin r = vmd_find_parent_resource(sc, r); 558d714e73fSJohn Baldwin if (r == NULL) 559d714e73fSJohn Baldwin return (ENOENT); 560d77f2092SJohn Baldwin return (bus_generic_unmap_resource(dev, child, r, map)); 561f2521a76SDoug Ambrisko } 562f2521a76SDoug Ambrisko 563f2521a76SDoug Ambrisko static int 5647af4475aSAlexander Motin vmd_route_interrupt(device_t dev, device_t child, int pin) 565f2521a76SDoug Ambrisko { 5667af4475aSAlexander Motin 567b2c48aa4SGordon Bergling /* VMD hardware does not support legacy interrupts. */ 5687af4475aSAlexander Motin return (PCI_INVALID_IRQ); 5697af4475aSAlexander Motin } 5707af4475aSAlexander Motin 5717af4475aSAlexander Motin static int 5727af4475aSAlexander Motin vmd_alloc_msi(device_t dev, device_t child, int count, int maxcount, 5737af4475aSAlexander Motin int *irqs) 5747af4475aSAlexander Motin { 5757af4475aSAlexander Motin struct vmd_softc *sc = device_get_softc(dev); 5767af4475aSAlexander Motin struct vmd_irq_user *u; 5777af4475aSAlexander Motin int i, ibest = 0, best = INT_MAX; 5787af4475aSAlexander Motin 579c28220d8SAlexander Motin if (sc->vmd_msix_count == 0) { 580c28220d8SAlexander Motin return (PCIB_ALLOC_MSI(device_get_parent(device_get_parent(dev)), 581c28220d8SAlexander Motin child, count, maxcount, irqs)); 582c28220d8SAlexander Motin } 583c28220d8SAlexander Motin 5847af4475aSAlexander Motin if (count > vmd_max_msi) 5857af4475aSAlexander Motin return (ENOSPC); 5867af4475aSAlexander Motin LIST_FOREACH(u, &sc->vmd_users, viu_link) { 5877af4475aSAlexander Motin if (u->viu_child == child) 5887af4475aSAlexander Motin return (EBUSY); 5897af4475aSAlexander Motin } 5907af4475aSAlexander Motin 5917af4475aSAlexander Motin for (i = sc->vmd_fist_vector; i < sc->vmd_msix_count; i++) { 5927af4475aSAlexander Motin if (best > sc->vmd_irq[i].vi_nusers) { 5937af4475aSAlexander Motin best = sc->vmd_irq[i].vi_nusers; 5947af4475aSAlexander Motin ibest = i; 5957af4475aSAlexander Motin } 5967af4475aSAlexander Motin } 5977af4475aSAlexander Motin 5987af4475aSAlexander Motin u = malloc(sizeof(*u), M_DEVBUF, M_WAITOK | M_ZERO); 5997af4475aSAlexander Motin u->viu_child = child; 6007af4475aSAlexander Motin u->viu_vector = ibest; 6017af4475aSAlexander Motin LIST_INSERT_HEAD(&sc->vmd_users, u, viu_link); 6027af4475aSAlexander Motin sc->vmd_irq[ibest].vi_nusers += count; 6037af4475aSAlexander Motin 6047af4475aSAlexander Motin for (i = 0; i < count; i++) 6057af4475aSAlexander Motin irqs[i] = sc->vmd_irq[ibest].vi_irq; 606f2521a76SDoug Ambrisko return (0); 607f2521a76SDoug Ambrisko } 608f2521a76SDoug Ambrisko 609f2521a76SDoug Ambrisko static int 6107af4475aSAlexander Motin vmd_release_msi(device_t dev, device_t child, int count, int *irqs) 611f2521a76SDoug Ambrisko { 6127af4475aSAlexander Motin struct vmd_softc *sc = device_get_softc(dev); 6137af4475aSAlexander Motin struct vmd_irq_user *u; 6147af4475aSAlexander Motin 615c28220d8SAlexander Motin if (sc->vmd_msix_count == 0) { 616c28220d8SAlexander Motin return (PCIB_RELEASE_MSI(device_get_parent(device_get_parent(dev)), 617c28220d8SAlexander Motin child, count, irqs)); 618c28220d8SAlexander Motin } 619c28220d8SAlexander Motin 6207af4475aSAlexander Motin LIST_FOREACH(u, &sc->vmd_users, viu_link) { 6217af4475aSAlexander Motin if (u->viu_child == child) { 6227af4475aSAlexander Motin sc->vmd_irq[u->viu_vector].vi_nusers -= count; 6237af4475aSAlexander Motin LIST_REMOVE(u, viu_link); 6247af4475aSAlexander Motin free(u, M_DEVBUF); 6257af4475aSAlexander Motin return (0); 6267af4475aSAlexander Motin } 6277af4475aSAlexander Motin } 6287af4475aSAlexander Motin return (EINVAL); 629f2521a76SDoug Ambrisko } 630f2521a76SDoug Ambrisko 631f2521a76SDoug Ambrisko static int 6327af4475aSAlexander Motin vmd_alloc_msix(device_t dev, device_t child, int *irq) 633f2521a76SDoug Ambrisko { 6347af4475aSAlexander Motin struct vmd_softc *sc = device_get_softc(dev); 6357af4475aSAlexander Motin struct vmd_irq_user *u; 6367af4475aSAlexander Motin int i, ibest = 0, best = INT_MAX; 637f2521a76SDoug Ambrisko 638c28220d8SAlexander Motin if (sc->vmd_msix_count == 0) { 639c28220d8SAlexander Motin return (PCIB_ALLOC_MSIX(device_get_parent(device_get_parent(dev)), 640c28220d8SAlexander Motin child, irq)); 641c28220d8SAlexander Motin } 642c28220d8SAlexander Motin 643f2521a76SDoug Ambrisko i = 0; 6447af4475aSAlexander Motin LIST_FOREACH(u, &sc->vmd_users, viu_link) { 6457af4475aSAlexander Motin if (u->viu_child == child) 6467af4475aSAlexander Motin i++; 6477af4475aSAlexander Motin } 6487af4475aSAlexander Motin if (i >= vmd_max_msix) 6497af4475aSAlexander Motin return (ENOSPC); 650f2521a76SDoug Ambrisko 6517af4475aSAlexander Motin for (i = sc->vmd_fist_vector; i < sc->vmd_msix_count; i++) { 6527af4475aSAlexander Motin if (best > sc->vmd_irq[i].vi_nusers) { 6537af4475aSAlexander Motin best = sc->vmd_irq[i].vi_nusers; 6547af4475aSAlexander Motin ibest = i; 6557af4475aSAlexander Motin } 6567af4475aSAlexander Motin } 6577af4475aSAlexander Motin 6587af4475aSAlexander Motin u = malloc(sizeof(*u), M_DEVBUF, M_WAITOK | M_ZERO); 6597af4475aSAlexander Motin u->viu_child = child; 6607af4475aSAlexander Motin u->viu_vector = ibest; 6617af4475aSAlexander Motin LIST_INSERT_HEAD(&sc->vmd_users, u, viu_link); 6627af4475aSAlexander Motin sc->vmd_irq[ibest].vi_nusers++; 6637af4475aSAlexander Motin 6647af4475aSAlexander Motin *irq = sc->vmd_irq[ibest].vi_irq; 6657af4475aSAlexander Motin return (0); 666f2521a76SDoug Ambrisko } 667f2521a76SDoug Ambrisko 668f2521a76SDoug Ambrisko static int 6697af4475aSAlexander Motin vmd_release_msix(device_t dev, device_t child, int irq) 670f2521a76SDoug Ambrisko { 6717af4475aSAlexander Motin struct vmd_softc *sc = device_get_softc(dev); 6727af4475aSAlexander Motin struct vmd_irq_user *u; 673f2521a76SDoug Ambrisko 674c28220d8SAlexander Motin if (sc->vmd_msix_count == 0) { 675c28220d8SAlexander Motin return (PCIB_RELEASE_MSIX(device_get_parent(device_get_parent(dev)), 676c28220d8SAlexander Motin child, irq)); 677c28220d8SAlexander Motin } 678c28220d8SAlexander Motin 6797af4475aSAlexander Motin LIST_FOREACH(u, &sc->vmd_users, viu_link) { 6807af4475aSAlexander Motin if (u->viu_child == child && 6817af4475aSAlexander Motin sc->vmd_irq[u->viu_vector].vi_irq == irq) { 6827af4475aSAlexander Motin sc->vmd_irq[u->viu_vector].vi_nusers--; 6837af4475aSAlexander Motin LIST_REMOVE(u, viu_link); 6847af4475aSAlexander Motin free(u, M_DEVBUF); 6857af4475aSAlexander Motin return (0); 686f2521a76SDoug Ambrisko } 687f2521a76SDoug Ambrisko } 6887af4475aSAlexander Motin return (EINVAL); 6897af4475aSAlexander Motin } 690f2521a76SDoug Ambrisko 6917af4475aSAlexander Motin static int 6927af4475aSAlexander Motin vmd_map_msi(device_t dev, device_t child, int irq, uint64_t *addr, uint32_t *data) 6937af4475aSAlexander Motin { 6947af4475aSAlexander Motin struct vmd_softc *sc = device_get_softc(dev); 6957af4475aSAlexander Motin int i; 6967af4475aSAlexander Motin 697c28220d8SAlexander Motin if (sc->vmd_msix_count == 0) { 698c28220d8SAlexander Motin return (PCIB_MAP_MSI(device_get_parent(device_get_parent(dev)), 699c28220d8SAlexander Motin child, irq, addr, data)); 700c28220d8SAlexander Motin } 701c28220d8SAlexander Motin 7027af4475aSAlexander Motin for (i = sc->vmd_fist_vector; i < sc->vmd_msix_count; i++) { 7037af4475aSAlexander Motin if (sc->vmd_irq[i].vi_irq == irq) 7047af4475aSAlexander Motin break; 7057af4475aSAlexander Motin } 7067af4475aSAlexander Motin if (i >= sc->vmd_msix_count) 7077af4475aSAlexander Motin return (EINVAL); 7087af4475aSAlexander Motin *addr = MSI_INTEL_ADDR_BASE | (i << 12); 7097af4475aSAlexander Motin *data = 0; 7107af4475aSAlexander Motin return (0); 711f2521a76SDoug Ambrisko } 712f2521a76SDoug Ambrisko 713f2521a76SDoug Ambrisko static device_method_t vmd_pci_methods[] = { 714f2521a76SDoug Ambrisko /* Device interface */ 715f2521a76SDoug Ambrisko DEVMETHOD(device_probe, vmd_probe), 716f2521a76SDoug Ambrisko DEVMETHOD(device_attach, vmd_attach), 717f2521a76SDoug Ambrisko DEVMETHOD(device_detach, vmd_detach), 7187af4475aSAlexander Motin DEVMETHOD(device_suspend, bus_generic_suspend), 7197af4475aSAlexander Motin DEVMETHOD(device_resume, bus_generic_resume), 7207af4475aSAlexander Motin DEVMETHOD(device_shutdown, bus_generic_shutdown), 721f2521a76SDoug Ambrisko 722f2521a76SDoug Ambrisko /* Bus interface */ 7237af4475aSAlexander Motin DEVMETHOD(bus_get_dma_tag, vmd_get_dma_tag), 724d714e73fSJohn Baldwin DEVMETHOD(bus_get_rman, vmd_get_rman), 725f2521a76SDoug Ambrisko DEVMETHOD(bus_read_ivar, pcib_read_ivar), 726f2521a76SDoug Ambrisko DEVMETHOD(bus_write_ivar, pcib_write_ivar), 727f2521a76SDoug Ambrisko DEVMETHOD(bus_alloc_resource, vmd_alloc_resource), 728f2521a76SDoug Ambrisko DEVMETHOD(bus_adjust_resource, vmd_adjust_resource), 729f2521a76SDoug Ambrisko DEVMETHOD(bus_release_resource, vmd_release_resource), 730d714e73fSJohn Baldwin DEVMETHOD(bus_activate_resource, vmd_activate_resource), 731d714e73fSJohn Baldwin DEVMETHOD(bus_deactivate_resource, vmd_deactivate_resource), 732d714e73fSJohn Baldwin DEVMETHOD(bus_map_resource, vmd_map_resource), 733d714e73fSJohn Baldwin DEVMETHOD(bus_unmap_resource, vmd_unmap_resource), 7347af4475aSAlexander Motin DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 7357af4475aSAlexander Motin DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 736f2521a76SDoug Ambrisko 737f2521a76SDoug Ambrisko /* pcib interface */ 738f2521a76SDoug Ambrisko DEVMETHOD(pcib_maxslots, pcib_maxslots), 739f2521a76SDoug Ambrisko DEVMETHOD(pcib_read_config, vmd_read_config), 740f2521a76SDoug Ambrisko DEVMETHOD(pcib_write_config, vmd_write_config), 7417af4475aSAlexander Motin DEVMETHOD(pcib_route_interrupt, vmd_route_interrupt), 7427af4475aSAlexander Motin DEVMETHOD(pcib_alloc_msi, vmd_alloc_msi), 7437af4475aSAlexander Motin DEVMETHOD(pcib_release_msi, vmd_release_msi), 744f2521a76SDoug Ambrisko DEVMETHOD(pcib_alloc_msix, vmd_alloc_msix), 7457af4475aSAlexander Motin DEVMETHOD(pcib_release_msix, vmd_release_msix), 7467af4475aSAlexander Motin DEVMETHOD(pcib_map_msi, vmd_map_msi), 7477af4475aSAlexander Motin DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), 748f2521a76SDoug Ambrisko 749f2521a76SDoug Ambrisko DEVMETHOD_END 750f2521a76SDoug Ambrisko }; 751f2521a76SDoug Ambrisko 7527af4475aSAlexander Motin DEFINE_CLASS_0(pcib, vmd_pci_driver, vmd_pci_methods, sizeof(struct vmd_softc)); 75344031900SJohn Baldwin DRIVER_MODULE(vmd, pci, vmd_pci_driver, NULL, NULL); 754f2521a76SDoug Ambrisko MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, vmd, 755f2521a76SDoug Ambrisko vmd_devs, nitems(vmd_devs) - 1); 756