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