]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/xen/pcifront/pcifront.c
dev/xen: clean up empty lines in .c and .h files
[FreeBSD/FreeBSD.git] / sys / dev / xen / pcifront / pcifront.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2006, 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  *
11  * 1. Redistributions of source code must retain the above copyright 
12  *    notice, this list of conditions and the following disclaimer. 
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  * 3. Neither the name of Cisco Systems, Inc. nor the names of its contributors 
17  *    may be used to endorse or promote products derived from this software 
18  *    without specific prior written permission. 
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/module.h>
38 #include <sys/systm.h>
39 #include <sys/mbuf.h>
40 #include <sys/malloc.h>
41 #include <sys/kernel.h>
42 #include <sys/socket.h>
43 #include <sys/queue.h>
44
45 #include <machine/vmparam.h>
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48
49 #include <machine/bus.h>
50 #include <machine/resource.h>
51 #include <machine/frame.h>
52
53 #include <sys/bus.h>
54 #include <sys/rman.h>
55
56 #include <machine/intr_machdep.h>
57
58 #include <machine/xen-os.h>
59 #include <machine/hypervisor.h>
60 #include <machine/hypervisor-ifs.h>
61 #include <machine/xen_intr.h>
62 #include <machine/evtchn.h>
63 #include <machine/xenbus.h>
64 #include <machine/gnttab.h>
65 #include <machine/xen-public/memory.h>
66 #include <machine/xen-public/io/pciif.h>
67
68 #include <sys/pciio.h>
69 #include <dev/pci/pcivar.h>
70 #include "pcib_if.h"
71
72 #ifdef XEN_PCIDEV_FE_DEBUG
73 #define DPRINTF(fmt, args...) \
74     printf("pcifront (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args)
75 #else
76 #define DPRINTF(fmt, args...) ((void)0)
77 #endif
78 #define WPRINTF(fmt, args...) \
79     printf("pcifront (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args)
80
81 #define INVALID_GRANT_REF (0)
82 #define INVALID_EVTCHN    (-1)
83 #define virt_to_mfn(x) (vtophys(x) >> PAGE_SHIFT)
84
85 struct pcifront_device {
86         STAILQ_ENTRY(pcifront_device) next;
87
88         struct xenbus_device *xdev;
89
90         int unit;
91         int evtchn;
92         int gnt_ref;
93
94         /* Lock this when doing any operations in sh_info */
95         struct mtx sh_info_lock;
96         struct xen_pci_sharedinfo *sh_info;
97
98         device_t ndev;
99
100         int ref_cnt;
101 };
102
103 static STAILQ_HEAD(pcifront_dlist, pcifront_device) pdev_list = STAILQ_HEAD_INITIALIZER(pdev_list);
104
105 struct xpcib_softc {
106         int domain;
107         int bus;
108         struct pcifront_device *pdev;
109 };
110
111 /* Allocate a PCI device structure */
112 static struct pcifront_device *
113 alloc_pdev(struct xenbus_device *xdev)
114 {
115         struct pcifront_device *pdev = NULL;
116         int err, unit;
117
118         err = sscanf(xdev->nodename, "device/pci/%d", &unit);
119         if (err != 1) {
120                 if (err == 0)
121                         err = -EINVAL;
122                 xenbus_dev_fatal(pdev->xdev, err, "Error scanning pci device instance number");
123                 goto out;
124         }
125
126         pdev = (struct pcifront_device *)malloc(sizeof(struct pcifront_device), M_DEVBUF, M_NOWAIT);
127         if (pdev == NULL) {
128                 err = -ENOMEM;
129                 xenbus_dev_fatal(xdev, err, "Error allocating pcifront_device struct");
130                 goto out;
131         }
132         pdev->unit = unit;
133         pdev->xdev = xdev;
134         pdev->ref_cnt = 1;
135
136         pdev->sh_info = (struct xen_pci_sharedinfo *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT);
137         if (pdev->sh_info == NULL) {
138                 free(pdev, M_DEVBUF);
139                 pdev = NULL;
140                 err = -ENOMEM;
141                 xenbus_dev_fatal(xdev, err, "Error allocating sh_info struct");
142                 goto out;
143         }
144         pdev->sh_info->flags = 0;
145
146         xdev->data = pdev;
147
148         mtx_init(&pdev->sh_info_lock, "info_lock", "pci shared dev info lock", MTX_DEF);
149
150         pdev->evtchn = INVALID_EVTCHN;
151         pdev->gnt_ref = INVALID_GRANT_REF;
152
153         STAILQ_INSERT_TAIL(&pdev_list, pdev, next);
154
155         DPRINTF("Allocated pdev @ 0x%p (unit=%d)\n", pdev, unit);
156
157  out:
158         return pdev;
159 }
160
161 /* Hold a reference to a pcifront device */
162 static void
163 get_pdev(struct pcifront_device *pdev)
164 {
165         pdev->ref_cnt++;
166 }
167
168 /* Release a reference to a pcifront device */
169 static void
170 put_pdev(struct pcifront_device *pdev)
171 {
172         if (--pdev->ref_cnt > 0)
173                 return;
174
175         DPRINTF("freeing pdev @ 0x%p (ref_cnt=%d)\n", pdev, pdev->ref_cnt);
176
177         if (pdev->evtchn != INVALID_EVTCHN)
178                 xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
179
180         if (pdev->gnt_ref != INVALID_GRANT_REF)
181                 gnttab_end_foreign_access(pdev->gnt_ref, 0, (void *)pdev->sh_info);
182
183         pdev->xdev->data = NULL;
184
185         free(pdev, M_DEVBUF);
186 }
187
188 /* Write to the xenbus info needed by backend */
189 static int
190 pcifront_publish_info(struct pcifront_device *pdev)
191 {
192         int err = 0;
193         struct xenbus_transaction *trans;
194
195         err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
196         if (err < 0) {
197                 WPRINTF("error granting access to ring page\n");
198                 goto out;
199         }
200
201         pdev->gnt_ref = err;
202
203         err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
204         if (err)
205                 goto out;
206
207  do_publish:
208         trans = xenbus_transaction_start();
209         if (IS_ERR(trans)) {
210                 xenbus_dev_fatal(pdev->xdev, err,
211                                                  "Error writing configuration for backend "
212                                                  "(start transaction)");
213                 goto out;
214         }
215
216         err = xenbus_printf(trans, pdev->xdev->nodename,
217                                                 "pci-op-ref", "%u", pdev->gnt_ref);
218         if (!err)
219                 err = xenbus_printf(trans, pdev->xdev->nodename,
220                                                         "event-channel", "%u", pdev->evtchn);
221         if (!err)
222                 err = xenbus_printf(trans, pdev->xdev->nodename,
223                                                         "magic", XEN_PCI_MAGIC);
224         if (!err)
225                 err = xenbus_switch_state(pdev->xdev, trans,
226                                                                   XenbusStateInitialised);
227
228         if (err) {
229                 xenbus_transaction_end(trans, 1);
230                 xenbus_dev_fatal(pdev->xdev, err,
231                                                  "Error writing configuration for backend");
232                 goto out;
233         } else {
234                 err = xenbus_transaction_end(trans, 0);
235                 if (err == -EAGAIN)
236                         goto do_publish;
237                 else if (err) {
238                         xenbus_dev_fatal(pdev->xdev, err,
239                                                          "Error completing transaction for backend");
240                         goto out;
241                 }
242         }
243
244  out:
245         return err;
246 }
247
248 /* The backend is now connected so complete the connection process on our side */
249 static int
250 pcifront_connect(struct pcifront_device *pdev)
251 {
252         device_t nexus;
253         devclass_t nexus_devclass;
254
255         /* We will add our device as a child of the nexus0 device */
256         if (!(nexus_devclass = devclass_find("nexus")) ||
257                 !(nexus = devclass_get_device(nexus_devclass, 0))) {
258                 WPRINTF("could not find nexus0!\n");
259                 return -1;
260         }
261
262         /* Create a newbus device representing this frontend instance */
263         pdev->ndev = BUS_ADD_CHILD(nexus, 0, "xpcife", pdev->unit);
264         if (!pdev->ndev) {
265                 WPRINTF("could not create xpcife%d!\n", pdev->unit);
266                 return -EFAULT;
267         }
268         get_pdev(pdev);
269         device_set_ivars(pdev->ndev, pdev);
270
271         /* Good to go connected now */
272         xenbus_switch_state(pdev->xdev, NULL, XenbusStateConnected);
273
274         printf("pcifront: connected to %s\n", pdev->xdev->nodename);
275
276         mtx_lock(&Giant);
277         device_probe_and_attach(pdev->ndev);
278         mtx_unlock(&Giant);
279
280         return 0;
281 }
282
283 /* The backend is closing so process a disconnect */
284 static int
285 pcifront_disconnect(struct pcifront_device *pdev)
286 {
287         int err = 0;
288         XenbusState prev_state;
289
290         prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
291
292         if (prev_state < XenbusStateClosing) {
293                 err = xenbus_switch_state(pdev->xdev, NULL, XenbusStateClosing);
294                 if (!err && prev_state == XenbusStateConnected) {
295                         /* TODO - need to detach the newbus devices */
296                 }
297         }
298
299         return err;
300 }
301
302 /* Process a probe from the xenbus */
303 static int
304 pcifront_probe(struct xenbus_device *xdev,
305                            const struct xenbus_device_id *id)
306 {
307         int err = 0;
308         struct pcifront_device *pdev;
309
310         DPRINTF("xenbus probing\n");
311
312         if ((pdev = alloc_pdev(xdev)) == NULL)
313                 goto out;
314
315         err = pcifront_publish_info(pdev);
316
317  out:
318         if (err)
319                 put_pdev(pdev);
320         return err;
321 }
322
323 /* Remove the xenbus PCI device */
324 static int
325 pcifront_remove(struct xenbus_device *xdev)
326 {
327         DPRINTF("removing xenbus device node (%s)\n", xdev->nodename);
328         if (xdev->data)
329                 put_pdev(xdev->data);
330         return 0;
331 }
332
333 /* Called by xenbus when our backend node changes state */
334 static void
335 pcifront_backend_changed(struct xenbus_device *xdev,
336                                                  XenbusState be_state)
337 {
338         struct pcifront_device *pdev = xdev->data;
339
340         switch (be_state) {
341         case XenbusStateClosing:
342                 DPRINTF("backend closing (%s)\n", xdev->nodename);
343                 pcifront_disconnect(pdev);
344                 break;
345
346         case XenbusStateClosed:
347                 DPRINTF("backend closed (%s)\n", xdev->nodename);
348                 pcifront_disconnect(pdev);
349                 break;
350
351         case XenbusStateConnected:
352                 DPRINTF("backend connected (%s)\n", xdev->nodename);
353                 pcifront_connect(pdev);
354                 break;
355                 
356         default:
357                 break;
358         }
359 }
360
361 /* Process PCI operation */
362 static int
363 do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
364 {
365         int err = 0;
366         struct xen_pci_op *active_op = &pdev->sh_info->op;
367         evtchn_port_t port = pdev->evtchn;
368         time_t timeout;
369
370         mtx_lock(&pdev->sh_info_lock);
371
372         memcpy(active_op, op, sizeof(struct xen_pci_op));
373
374         /* Go */
375         wmb();
376         set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
377         notify_remote_via_evtchn(port);
378
379         timeout = time_uptime + 2;
380
381         clear_evtchn(port);
382
383         /* Spin while waiting for the answer */
384         while (test_bit
385                (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
386                 int err = HYPERVISOR_poll(&port, 1, 3 * hz);
387                 if (err)
388                         panic("Failed HYPERVISOR_poll: err=%d", err);
389                 clear_evtchn(port);
390                 if (time_uptime > timeout) {
391                         WPRINTF("pciback not responding!!!\n");
392                         clear_bit(_XEN_PCIF_active,
393                                   (unsigned long *)&pdev->sh_info->flags);
394                         err = XEN_PCI_ERR_dev_not_found;
395                         goto out;
396                 }
397         }
398
399         memcpy(op, active_op, sizeof(struct xen_pci_op));
400
401         err = op->err;
402  out:
403         mtx_unlock(&pdev->sh_info_lock);
404         return err;
405 }
406
407 /* ** XenBus Driver registration ** */
408
409 static struct xenbus_device_id pcifront_ids[] = {
410         { "pci" },
411         { "" }
412 };
413
414 static struct xenbus_driver pcifront = {
415         .name = "pcifront",
416         .ids = pcifront_ids,
417         .probe = pcifront_probe,
418         .remove = pcifront_remove,
419         .otherend_changed = pcifront_backend_changed,
420 };
421
422 /* Register the driver with xenbus during sys init */
423 static void
424 pcifront_init(void *unused)
425 {
426         if ((xen_start_info->flags & SIF_INITDOMAIN))
427                 return;
428
429         DPRINTF("xenbus registering\n");
430
431         xenbus_register_frontend(&pcifront);
432 }
433
434 SYSINIT(pciif, SI_SUB_PSEUDO, SI_ORDER_ANY, pcifront_init, NULL)
435
436 /* Newbus xpcife device driver probe */
437 static int
438 xpcife_probe(device_t dev)
439 {
440 #ifdef XEN_PCIDEV_FE_DEBUG
441         struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(dev);
442         DPRINTF("xpcife probe (unit=%d)\n", pdev->unit);
443 #endif
444         return (BUS_PROBE_NOWILDCARD);
445 }
446
447 /* Newbus xpcife device driver attach */
448 static int
449 xpcife_attach(device_t dev) 
450 {
451         struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(dev);
452         int i, num_roots, len, err;
453         char str[64];
454         unsigned int domain, bus;
455
456         DPRINTF("xpcife attach (unit=%d)\n", pdev->unit);
457
458         err = xenbus_scanf(NULL, pdev->xdev->otherend,
459                                            "root_num", "%d", &num_roots);
460         if (err != 1) {
461                 if (err == 0)
462                         err = -EINVAL;
463                 xenbus_dev_fatal(pdev->xdev, err,
464                                                  "Error reading number of PCI roots");
465                 goto out;
466         }
467
468         /* Add a pcib device for each root */
469         for (i = 0; i < num_roots; i++) {
470                 device_t child;
471
472                 len = snprintf(str, sizeof(str), "root-%d", i);
473                 if (unlikely(len >= (sizeof(str) - 1))) {
474                         err = -ENOMEM;
475                         goto out;
476                 }
477
478                 err = xenbus_scanf(NULL, pdev->xdev->otherend, str,
479                                                    "%x:%x", &domain, &bus);
480                 if (err != 2) {
481                         if (err >= 0)
482                                 err = -EINVAL;
483                         xenbus_dev_fatal(pdev->xdev, err,
484                                                          "Error reading PCI root %d", i);
485                         goto out;
486                 }
487                 err = 0;
488                 if (domain != pdev->xdev->otherend_id) {
489                         err = -EINVAL;
490                         xenbus_dev_fatal(pdev->xdev, err,
491                                                          "Domain mismatch %d != %d", domain, pdev->xdev->otherend_id);
492                         goto out;
493                 }
494                 
495                 child = device_add_child(dev, "pcib", bus);
496                 if (!child) {
497                         err = -ENOMEM;
498                         xenbus_dev_fatal(pdev->xdev, err,
499                                                          "Unable to create pcib%d", bus);
500                         goto out;
501                 }
502         }
503
504  out:
505         return bus_generic_attach(dev);
506 }
507
508 static devclass_t xpcife_devclass;
509
510 static device_method_t xpcife_methods[] = {
511         /* Device interface */
512         DEVMETHOD(device_probe, xpcife_probe),
513         DEVMETHOD(device_attach, xpcife_attach),
514         DEVMETHOD(device_detach,        bus_generic_detach),
515         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
516         DEVMETHOD(device_suspend,       bus_generic_suspend),
517         DEVMETHOD(device_resume,        bus_generic_resume),
518     /* Bus interface */
519     DEVMETHOD(bus_alloc_resource,       bus_generic_alloc_resource),
520     DEVMETHOD(bus_release_resource,     bus_generic_release_resource),
521     DEVMETHOD(bus_activate_resource,    bus_generic_activate_resource),
522     DEVMETHOD(bus_deactivate_resource,  bus_generic_deactivate_resource),
523     DEVMETHOD(bus_setup_intr,           bus_generic_setup_intr),
524     DEVMETHOD(bus_teardown_intr,        bus_generic_teardown_intr),
525
526         DEVMETHOD_END
527 };
528
529 static driver_t xpcife_driver = {
530         "xpcife",
531         xpcife_methods,
532         0,
533 };
534
535 DRIVER_MODULE(xpcife, nexus, xpcife_driver, xpcife_devclass, 0, 0);
536
537 /* Newbus xen pcib device driver probe */
538 static int
539 xpcib_probe(device_t dev)
540 {
541         struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
542         struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(device_get_parent(dev));
543
544         DPRINTF("xpcib probe (bus=%d)\n", device_get_unit(dev));
545
546         sc->domain = pdev->xdev->otherend_id;
547         sc->bus = device_get_unit(dev);
548         sc->pdev = pdev;
549
550         return 0;
551 }
552
553 /* Newbus xen pcib device driver attach */
554 static int
555 xpcib_attach(device_t dev) 
556 {
557         struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
558
559         DPRINTF("xpcib attach (bus=%d)\n", sc->bus);
560
561         device_add_child(dev, "pci", -1);
562         return bus_generic_attach(dev);
563 }
564
565 static int
566 xpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
567 {
568         struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
569         switch (which) {
570         case  PCIB_IVAR_BUS:
571                 *result = sc->bus;
572                 return 0;
573         }
574         return ENOENT;
575 }
576
577 /* Return the number of slots supported */
578 static int
579 xpcib_maxslots(device_t dev)
580 {
581         return 31;
582 }
583
584 #define PCI_DEVFN(slot,func)    ((((slot) & 0x1f) << 3) | ((func) & 0x07))
585
586 /* Read configuration space register */
587 static u_int32_t
588 xpcib_read_config(device_t dev, int bus, int slot, int func,
589                                   int reg, int bytes)
590 {
591         struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
592         struct xen_pci_op op = {
593                 .cmd    = XEN_PCI_OP_conf_read,
594                 .domain = sc->domain,
595                 .bus    = sc->bus,
596                 .devfn  = PCI_DEVFN(slot, func),
597                 .offset = reg,
598                 .size   = bytes,
599         };
600         int err;
601
602         err = do_pci_op(sc->pdev, &op);
603
604         DPRINTF("read config (b=%d, s=%d, f=%d, reg=%d, len=%d, val=%x, err=%d)\n",
605                         bus, slot, func, reg, bytes, op.value, err);
606
607         if (err)
608                 op.value = ~0;
609
610         return op.value;
611 }
612
613 /* Write configuration space register */
614 static void
615 xpcib_write_config(device_t dev, int bus, int slot, int func,
616                                    int reg, u_int32_t data, int bytes)
617 {
618         struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
619         struct xen_pci_op op = {
620                 .cmd    = XEN_PCI_OP_conf_write,
621                 .domain = sc->domain,
622                 .bus    = sc->bus,
623                 .devfn  = PCI_DEVFN(slot, func),
624                 .offset = reg,
625                 .size   = bytes,
626                 .value  = data,
627         };
628         int err;
629
630         err = do_pci_op(sc->pdev, &op);
631
632         DPRINTF("write config (b=%d, s=%d, f=%d, reg=%d, len=%d, val=%x, err=%d)\n",
633                         bus, slot, func, reg, bytes, data, err);
634 }
635
636 static int
637 xpcib_route_interrupt(device_t pcib, device_t dev, int pin)
638 {
639         struct pci_devinfo *dinfo = device_get_ivars(dev);
640         pcicfgregs *cfg = &dinfo->cfg;
641
642         DPRINTF("route intr (pin=%d, line=%d)\n", pin, cfg->intline);
643
644         return cfg->intline;
645 }
646
647 static device_method_t xpcib_methods[] = {
648     /* Device interface */
649     DEVMETHOD(device_probe,             xpcib_probe),
650     DEVMETHOD(device_attach,            xpcib_attach),
651     DEVMETHOD(device_detach,            bus_generic_detach),
652     DEVMETHOD(device_shutdown,          bus_generic_shutdown),
653     DEVMETHOD(device_suspend,           bus_generic_suspend),
654     DEVMETHOD(device_resume,            bus_generic_resume),
655
656     /* Bus interface */
657     DEVMETHOD(bus_read_ivar,            xpcib_read_ivar),
658     DEVMETHOD(bus_alloc_resource,       bus_generic_alloc_resource),
659     DEVMETHOD(bus_activate_resource,    bus_generic_activate_resource),
660     DEVMETHOD(bus_release_resource,     bus_generic_release_resource),
661     DEVMETHOD(bus_deactivate_resource,  bus_generic_deactivate_resource),
662     DEVMETHOD(bus_setup_intr,           bus_generic_setup_intr),
663     DEVMETHOD(bus_teardown_intr,        bus_generic_teardown_intr),
664
665     /* pcib interface */
666     DEVMETHOD(pcib_maxslots,            xpcib_maxslots),
667     DEVMETHOD(pcib_read_config,         xpcib_read_config),
668     DEVMETHOD(pcib_write_config,        xpcib_write_config),
669     DEVMETHOD(pcib_route_interrupt,     xpcib_route_interrupt),
670         DEVMETHOD(pcib_request_feature, pcib_request_feature_allow),
671
672     DEVMETHOD_END
673 };
674
675 static devclass_t xpcib_devclass;
676
677 DEFINE_CLASS_0(pcib, xpcib_driver, xpcib_methods, sizeof(struct xpcib_softc));
678 DRIVER_MODULE(pcib, xpcife, xpcib_driver, xpcib_devclass, 0, 0);
679
680 /*
681  * Local variables:
682  * mode: C
683  * c-set-style: "BSD"
684  * c-basic-offset: 4
685  * tab-width: 4
686  * indent-tabs-mode: t
687  * End:
688  */