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 *
alloc_pdev(struct xenbus_device * xdev)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
get_pdev(struct pcifront_device * pdev)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
put_pdev(struct pcifront_device * pdev)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
pcifront_publish_info(struct pcifront_device * pdev)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
pcifront_connect(struct pcifront_device * pdev)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
pcifront_disconnect(struct pcifront_device * pdev)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
pcifront_probe(struct xenbus_device * xdev,const struct xenbus_device_id * id)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
pcifront_remove(struct xenbus_device * xdev)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
pcifront_backend_changed(struct xenbus_device * xdev,XenbusState be_state)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
do_pci_op(struct pcifront_device * pdev,struct xen_pci_op * op)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
pcifront_init(void * unused)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
SYSINIT(pciif,SI_SUB_PSEUDO,SI_ORDER_ANY,pcifront_init,NULL)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
xpcife_attach(device_t dev)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 bus_attach_children(dev);
506 return (0);
507 }
508
509 static devclass_t xpcife_devclass;
510
511 static device_method_t xpcife_methods[] = {
512 /* Device interface */
513 DEVMETHOD(device_probe, xpcife_probe),
514 DEVMETHOD(device_attach, xpcife_attach),
515 DEVMETHOD(device_detach, bus_generic_detach),
516 DEVMETHOD(device_shutdown, bus_generic_shutdown),
517 DEVMETHOD(device_suspend, bus_generic_suspend),
518 DEVMETHOD(device_resume, bus_generic_resume),
519 /* Bus interface */
520 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
521 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
522 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
523 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
524 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
525 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
526
527 DEVMETHOD_END
528 };
529
530 static driver_t xpcife_driver = {
531 "xpcife",
532 xpcife_methods,
533 0,
534 };
535
536 DRIVER_MODULE(xpcife, nexus, xpcife_driver, xpcife_devclass, 0, 0);
537
538 /* Newbus xen pcib device driver probe */
539 static int
xpcib_probe(device_t dev)540 xpcib_probe(device_t dev)
541 {
542 struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
543 struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(device_get_parent(dev));
544
545 DPRINTF("xpcib probe (bus=%d)\n", device_get_unit(dev));
546
547 sc->domain = pdev->xdev->otherend_id;
548 sc->bus = device_get_unit(dev);
549 sc->pdev = pdev;
550
551 return 0;
552 }
553
554 /* Newbus xen pcib device driver attach */
555 static int
xpcib_attach(device_t dev)556 xpcib_attach(device_t dev)
557 {
558 struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
559
560 DPRINTF("xpcib attach (bus=%d)\n", sc->bus);
561
562 device_add_child(dev, "pci", DEVICE_UNIT_ANY);
563 bus_attach_children(dev);
564 return (0);
565 }
566
567 static int
xpcib_read_ivar(device_t dev,device_t child,int which,uintptr_t * result)568 xpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
569 {
570 struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
571 switch (which) {
572 case PCIB_IVAR_BUS:
573 *result = sc->bus;
574 return 0;
575 }
576 return ENOENT;
577 }
578
579 /* Return the number of slots supported */
580 static int
xpcib_maxslots(device_t dev)581 xpcib_maxslots(device_t dev)
582 {
583 return 31;
584 }
585
586 #define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
587
588 /* Read configuration space register */
589 static u_int32_t
xpcib_read_config(device_t dev,int bus,int slot,int func,int reg,int bytes)590 xpcib_read_config(device_t dev, int bus, int slot, int func,
591 int reg, int bytes)
592 {
593 struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
594 struct xen_pci_op op = {
595 .cmd = XEN_PCI_OP_conf_read,
596 .domain = sc->domain,
597 .bus = sc->bus,
598 .devfn = PCI_DEVFN(slot, func),
599 .offset = reg,
600 .size = bytes,
601 };
602 int err;
603
604 err = do_pci_op(sc->pdev, &op);
605
606 DPRINTF("read config (b=%d, s=%d, f=%d, reg=%d, len=%d, val=%x, err=%d)\n",
607 bus, slot, func, reg, bytes, op.value, err);
608
609 if (err)
610 op.value = ~0;
611
612 return op.value;
613 }
614
615 /* Write configuration space register */
616 static void
xpcib_write_config(device_t dev,int bus,int slot,int func,int reg,u_int32_t data,int bytes)617 xpcib_write_config(device_t dev, int bus, int slot, int func,
618 int reg, u_int32_t data, int bytes)
619 {
620 struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev);
621 struct xen_pci_op op = {
622 .cmd = XEN_PCI_OP_conf_write,
623 .domain = sc->domain,
624 .bus = sc->bus,
625 .devfn = PCI_DEVFN(slot, func),
626 .offset = reg,
627 .size = bytes,
628 .value = data,
629 };
630 int err;
631
632 err = do_pci_op(sc->pdev, &op);
633
634 DPRINTF("write config (b=%d, s=%d, f=%d, reg=%d, len=%d, val=%x, err=%d)\n",
635 bus, slot, func, reg, bytes, data, err);
636 }
637
638 static int
xpcib_route_interrupt(device_t pcib,device_t dev,int pin)639 xpcib_route_interrupt(device_t pcib, device_t dev, int pin)
640 {
641 struct pci_devinfo *dinfo = device_get_ivars(dev);
642 pcicfgregs *cfg = &dinfo->cfg;
643
644 DPRINTF("route intr (pin=%d, line=%d)\n", pin, cfg->intline);
645
646 return cfg->intline;
647 }
648
649 static device_method_t xpcib_methods[] = {
650 /* Device interface */
651 DEVMETHOD(device_probe, xpcib_probe),
652 DEVMETHOD(device_attach, xpcib_attach),
653 DEVMETHOD(device_detach, bus_generic_detach),
654 DEVMETHOD(device_shutdown, bus_generic_shutdown),
655 DEVMETHOD(device_suspend, bus_generic_suspend),
656 DEVMETHOD(device_resume, bus_generic_resume),
657
658 /* Bus interface */
659 DEVMETHOD(bus_read_ivar, xpcib_read_ivar),
660 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
661 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
662 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
663 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
664 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
665 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
666
667 /* pcib interface */
668 DEVMETHOD(pcib_maxslots, xpcib_maxslots),
669 DEVMETHOD(pcib_read_config, xpcib_read_config),
670 DEVMETHOD(pcib_write_config, xpcib_write_config),
671 DEVMETHOD(pcib_route_interrupt, xpcib_route_interrupt),
672 DEVMETHOD(pcib_request_feature, pcib_request_feature_allow),
673
674 DEVMETHOD_END
675 };
676
677 static devclass_t xpcib_devclass;
678
679 DEFINE_CLASS_0(pcib, xpcib_driver, xpcib_methods, sizeof(struct xpcib_softc));
680 DRIVER_MODULE(pcib, xpcife, xpcib_driver, xpcib_devclass, 0, 0);
681
682 /*
683 * Local variables:
684 * mode: C
685 * c-set-style: "BSD"
686 * c-basic-offset: 4
687 * tab-width: 4
688 * indent-tabs-mode: t
689 * End:
690 */
691