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