]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/sparc64/ebus/ebus.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / sparc64 / ebus / ebus.c
1 /*-
2  * Copyright (c) 1999, 2000 Matthew R. Green
3  * Copyright (c) 2009 by Marius Strobl <marius@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      from: NetBSD: ebus.c,v 1.52 2008/05/29 14:51:26 mrg Exp
30  */
31 /*-
32  * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org>
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  * 3. The name of the author may not be used to endorse or promote products
44  *    derived from this software without specific prior written permission.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
47  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
50  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
51  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
53  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
54  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  */
58
59 #include <sys/cdefs.h>
60 __FBSDID("$FreeBSD$");
61
62 /*
63  * Driver for JBus to EBus and PCI to EBus bridges
64  */
65
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/bus.h>
69 #include <sys/kernel.h>
70 #include <sys/malloc.h>
71 #include <sys/module.h>
72
73 #include <sys/rman.h>
74
75 #include <dev/ofw/ofw_bus.h>
76 #include <dev/ofw/ofw_bus_subr.h>
77 #include <dev/ofw/openfirm.h>
78
79 #include <machine/bus.h>
80 #ifndef SUN4V
81 #include <machine/bus_common.h>
82 #endif
83 #include <machine/intr_machdep.h>
84 #include <machine/resource.h>
85
86 #include <dev/pci/pcireg.h>
87 #include <dev/pci/pcivar.h>
88
89 #include <sparc64/pci/ofw_pci.h>
90
91 /*
92  * The register, interrupt map and for the PCI variant also the ranges
93  * properties are identical to the ISA ones.
94  */
95 #include <sparc64/isa/ofw_isa.h>
96
97 struct ebus_nexus_ranges {
98         uint32_t        child_hi;
99         uint32_t        child_lo;
100         uint32_t        phys_hi;
101         uint32_t        phys_lo;
102         uint32_t        size;
103 };
104
105 struct ebus_devinfo {
106         struct ofw_bus_devinfo  edi_obdinfo;
107         struct resource_list    edi_rl;
108 };
109
110 struct ebus_rinfo {
111         int                     eri_rtype;
112         struct rman             eri_rman;
113         struct resource         *eri_res;
114 };
115
116 struct ebus_softc {
117         void                    *sc_range;
118         struct ebus_rinfo       *sc_rinfo;
119
120         u_int                   sc_flags;
121 #define EBUS_PCI                (1 << 0)
122
123         int                     sc_nrange;
124
125         struct ofw_bus_iinfo    sc_iinfo;
126
127 #ifndef SUN4V
128         uint32_t                sc_ign;
129 #endif
130 };
131
132 static device_probe_t ebus_nexus_probe;
133 static device_attach_t ebus_nexus_attach;
134 static device_probe_t ebus_pci_probe;
135 static device_attach_t ebus_pci_attach;
136 static bus_print_child_t ebus_print_child;
137 static bus_probe_nomatch_t ebus_probe_nomatch;
138 static bus_alloc_resource_t ebus_alloc_resource;
139 static bus_activate_resource_t ebus_activate_resource;
140 static bus_adjust_resource_t ebus_adjust_resource;
141 static bus_release_resource_t ebus_release_resource;
142 static bus_setup_intr_t ebus_setup_intr;
143 static bus_get_resource_list_t ebus_get_resource_list;
144 static ofw_bus_get_devinfo_t ebus_get_devinfo;
145
146 static int ebus_attach(device_t dev, struct ebus_softc *sc, phandle_t node);
147 static struct ebus_devinfo *ebus_setup_dinfo(device_t dev,
148     struct ebus_softc *sc, phandle_t node);
149 static void ebus_destroy_dinfo(struct ebus_devinfo *edi);
150 static int ebus_print_res(struct ebus_devinfo *edi);
151
152 static devclass_t ebus_devclass;
153
154 static device_method_t ebus_nexus_methods[] = {
155         /* Device interface */
156         DEVMETHOD(device_probe,         ebus_nexus_probe),
157         DEVMETHOD(device_attach,        ebus_nexus_attach),
158         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
159         DEVMETHOD(device_suspend,       bus_generic_suspend),
160         DEVMETHOD(device_resume,        bus_generic_resume),
161
162         /* Bus interface */
163         DEVMETHOD(bus_print_child,      ebus_print_child),
164         DEVMETHOD(bus_probe_nomatch,    ebus_probe_nomatch),
165         DEVMETHOD(bus_alloc_resource,   ebus_alloc_resource),
166         DEVMETHOD(bus_activate_resource, ebus_activate_resource),
167         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
168         DEVMETHOD(bus_adjust_resource,  ebus_adjust_resource),
169         DEVMETHOD(bus_release_resource, ebus_release_resource),
170         DEVMETHOD(bus_setup_intr,       ebus_setup_intr),
171         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
172         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
173         DEVMETHOD(bus_get_resource_list, ebus_get_resource_list),
174         DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
175
176         /* ofw_bus interface */
177         DEVMETHOD(ofw_bus_get_devinfo,  ebus_get_devinfo),
178         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
179         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
180         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
181         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
182         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
183
184         DEVMETHOD_END
185 };
186
187 static driver_t ebus_nexus_driver = {
188         "ebus",
189         ebus_nexus_methods,
190         sizeof(struct ebus_softc),
191 };
192
193 /*
194  * NB: we rely on the interrupt controllers of the accompanying PCI-Express
195  * bridge to be registered as the nexus variant of the EBus bridges doesn't
196  * employ its own one.
197  */
198 EARLY_DRIVER_MODULE(ebus, nexus, ebus_nexus_driver, ebus_devclass, 0, 0,
199     BUS_PASS_BUS + 1);
200 MODULE_DEPEND(ebus, nexus, 1, 1, 1);
201
202 static device_method_t ebus_pci_methods[] = {
203         /* Device interface */
204         DEVMETHOD(device_probe,         ebus_pci_probe),
205         DEVMETHOD(device_attach,        ebus_pci_attach),
206         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
207         DEVMETHOD(device_suspend,       bus_generic_suspend),
208         DEVMETHOD(device_resume,        bus_generic_resume),
209
210         /* Bus interface */
211         DEVMETHOD(bus_print_child,      ebus_print_child),
212         DEVMETHOD(bus_probe_nomatch,    ebus_probe_nomatch),
213         DEVMETHOD(bus_alloc_resource,   ebus_alloc_resource),
214         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
215         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
216         DEVMETHOD(bus_release_resource, ebus_release_resource),
217         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
218         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
219         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
220         DEVMETHOD(bus_get_resource_list, ebus_get_resource_list),
221         DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
222
223         /* ofw_bus interface */
224         DEVMETHOD(ofw_bus_get_devinfo,  ebus_get_devinfo),
225         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
226         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
227         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
228         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
229         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
230
231         DEVMETHOD_END
232 };
233
234 static driver_t ebus_pci_driver = {
235         "ebus",
236         ebus_pci_methods,
237         sizeof(struct ebus_softc),
238 };
239
240 EARLY_DRIVER_MODULE(ebus, pci, ebus_pci_driver, ebus_devclass, 0, 0,
241     BUS_PASS_BUS);
242 MODULE_DEPEND(ebus, pci, 1, 1, 1);
243 MODULE_VERSION(ebus, 1);
244
245 static int
246 ebus_nexus_probe(device_t dev)
247 {
248         const char* compat;
249
250         compat = ofw_bus_get_compat(dev);
251         if (compat != NULL && strcmp(ofw_bus_get_name(dev), "ebus") == 0 &&
252             strcmp(compat, "jbus-ebus") == 0) {
253                 device_set_desc(dev, "JBus-EBus bridge");
254                 return (BUS_PROBE_GENERIC);
255         }
256         return (ENXIO);
257 }
258
259 static int
260 ebus_pci_probe(device_t dev)
261 {
262
263         if (pci_get_class(dev) != PCIC_BRIDGE ||
264             pci_get_vendor(dev) != 0x108e ||
265             strcmp(ofw_bus_get_name(dev), "ebus") != 0)
266                 return (ENXIO);
267
268         if (pci_get_device(dev) == 0x1000)
269                 device_set_desc(dev, "PCI-EBus2 bridge");
270         else if (pci_get_device(dev) == 0x1100)
271                 device_set_desc(dev, "PCI-EBus3 bridge");
272         else
273                 return (ENXIO);
274         return (BUS_PROBE_GENERIC);
275 }
276
277 static int
278 ebus_nexus_attach(device_t dev)
279 {
280         struct ebus_softc *sc;
281         phandle_t node;
282
283         sc = device_get_softc(dev);
284         node = ofw_bus_get_node(dev);
285
286 #ifndef SUN4V
287         if (OF_getprop(node, "portid", &sc->sc_ign,
288             sizeof(sc->sc_ign)) == -1) {
289                 device_printf(dev, "could not determine IGN");
290                 return (ENXIO);
291         }
292 #endif
293
294         sc->sc_nrange = OF_getprop_alloc(node, "ranges",
295             sizeof(struct ebus_nexus_ranges), &sc->sc_range);
296         if (sc->sc_nrange == -1) {
297                 printf("%s: could not get ranges property\n", __func__);
298                 return (ENXIO);
299         }
300         return (ebus_attach(dev, sc, node));
301 }
302
303 static int
304 ebus_pci_attach(device_t dev)
305 {
306         struct ebus_softc *sc;
307         struct ebus_rinfo *eri;
308         struct resource *res;
309         phandle_t node;
310         int i, rnum, rid;
311
312         sc = device_get_softc(dev);
313         sc->sc_flags |= EBUS_PCI;
314
315         pci_write_config(dev, PCIR_COMMAND,
316             pci_read_config(dev, PCIR_COMMAND, 2) | PCIM_CMD_SERRESPEN |
317             PCIM_CMD_PERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN, 2);
318         pci_write_config(dev, PCIR_CACHELNSZ, 16 /* 64 bytes */, 1);
319         pci_write_config(dev, PCIR_LATTIMER, 64 /* 64 PCI cycles */, 1);
320
321         node = ofw_bus_get_node(dev);
322         sc->sc_nrange = OF_getprop_alloc(node, "ranges",
323             sizeof(struct isa_ranges), &sc->sc_range);
324         if (sc->sc_nrange == -1) {
325                 printf("%s: could not get ranges property\n", __func__);
326                 return (ENXIO);
327         }
328
329         sc->sc_rinfo = malloc(sizeof(*sc->sc_rinfo) * sc->sc_nrange, M_DEVBUF,
330             M_WAITOK | M_ZERO);
331
332         /* For every range, there must be a matching resource. */
333         for (rnum = 0; rnum < sc->sc_nrange; rnum++) {
334                 eri = &sc->sc_rinfo[rnum];
335                 eri->eri_rtype = ofw_isa_range_restype(
336                     &((struct isa_ranges *)sc->sc_range)[rnum]);
337                 rid = PCIR_BAR(rnum);
338                 res = bus_alloc_resource_any(dev, eri->eri_rtype, &rid,
339                     RF_ACTIVE);
340                 if (res == NULL) {
341                         printf("%s: failed to allocate range resource!\n",
342                             __func__);
343                         goto fail;
344                 }
345                 eri->eri_res = res;
346                 eri->eri_rman.rm_type = RMAN_ARRAY;
347                 eri->eri_rman.rm_descr = "EBus range";
348                 if (rman_init_from_resource(&eri->eri_rman, res) != 0) {
349                         printf("%s: failed to initialize rman!", __func__);
350                         goto fail;
351                 }
352         }
353         return (ebus_attach(dev, sc, node));
354
355  fail:
356         for (i = rnum; i >= 0; i--) {
357                 eri = &sc->sc_rinfo[i];
358                 if (i < rnum)
359                         rman_fini(&eri->eri_rman);
360                 if (eri->eri_res != 0) {
361                         bus_release_resource(dev, eri->eri_rtype,
362                             PCIR_BAR(rnum), eri->eri_res);
363                 }
364         }
365         free(sc->sc_rinfo, M_DEVBUF);
366         free(sc->sc_range, M_OFWPROP);
367         return (ENXIO);
368 }
369
370 static int
371 ebus_attach(device_t dev, struct ebus_softc *sc, phandle_t node)
372 {
373         struct ebus_devinfo *edi;
374         device_t cdev;
375
376         ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_isa_intr_t));
377
378         /*
379          * Now attach our children.
380          */
381         for (node = OF_child(node); node > 0; node = OF_peer(node)) {
382                 if ((edi = ebus_setup_dinfo(dev, sc, node)) == NULL)
383                         continue;
384                 if ((cdev = device_add_child(dev, NULL, -1)) == NULL) {
385                         device_printf(dev, "<%s>: device_add_child failed\n",
386                             edi->edi_obdinfo.obd_name);
387                         ebus_destroy_dinfo(edi);
388                         continue;
389                 }
390                 device_set_ivars(cdev, edi);
391         }
392         return (bus_generic_attach(dev));
393 }
394
395 static int
396 ebus_print_child(device_t dev, device_t child)
397 {
398         int retval;
399
400         retval = bus_print_child_header(dev, child);
401         retval += ebus_print_res(device_get_ivars(child));
402         retval += bus_print_child_footer(dev, child);
403         return (retval);
404 }
405
406 static void
407 ebus_probe_nomatch(device_t dev, device_t child)
408 {
409
410         device_printf(dev, "<%s>", ofw_bus_get_name(child));
411         ebus_print_res(device_get_ivars(child));
412         printf(" (no driver attached)\n");
413 }
414
415 static struct resource *
416 ebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
417     u_long start, u_long end, u_long count, u_int flags)
418 {
419         struct ebus_softc *sc;
420         struct resource_list *rl;
421         struct resource_list_entry *rle = NULL;
422         struct resource *res;
423         struct ebus_rinfo *eri;
424         struct ebus_nexus_ranges *enr;
425         uint64_t cend, cstart, offset;
426         int i, isdefault, passthrough, ridx;
427
428         isdefault = (start == 0UL && end == ~0UL);
429         passthrough = (device_get_parent(child) != bus);
430         sc = device_get_softc(bus);
431         rl = BUS_GET_RESOURCE_LIST(bus, child);
432         switch (type) {
433         case SYS_RES_MEMORY:
434                 KASSERT(!(isdefault && passthrough),
435                     ("%s: passthrough of default allocation", __func__));
436                 if (!passthrough) {
437                         rle = resource_list_find(rl, type, *rid);
438                         if (rle == NULL)
439                                 return (NULL);
440                         KASSERT(rle->res == NULL,
441                             ("%s: resource entry is busy", __func__));
442                         if (isdefault) {
443                                 start = rle->start;
444                                 count = ulmax(count, rle->count);
445                                 end = ulmax(rle->end, start + count - 1);
446                         }
447                 }
448
449                 res = NULL;
450                 if ((sc->sc_flags & EBUS_PCI) != 0) {
451                         /*
452                          * Map EBus ranges to PCI ranges.  This may include
453                          * changing the allocation type.
454                          */
455                         (void)ofw_isa_range_map(sc->sc_range, sc->sc_nrange,
456                             &start, &end, &ridx);
457                         eri = &sc->sc_rinfo[ridx];
458                         res = rman_reserve_resource(&eri->eri_rman, start,
459                             end, count, flags & ~RF_ACTIVE, child);
460                         if (res == NULL)
461                                 return (NULL);
462                         rman_set_rid(res, *rid);
463                         if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(
464                             child, type, *rid, res) != 0) {
465                                 rman_release_resource(res);
466                                 return (NULL);
467                         }
468                 } else {
469                         /* Map EBus ranges to nexus ranges. */
470                         for (i = 0; i < sc->sc_nrange; i++) {
471                                 enr = &((struct ebus_nexus_ranges *)
472                                     sc->sc_range)[i];
473                                 cstart = (((uint64_t)enr->child_hi) << 32) |
474                                     enr->child_lo;
475                                 cend = cstart + enr->size - 1;
476                                 if (start >= cstart && end <= cend) {
477                                         offset =
478                                             (((uint64_t)enr->phys_hi) << 32) |
479                                             enr->phys_lo;
480                                         start += offset - cstart;
481                                         end += offset - cstart;
482                                         res = bus_generic_alloc_resource(bus,
483                                             child, type, rid, start, end,
484                                             count, flags);
485                                         break;
486                                 }
487                         }
488                 }
489                 if (!passthrough)
490                         rle->res = res;
491                 return (res);
492         case SYS_RES_IRQ:
493                 return (resource_list_alloc(rl, bus, child, type, rid, start,
494                     end, count, flags));
495         }
496         return (NULL);
497 }
498
499 static int
500 ebus_activate_resource(device_t bus, device_t child, int type, int rid,
501     struct resource *res)
502 {
503         struct ebus_softc *sc;
504         struct ebus_rinfo *eri;
505         bus_space_tag_t bt;
506         bus_space_handle_t bh;
507         int i, rv;
508
509         sc = device_get_softc(bus);
510         if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) {
511                 for (i = 0; i < sc->sc_nrange; i++) {
512                         eri = &sc->sc_rinfo[i];
513                         if (rman_is_region_manager(res, &eri->eri_rman) != 0) {
514                                 bt = rman_get_bustag(eri->eri_res);
515                                 rv = bus_space_subregion(bt,
516                                     rman_get_bushandle(eri->eri_res),
517                                     rman_get_start(res) -
518                                     rman_get_start(eri->eri_res),
519                                     rman_get_size(res), &bh);
520                                 if (rv != 0)
521                                         return (rv);
522                                 rman_set_bustag(res, bt);
523                                 rman_set_bushandle(res, bh);
524                                 return (rman_activate_resource(res));
525                         }
526                 }
527                 return (EINVAL);
528         }
529         return (bus_generic_activate_resource(bus, child, type, rid, res));
530 }
531
532 static int
533 ebus_adjust_resource(device_t bus __unused, device_t child __unused,
534     int type __unused, struct resource *res __unused, u_long start __unused,
535     u_long end __unused)
536 {
537
538         return (ENXIO);
539 }
540
541 static int
542 ebus_release_resource(device_t bus, device_t child, int type, int rid,
543     struct resource *res)
544 {
545         struct ebus_softc *sc;
546         struct resource_list *rl;
547         struct resource_list_entry *rle;
548         int passthrough, rv;
549
550         passthrough = (device_get_parent(child) != bus);
551         rl = BUS_GET_RESOURCE_LIST(bus, child);
552         sc = device_get_softc(bus);
553         if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) {
554                 if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){
555                         rv = bus_deactivate_resource(child, type, rid, res);
556                         if (rv != 0)
557                                 return (rv);
558                 }
559                 rv = rman_release_resource(res);
560                 if (rv != 0)
561                         return (rv);
562                 if (!passthrough) {
563                         rle = resource_list_find(rl, type, rid);
564                         KASSERT(rle != NULL,
565                             ("%s: resource entry not found!", __func__));
566                         KASSERT(rle->res != NULL,
567                            ("%s: resource entry is not busy", __func__));
568                         rle->res = NULL;
569                 }
570                 return (0);
571         }
572         return (resource_list_release(rl, bus, child, type, rid, res));
573 }
574
575 static int
576 ebus_setup_intr(device_t dev, device_t child, struct resource *ires,
577     int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
578     void **cookiep)
579 {
580 #ifndef SUN4V
581         struct ebus_softc *sc;
582         u_long vec;
583
584         sc = device_get_softc(dev);
585         if ((sc->sc_flags & EBUS_PCI) == 0) {
586                 /*
587                  * Make sure the vector is fully specified.  This isn't
588                  * necessarily the case with the PCI variant.
589                  */
590                 vec = rman_get_start(ires);
591                 if (INTIGN(vec) != sc->sc_ign) {
592                         device_printf(dev,
593                             "invalid interrupt vector 0x%lx\n", vec);
594                         return (EINVAL);
595                 }
596
597                 /*
598                  * As we rely on the interrupt controllers of the
599                  * accompanying PCI-Express bridge ensure at least
600                  * something is registered for this vector.
601                  */
602                 if (intr_vectors[vec].iv_ic == NULL) {
603                         device_printf(dev,
604                             "invalid interrupt controller for vector 0x%lx\n",
605                             vec);
606                         return (EINVAL);
607                 }
608         }
609 #endif
610         return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr,
611             arg, cookiep));
612 }
613
614 static struct resource_list *
615 ebus_get_resource_list(device_t dev, device_t child)
616 {
617         struct ebus_devinfo *edi;
618
619         edi = device_get_ivars(child);
620         return (&edi->edi_rl);
621 }
622
623 static const struct ofw_bus_devinfo *
624 ebus_get_devinfo(device_t bus, device_t dev)
625 {
626         struct ebus_devinfo *edi;
627
628         edi = device_get_ivars(dev);
629         return (&edi->edi_obdinfo);
630 }
631
632 static struct ebus_devinfo *
633 ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node)
634 {
635         struct isa_regs reg, *regs;
636         ofw_isa_intr_t intr, *intrs;
637         struct ebus_devinfo *edi;
638         uint64_t start;
639         uint32_t rintr;
640         int i, nintr, nreg, rv;
641         uint8_t maskbuf[sizeof(reg) + sizeof(intr)];
642
643         edi = malloc(sizeof(*edi), M_DEVBUF, M_ZERO | M_WAITOK);
644         if (ofw_bus_gen_setup_devinfo(&edi->edi_obdinfo, node) != 0) {
645                 free(edi, M_DEVBUF);
646                 return (NULL);
647         }
648         resource_list_init(&edi->edi_rl);
649         nreg = OF_getprop_alloc(node, "reg", sizeof(*regs), (void **)&regs);
650         if (nreg == -1) {
651                 device_printf(dev, "<%s>: incomplete\n",
652                     edi->edi_obdinfo.obd_name);
653                 ebus_destroy_dinfo(edi);
654                 return (NULL);
655         }
656         for (i = 0; i < nreg; i++) {
657                 start = ISA_REG_PHYS(regs + i);
658                 (void)resource_list_add(&edi->edi_rl, SYS_RES_MEMORY, i,
659                     start, start + regs[i].size - 1, regs[i].size);
660         }
661         free(regs, M_OFWPROP);
662
663         nintr = OF_getprop_alloc(node, "interrupts",  sizeof(*intrs),
664             (void **)&intrs);
665         if (nintr == -1)
666                 return (edi);
667         for (i = 0; i < nintr; i++) {
668                 rv = 0;
669                 if ((sc->sc_flags & EBUS_PCI) != 0) {
670                         rintr = ofw_isa_route_intr(dev, node, &sc->sc_iinfo,
671                             intrs[i]);
672                 } else {
673                         intr = intrs[i];
674                         rv = ofw_bus_lookup_imap(node, &sc->sc_iinfo, &reg,
675                             sizeof(reg), &intr, sizeof(intr), &rintr,
676                             sizeof(rintr), NULL, maskbuf);
677 #ifndef SUN4V
678                         if (rv != 0)
679                                 rintr = INTMAP_VEC(sc->sc_ign, rintr);
680 #endif
681                 }
682                 if ((sc->sc_flags & EBUS_PCI) == 0 ? rv == 0 :
683                     rintr == PCI_INVALID_IRQ) {
684                         device_printf(dev,
685                             "<%s>: could not map EBus interrupt %d\n",
686                             edi->edi_obdinfo.obd_name, intrs[i]);
687                         continue;
688                 }
689                 (void)resource_list_add(&edi->edi_rl, SYS_RES_IRQ, i, rintr,
690                     rintr, 1);
691         }
692         free(intrs, M_OFWPROP);
693         return (edi);
694 }
695
696 static void
697 ebus_destroy_dinfo(struct ebus_devinfo *edi)
698 {
699
700         resource_list_free(&edi->edi_rl);
701         ofw_bus_gen_destroy_devinfo(&edi->edi_obdinfo);
702         free(edi, M_DEVBUF);
703 }
704
705 static int
706 ebus_print_res(struct ebus_devinfo *edi)
707 {
708         int retval;
709
710         retval = 0;
711         retval += resource_list_print_type(&edi->edi_rl, "addr", SYS_RES_MEMORY,
712             "%#lx");
713         retval += resource_list_print_type(&edi->edi_rl, "irq", SYS_RES_IRQ,
714             "%ld");
715         return (retval);
716 }