]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/vmd/vmd.c
MFV r353558: 10572 10579 Fix race in dnode_check_slots_free()
[FreeBSD/FreeBSD.git] / sys / dev / vmd / vmd.c
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
320         sc->vmd_btag = rman_get_bustag(sc->vmd_regs_resource[0]);
321         sc->vmd_bhandle = rman_get_bushandle(sc->vmd_regs_resource[0]);
322
323         pci_write_config(dev, PCIR_PRIBUS_2,
324             pcib_get_bus(device_get_parent(dev)), 1);
325
326         sec_reg = PCIR_SECBUS_1;
327         bus = &sc->vmd_bus;
328         bus->sub_reg = PCIR_SUBBUS_1;
329         bus->sec = vmd_read_config(dev, b, s, f, sec_reg, 1);
330         bus->sub = vmd_read_config(dev, b, s, f, bus->sub_reg, 1);
331         bus->dev = dev;
332         bus->rman.rm_start = 0;
333         bus->rman.rm_end = PCI_BUSMAX;
334         bus->rman.rm_type = RMAN_ARRAY;
335         snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev));
336         bus->rman.rm_descr = strdup(buf, M_DEVBUF);
337         error = rman_init(&bus->rman);
338
339         if (error) {
340                 device_printf(dev, "Failed to initialize %s bus number rman\n",
341                     device_get_nameunit(dev));
342                 goto fail;
343         }
344
345         /*
346          * Allocate a bus range.  This will return an existing bus range
347          * if one exists, or a new bus range if one does not.
348          */
349         rid = 0;
350         bus->res = bus_alloc_resource_anywhere(dev, PCI_RES_BUS, &rid,
351             min_count, 0);
352         if (bus->res == NULL) {
353                 /*
354                  * Fall back to just allocating a range of a single bus
355                  * number.
356                  */
357                 bus->res = bus_alloc_resource_anywhere(dev, PCI_RES_BUS, &rid,
358                     1, 0);
359         } else if (rman_get_size(bus->res) < min_count) {
360                 /*
361                  * Attempt to grow the existing range to satisfy the
362                  * minimum desired count.
363                  */
364                 (void)bus_adjust_resource(dev, PCI_RES_BUS, bus->res,
365                     rman_get_start(bus->res), rman_get_start(bus->res) +
366                     min_count - 1);
367         }
368
369
370         /*
371          * Add the initial resource to the rman.
372          */
373         if (bus->res != NULL) {
374                 error = rman_manage_region(&bus->rman, rman_get_start(bus->res),
375                     rman_get_end(bus->res));
376                 if (error) {
377                         device_printf(dev, "Failed to add resource to rman\n");
378                         goto fail;
379                 }
380                 bus->sec = rman_get_start(bus->res);
381                 bus->sub = rman_get_end(bus->res);
382         }
383
384         sc->vmd_msix_count = pci_msix_count(dev);
385         if (pci_alloc_msix(dev, &sc->vmd_msix_count) == 0) {
386                 sc->vmd_irq = malloc(sizeof(struct vmd_irq) *
387                     sc->vmd_msix_count,
388                     M_DEVBUF, M_WAITOK | M_ZERO);
389
390                 for (i = 0; i < sc->vmd_msix_count; i++) {
391                         sc->vmd_irq[i].vmd_rid = i + 1;
392                         sc->vmd_irq[i].vmd_sc = sc;
393                         sc->vmd_irq[i].vmd_instance = i;
394                         sc->vmd_irq[i].vmd_res = bus_alloc_resource_any(dev,
395                             SYS_RES_IRQ, &sc->vmd_irq[i].vmd_rid,
396                             RF_ACTIVE);
397                         if (sc->vmd_irq[i].vmd_res == NULL) {
398                                 device_printf(dev,"Failed to alloc irq\n");
399                                 goto fail;
400                         }
401
402                         TAILQ_INIT(&sc->vmd_irq[i].vmd_list);
403                         if (bus_setup_intr(dev, sc->vmd_irq[i].vmd_res,
404                             INTR_TYPE_MISC | INTR_MPSAFE, NULL, vmd_intr,
405                             &sc->vmd_irq[i], &sc->vmd_irq[i].vmd_handle)) {
406                                 device_printf(sc->vmd_dev,
407                                     "Cannot set up interrupt\n");
408                                 sc->vmd_irq[i].vmd_res = NULL;
409                                 goto fail;
410                         }
411                 }
412         }
413
414         sc->vmd_child = device_add_child(dev, NULL, -1);
415
416         if (sc->vmd_child == NULL) {
417                 device_printf(dev, "Failed to attach child\n");
418                 goto fail;
419         }
420
421         error = device_probe_and_attach(sc->vmd_child);
422         if (error) {
423                 device_printf(dev, "Failed to add probe child\n");
424                 goto fail;
425         }
426
427
428         return (0);
429
430 fail:
431         vmd_free(sc);
432         return (ENXIO);
433 }
434
435 static int
436 vmd_detach(device_t dev)
437 {
438         struct vmd_softc *sc;
439         int err;
440
441         sc = device_get_softc(dev);
442         if (sc->vmd_child != NULL) {
443                 err = bus_generic_detach(sc->vmd_child);
444                 if (err)
445                         return (err);
446                 err = device_delete_child(dev, sc->vmd_child);
447                 if (err)
448                         return (err);
449         }
450         if (sc->vmd_bus.rman.rm_end != 0)
451                 rman_fini(&sc->vmd_bus.rman);
452
453         vmd_free(sc);
454         return (0);
455 }
456
457 /* Pass request to alloc an MSI-X message up to the parent bridge. */
458 static int
459 vmd_alloc_msix(device_t pcib, device_t dev, int *irq)
460 {
461         struct vmd_softc *sc = device_get_softc(pcib);
462         device_t bus;
463         int ret;
464
465         if (sc->vmd_flags & PCIB_DISABLE_MSIX)
466                 return (ENXIO);
467         bus = device_get_parent(pcib);
468         ret = PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq);
469         return (ret);
470 }
471
472 static struct resource *
473 vmd_alloc_resource(device_t dev, device_t child, int type, int *rid,
474     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
475 {
476         /* Start at max PCI vmd_domain and work down */
477         if (type == PCI_RES_BUS) {
478                 return (pci_domain_alloc_bus(PCI_DOMAINMAX -
479                     device_get_unit(dev), child, rid, start, end,
480                     count, flags));
481         }
482
483         return (pcib_alloc_resource(dev, child, type, rid, start, end,
484                                     count, flags));
485 }
486
487 static int
488 vmd_adjust_resource(device_t dev, device_t child, int type,
489     struct resource *r, rman_res_t start, rman_res_t end)
490 {
491         struct resource *res = r;
492
493         if (type == PCI_RES_BUS)
494                 return (pci_domain_adjust_bus(PCI_DOMAINMAX -
495                         device_get_unit(dev), child, res, start, end));
496         return (pcib_adjust_resource(dev, child, type, res, start, end));
497 }
498
499 static int
500 vmd_release_resource(device_t dev, device_t child, int type, int rid,
501     struct resource *r)
502 {
503         if (type == PCI_RES_BUS)
504                 return (pci_domain_release_bus(PCI_DOMAINMAX -
505                     device_get_unit(dev), child, rid, r));
506         return (pcib_release_resource(dev, child, type, rid, r));
507 }
508
509 static int
510 vmd_shutdown(device_t dev)
511 {
512         return (0);
513 }
514
515 static int
516 vmd_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
517 {
518         return (pcib_route_interrupt(pcib, dev, pin));
519 }
520
521
522 static int
523 vmd_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount,
524     int *irqs)
525 {
526         return (pcib_alloc_msi(pcib, dev, count, maxcount, irqs));
527 }
528
529 static int
530 vmd_pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs)
531 {
532
533         return (pcib_release_msi(pcib, dev, count, irqs));
534 }
535
536 static int
537 vmd_pcib_release_msix(device_t pcib, device_t dev, int irq) {
538         return  pcib_release_msix(pcib, dev, irq);
539 }
540
541 static int
542 vmd_setup_intr(device_t dev, device_t child, struct resource *irq,
543     int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
544     void **cookiep)
545 {
546         struct vmd_irq_handler *elm;
547         struct vmd_softc *sc;
548         int i;
549
550         sc = device_get_softc(dev);
551
552         /*
553          * There appears to be no steering of VMD interrupts from device
554          * to VMD interrupt
555          */
556
557         i = 0;
558         elm = malloc(sizeof(*elm), M_DEVBUF, M_NOWAIT|M_ZERO);
559         elm->vmd_child = child;
560         elm->vmd_intr = intr;
561         elm->vmd_rid = rman_get_rid(irq);
562         elm->vmd_arg = arg;
563         TAILQ_INSERT_TAIL(&sc->vmd_irq[i].vmd_list, elm, vmd_link);
564
565         return (bus_generic_setup_intr(dev, child, irq, flags, filter, intr,
566             arg, cookiep));
567 }
568
569 static int
570 vmd_teardown_intr(device_t dev, device_t child, struct resource *irq,
571     void *cookie)
572 {
573         struct vmd_irq_handler *elm, *tmp;;
574         struct vmd_softc *sc;
575
576         sc = device_get_softc(dev);
577         TAILQ_FOREACH_SAFE(elm, &sc->vmd_irq[0].vmd_list, vmd_link, tmp) {
578                 if (elm->vmd_child == child &&
579                     elm->vmd_rid == rman_get_rid(irq)) {
580                         TAILQ_REMOVE(&sc->vmd_irq[0].vmd_list, elm, vmd_link);
581                         free(elm, M_DEVBUF);
582                 }
583         }
584
585         return (bus_generic_teardown_intr(dev, child, irq, cookie));
586 }
587
588 static device_method_t vmd_pci_methods[] = {
589         /* Device interface */
590         DEVMETHOD(device_probe,                 vmd_probe),
591         DEVMETHOD(device_attach,                vmd_attach),
592         DEVMETHOD(device_detach,                vmd_detach),
593         DEVMETHOD(device_shutdown,              vmd_shutdown),
594
595         /* Bus interface */
596         DEVMETHOD(bus_read_ivar,                pcib_read_ivar),
597         DEVMETHOD(bus_write_ivar,               pcib_write_ivar),
598         DEVMETHOD(bus_alloc_resource,           vmd_alloc_resource),
599         DEVMETHOD(bus_adjust_resource,          vmd_adjust_resource),
600         DEVMETHOD(bus_release_resource,         vmd_release_resource),
601         DEVMETHOD(bus_activate_resource,        bus_generic_activate_resource),
602         DEVMETHOD(bus_deactivate_resource,      bus_generic_deactivate_resource),
603         DEVMETHOD(bus_setup_intr,               vmd_setup_intr),
604         DEVMETHOD(bus_teardown_intr,            vmd_teardown_intr),
605
606         /* pci interface */
607         DEVMETHOD(pci_read_config,              vmd_pci_read_config),
608         DEVMETHOD(pci_write_config,             vmd_pci_write_config),
609         DEVMETHOD(pci_alloc_devinfo,            vmd_alloc_devinfo),
610
611         /* pcib interface */
612         DEVMETHOD(pcib_maxslots,                pcib_maxslots),
613         DEVMETHOD(pcib_read_config,             vmd_read_config),
614         DEVMETHOD(pcib_write_config,            vmd_write_config),
615         DEVMETHOD(pcib_route_interrupt,         vmd_pcib_route_interrupt),
616         DEVMETHOD(pcib_alloc_msi,               vmd_pcib_alloc_msi),
617         DEVMETHOD(pcib_release_msi,             vmd_pcib_release_msi),
618         DEVMETHOD(pcib_alloc_msix,              vmd_alloc_msix),
619         DEVMETHOD(pcib_release_msix,            vmd_pcib_release_msix),
620         DEVMETHOD(pcib_map_msi,                 pcib_map_msi),
621
622         DEVMETHOD_END
623 };
624
625 static devclass_t vmd_devclass;
626
627 DEFINE_CLASS_0(vmd, vmd_pci_driver, vmd_pci_methods, sizeof(struct vmd_softc));
628 DRIVER_MODULE(vmd, pci, vmd_pci_driver, vmd_devclass, NULL, NULL);
629 MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, vmd,
630     vmd_devs, nitems(vmd_devs) - 1);
631 MODULE_DEPEND(vmd, vmd_bus, 1, 1, 1);