]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ofw/ofwpci.c
MFV r362990:
[FreeBSD/FreeBSD.git] / sys / dev / ofw / ofwpci.c
1 /*-
2  * Copyright (c) 2011 Nathan Whitehorn
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  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/module.h>
32 #include <sys/bus.h>
33 #include <sys/conf.h>
34 #include <sys/kernel.h>
35 #include <sys/rman.h>
36
37 #include <dev/ofw/openfirm.h>
38 #include <dev/ofw/ofw_pci.h>
39 #include <dev/ofw/ofw_bus.h>
40 #include <dev/ofw/ofw_bus_subr.h>
41 #include <dev/ofw/ofwpci.h>
42
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcireg.h>
45 #include <dev/pci/pcib_private.h>
46
47 #include <machine/bus.h>
48 #include <machine/md_var.h>
49 #include <machine/resource.h>
50
51 #include <vm/vm.h>
52 #include <vm/pmap.h>
53
54 #include "pcib_if.h"
55
56 /*
57  * If it is necessary to set another value of this for
58  * some platforms it should be set at fdt.h file
59  */
60 #ifndef PCI_MAP_INTR
61 #define PCI_MAP_INTR    4
62 #endif
63
64 #define PCI_INTR_PINS   4
65
66 /*
67  * bus interface.
68  */
69 static struct resource * ofw_pci_alloc_resource(device_t, device_t,
70     int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
71 static int ofw_pci_release_resource(device_t, device_t, int, int,
72     struct resource *);
73 static int ofw_pci_activate_resource(device_t, device_t, int, int,
74     struct resource *);
75 static int ofw_pci_deactivate_resource(device_t, device_t, int, int,
76     struct resource *);
77 static int ofw_pci_adjust_resource(device_t, device_t, int,
78     struct resource *, rman_res_t, rman_res_t);
79 static int ofw_pci_translate_resource(device_t bus, int type,
80         rman_res_t start, rman_res_t *newstart);
81
82 #ifdef __powerpc__
83 static bus_space_tag_t ofw_pci_bus_get_bus_tag(device_t, device_t);
84 #endif
85
86 /*
87  * pcib interface
88  */
89 static int ofw_pci_maxslots(device_t);
90
91 /*
92  * ofw_bus interface
93  */
94 static phandle_t ofw_pci_get_node(device_t, device_t);
95
96 /*
97  * local methods
98  */
99 static int ofw_pci_fill_ranges(phandle_t, struct ofw_pci_range *);
100 static struct rman *ofw_pci_get_rman(struct ofw_pci_softc *, int, u_int);
101
102 /*
103  * Driver methods.
104  */
105 static device_method_t  ofw_pci_methods[] = {
106
107         /* Device interface */
108         DEVMETHOD(device_attach,        ofw_pci_attach),
109
110         /* Bus interface */
111         DEVMETHOD(bus_print_child,      bus_generic_print_child),
112         DEVMETHOD(bus_read_ivar,        ofw_pci_read_ivar),
113         DEVMETHOD(bus_write_ivar,       ofw_pci_write_ivar),
114         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
115         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
116         DEVMETHOD(bus_alloc_resource,   ofw_pci_alloc_resource),
117         DEVMETHOD(bus_release_resource, ofw_pci_release_resource),
118         DEVMETHOD(bus_activate_resource,        ofw_pci_activate_resource),
119         DEVMETHOD(bus_deactivate_resource,      ofw_pci_deactivate_resource),
120         DEVMETHOD(bus_adjust_resource,  ofw_pci_adjust_resource),
121         DEVMETHOD(bus_translate_resource,       ofw_pci_translate_resource),
122 #ifdef __powerpc__
123         DEVMETHOD(bus_get_bus_tag,      ofw_pci_bus_get_bus_tag),
124 #endif
125
126         /* pcib interface */
127         DEVMETHOD(pcib_maxslots,        ofw_pci_maxslots),
128         DEVMETHOD(pcib_route_interrupt, ofw_pci_route_interrupt),
129         DEVMETHOD(pcib_request_feature, pcib_request_feature_allow),
130
131         /* ofw_bus interface */
132         DEVMETHOD(ofw_bus_get_node,     ofw_pci_get_node),
133
134         DEVMETHOD_END
135 };
136
137 DEFINE_CLASS_0(ofw_pci, ofw_pci_driver, ofw_pci_methods, 0);
138
139 int
140 ofw_pci_init(device_t dev)
141 {
142         struct ofw_pci_softc *sc;
143         phandle_t node;
144         u_int32_t busrange[2];
145         struct ofw_pci_range *rp;
146         int i, error;
147         struct ofw_pci_cell_info *cell_info;
148
149         node = ofw_bus_get_node(dev);
150         sc = device_get_softc(dev);
151         sc->sc_initialized = 1;
152         sc->sc_range = NULL;
153         sc->sc_pci_domain = device_get_unit(dev);
154
155         cell_info = (struct ofw_pci_cell_info *)malloc(sizeof(*cell_info),
156             M_DEVBUF, M_WAITOK | M_ZERO);
157
158         sc->sc_cell_info = cell_info;
159
160         if (OF_getencprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
161                 busrange[0] = 0;
162
163         sc->sc_dev = dev;
164         sc->sc_node = node;
165         sc->sc_bus = busrange[0];
166
167         if (sc->sc_quirks & OFW_PCI_QUIRK_RANGES_ON_CHILDREN) {
168                 phandle_t c;
169                 int n, i;
170
171                 sc->sc_nrange = 0;
172                 for (c = OF_child(node); c != 0; c = OF_peer(c)) {
173                         n = ofw_pci_nranges(c, cell_info);
174                         if (n > 0)
175                                 sc->sc_nrange += n;
176                 }
177                 if (sc->sc_nrange == 0) {
178                         error = ENXIO;
179                         goto out;
180                 }
181                 sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
182                     M_DEVBUF, M_WAITOK);
183                 i = 0;
184                 for (c = OF_child(node); c != 0; c = OF_peer(c)) {
185                         n = ofw_pci_fill_ranges(c, &sc->sc_range[i]);
186                         if (n > 0)
187                                 i += n;
188                 }
189                 KASSERT(i == sc->sc_nrange, ("range count mismatch"));
190         } else {
191                 sc->sc_nrange = ofw_pci_nranges(node, cell_info);
192                 if (sc->sc_nrange <= 0) {
193                         device_printf(dev, "could not getranges\n");
194                         error = ENXIO;
195                         goto out;
196                 }
197                 sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
198                     M_DEVBUF, M_WAITOK);
199                 ofw_pci_fill_ranges(node, sc->sc_range);
200         }
201
202         sc->sc_io_rman.rm_type = RMAN_ARRAY;
203         sc->sc_io_rman.rm_descr = "PCI I/O Ports";
204         error = rman_init(&sc->sc_io_rman);
205         if (error != 0) {
206                 device_printf(dev, "rman_init() failed. error = %d\n", error);
207                 goto out;
208         }
209
210         sc->sc_mem_rman.rm_type = RMAN_ARRAY;
211         sc->sc_mem_rman.rm_descr = "PCI Non Prefetchable Memory";
212         error = rman_init(&sc->sc_mem_rman);
213         if (error != 0) {
214                 device_printf(dev, "rman_init() failed. error = %d\n", error);
215                 goto out;
216         }
217
218         sc->sc_pmem_rman.rm_type = RMAN_ARRAY;
219         sc->sc_pmem_rman.rm_descr = "PCI Prefetchable Memory";
220         error = rman_init(&sc->sc_pmem_rman);
221         if (error != 0) {
222                 device_printf(dev, "rman_init() failed. error = %d\n", error);
223                 goto out;
224         }
225
226         for (i = 0; i < sc->sc_nrange; i++) {
227                 error = 0;
228                 rp = sc->sc_range + i;
229
230                 if (sc->sc_range_mask & ((uint64_t)1 << i))
231                         continue;
232                 switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
233                 case OFW_PCI_PHYS_HI_SPACE_CONFIG:
234                         break;
235                 case OFW_PCI_PHYS_HI_SPACE_IO:
236                         error = rman_manage_region(&sc->sc_io_rman, rp->pci,
237                             rp->pci + rp->size - 1);
238                         break;
239                 case OFW_PCI_PHYS_HI_SPACE_MEM32:
240                 case OFW_PCI_PHYS_HI_SPACE_MEM64:
241                         if (rp->pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) {
242                                 sc->sc_have_pmem = 1;
243                                 error = rman_manage_region(&sc->sc_pmem_rman,
244                                     rp->pci, rp->pci + rp->size - 1);
245                         } else {
246                                 error = rman_manage_region(&sc->sc_mem_rman,
247                                     rp->pci, rp->pci + rp->size - 1);
248                         }
249                         break;
250                 }
251
252                 if (error != 0) {
253                         device_printf(dev,
254                             "rman_manage_region(%x, %#jx, %#jx) failed. "
255                             "error = %d\n", rp->pci_hi &
256                             OFW_PCI_PHYS_HI_SPACEMASK, rp->pci,
257                             rp->pci + rp->size - 1, error);
258                         goto out;
259                 }
260         }
261
262         ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
263         return (0);
264
265 out:
266         free(cell_info, M_DEVBUF);
267         free(sc->sc_range, M_DEVBUF);
268         rman_fini(&sc->sc_io_rman);
269         rman_fini(&sc->sc_mem_rman);
270         rman_fini(&sc->sc_pmem_rman);
271
272         return (error);
273 }
274
275 int
276 ofw_pci_attach(device_t dev)
277 {
278         struct ofw_pci_softc *sc;
279         int error;
280
281         sc = device_get_softc(dev);
282         if (!sc->sc_initialized) {
283                 error = ofw_pci_init(dev);
284                 if (error != 0)
285                         return (error);
286         }
287
288         device_add_child(dev, "pci", -1);
289         return (bus_generic_attach(dev));
290 }
291
292 static int
293 ofw_pci_maxslots(device_t dev)
294 {
295
296         return (PCI_SLOTMAX);
297 }
298
299 int
300 ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
301 {
302         struct ofw_pci_softc *sc;
303         struct ofw_pci_register reg;
304         uint32_t pintr, mintr[PCI_MAP_INTR];
305         int intrcells;
306         phandle_t iparent;
307
308         sc = device_get_softc(bus);
309         pintr = pin;
310
311         /* Fabricate imap information in case this isn't an OFW device */
312         bzero(&reg, sizeof(reg));
313         reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
314             (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
315             (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
316
317         intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
318             &sc->sc_pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
319             mintr, sizeof(mintr), &iparent);
320         if (intrcells != 0) {
321                 pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
322                 return (pintr);
323         }
324
325         /*
326          * Maybe it's a real interrupt, not an intpin
327          */
328         if (pin > PCI_INTR_PINS)
329                 return (pin);
330
331         device_printf(bus, "could not route pin %d for device %d.%d\n",
332             pin, pci_get_slot(dev), pci_get_function(dev));
333         return (PCI_INVALID_IRQ);
334 }
335
336 int
337 ofw_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
338 {
339         struct ofw_pci_softc *sc;
340
341         sc = device_get_softc(dev);
342
343         switch (which) {
344         case PCIB_IVAR_DOMAIN:
345                 *result = sc->sc_pci_domain;
346                 return (0);
347         case PCIB_IVAR_BUS:
348                 *result = sc->sc_bus;
349                 return (0);
350         default:
351                 break;
352         }
353
354         return (ENOENT);
355 }
356
357 int
358 ofw_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
359 {
360         struct ofw_pci_softc *sc;
361
362         sc = device_get_softc(dev);
363
364         switch (which) {
365         case PCIB_IVAR_BUS:
366                 sc->sc_bus = value;
367                 return (0);
368         default:
369                 break;
370         }
371
372         return (ENOENT);
373 }
374
375 int
376 ofw_pci_nranges(phandle_t node, struct ofw_pci_cell_info *info)
377 {
378         ssize_t nbase_ranges;
379
380         if (info == NULL)
381                 return (-1);
382
383         info->host_address_cells = 1;
384         info->size_cells = 2;
385         info->pci_address_cell = 3;
386
387         OF_getencprop(OF_parent(node), "#address-cells",
388             &(info->host_address_cells), sizeof(info->host_address_cells));
389         OF_getencprop(node, "#address-cells",
390             &(info->pci_address_cell), sizeof(info->pci_address_cell));
391         OF_getencprop(node, "#size-cells", &(info->size_cells),
392             sizeof(info->size_cells));
393
394         nbase_ranges = OF_getproplen(node, "ranges");
395         if (nbase_ranges <= 0)
396                 return (-1);
397
398         return (nbase_ranges / sizeof(cell_t) /
399             (info->pci_address_cell + info->host_address_cells +
400             info->size_cells));
401 }
402
403 static struct resource *
404 ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
405     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
406 {
407         struct ofw_pci_softc *sc;
408         struct resource *rv;
409         struct rman *rm;
410         int needactivate;
411
412
413         needactivate = flags & RF_ACTIVE;
414         flags &= ~RF_ACTIVE;
415
416         sc = device_get_softc(bus);
417
418 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
419         if (type ==  PCI_RES_BUS) {
420                   return (pci_domain_alloc_bus(sc->sc_pci_domain, child, rid,
421                       start, end, count, flags | needactivate));
422         }
423 #endif
424
425         rm = ofw_pci_get_rman(sc, type, flags);
426         if (rm == NULL)  {
427                 return (bus_generic_alloc_resource(bus, child, type, rid,
428                     start, end, count, flags | needactivate));
429         }
430
431         rv = rman_reserve_resource(rm, start, end, count, flags, child);
432         if (rv == NULL) {
433                 device_printf(bus, "failed to reserve resource for %s\n",
434                     device_get_nameunit(child));
435                 return (NULL);
436         }
437
438         rman_set_rid(rv, *rid);
439
440         if (needactivate) {
441                 if (bus_activate_resource(child, type, *rid, rv) != 0) {
442                         device_printf(bus,
443                             "failed to activate resource for %s\n",
444                             device_get_nameunit(child));
445                         rman_release_resource(rv);
446                         return (NULL);
447                 }
448         }
449
450         return (rv);
451 }
452
453 static int
454 ofw_pci_release_resource(device_t bus, device_t child, int type, int rid,
455     struct resource *res)
456 {
457         struct ofw_pci_softc *sc;
458         struct rman *rm;
459         int error;
460
461         sc = device_get_softc(bus);
462
463 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
464         if (type == PCI_RES_BUS)
465                 return (pci_domain_release_bus(sc->sc_pci_domain, child, rid,
466                     res));
467 #endif
468
469         rm = ofw_pci_get_rman(sc, type, rman_get_flags(res));
470         if (rm == NULL) {
471                 return (bus_generic_release_resource(bus, child, type, rid,
472                     res));
473         }
474         KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
475
476         if (rman_get_flags(res) & RF_ACTIVE) {
477                 error = bus_deactivate_resource(child, type, rid, res);
478                 if (error != 0)
479                         return (error);
480         }
481         return (rman_release_resource(res));
482 }
483
484 static int
485 ofw_pci_translate_resource(device_t bus, int type, rman_res_t start,
486         rman_res_t *newstart)
487 {
488         struct ofw_pci_softc *sc;
489         struct ofw_pci_range *rp;
490         int space;
491
492         sc = device_get_softc(bus);
493
494         /*
495          * Map this through the ranges list
496          */
497         for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
498             rp->pci_hi != 0; rp++) {
499                 if (start < rp->pci || start >= rp->pci + rp->size)
500                         continue;
501
502                 switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
503                 case OFW_PCI_PHYS_HI_SPACE_IO:
504                         space = SYS_RES_IOPORT;
505                         break;
506                 case OFW_PCI_PHYS_HI_SPACE_MEM32:
507                 case OFW_PCI_PHYS_HI_SPACE_MEM64:
508                         space = SYS_RES_MEMORY;
509                         break;
510                 default:
511                         space = -1;
512                 }
513
514                 if (type == space) {
515                         start += (rp->host - rp->pci);
516                         break;
517                 }
518         }
519         *newstart = start;
520         return (0);
521 }
522
523 static int
524 ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
525     struct resource *res)
526 {
527         struct ofw_pci_softc *sc;
528         bus_space_handle_t handle;
529         bus_space_tag_t tag;
530         struct ofw_pci_range *rp;
531         vm_paddr_t start;
532         int space;
533         int rv;
534
535         sc = device_get_softc(bus);
536
537         if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
538                 return (bus_generic_activate_resource(bus, child, type, rid,
539                     res));
540         }
541
542         start = (vm_paddr_t)rman_get_start(res);
543
544         /*
545          * Map this through the ranges list
546          */
547         for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
548             rp->pci_hi != 0; rp++) {
549                 if (start < rp->pci || start >= rp->pci + rp->size)
550                         continue;
551
552                 switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
553                 case OFW_PCI_PHYS_HI_SPACE_IO:
554                         space = SYS_RES_IOPORT;
555                         break;
556                 case OFW_PCI_PHYS_HI_SPACE_MEM32:
557                 case OFW_PCI_PHYS_HI_SPACE_MEM64:
558                         space = SYS_RES_MEMORY;
559                         break;
560                 default:
561                         space = -1;
562                         }
563
564                 if (type == space) {
565                         start += (rp->host - rp->pci);
566                         break;
567                 }
568         }
569
570         if (bootverbose)
571                 printf("ofw_pci mapdev: start %jx, len %jd\n",
572                     (rman_res_t)start, rman_get_size(res));
573
574         tag = BUS_GET_BUS_TAG(child, child);
575         if (tag == NULL)
576                 return (ENOMEM);
577
578         rman_set_bustag(res, tag);
579         rv = bus_space_map(tag, start,
580             rman_get_size(res), 0, &handle);
581         if (rv != 0)
582                 return (ENOMEM);
583
584         rman_set_bushandle(res, handle);
585         rman_set_virtual(res, (void *)handle); /* XXX  for powerpc only ? */
586
587         return (rman_activate_resource(res));
588 }
589
590 #ifdef __powerpc__
591 static bus_space_tag_t
592 ofw_pci_bus_get_bus_tag(device_t bus, device_t child)
593 {
594
595         return (&bs_le_tag);
596 }
597 #endif
598
599 static int
600 ofw_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
601     struct resource *res)
602 {
603         vm_size_t psize;
604
605         if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
606                 return (bus_generic_deactivate_resource(bus, child, type, rid,
607                     res));
608         }
609
610         psize = rman_get_size(res);
611         pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
612
613         return (rman_deactivate_resource(res));
614 }
615
616 static int
617 ofw_pci_adjust_resource(device_t bus, device_t child, int type,
618     struct resource *res, rman_res_t start, rman_res_t end)
619 {
620         struct rman *rm;
621         struct ofw_pci_softc *sc;
622
623         sc = device_get_softc(bus);
624 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
625         if (type == PCI_RES_BUS)
626                 return (pci_domain_adjust_bus(sc->sc_pci_domain, child, res,
627                     start, end));
628 #endif
629
630         rm = ofw_pci_get_rman(sc, type, rman_get_flags(res));
631         if (rm == NULL) {
632                 return (bus_generic_adjust_resource(bus, child, type, res,
633                     start, end));
634         }
635         KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
636         KASSERT(!(rman_get_flags(res) & RF_ACTIVE),
637             ("active resources cannot be adjusted"));
638
639         return (rman_adjust_resource(res, start, end));
640 }
641
642 static phandle_t
643 ofw_pci_get_node(device_t bus, device_t dev)
644 {
645         struct ofw_pci_softc *sc;
646
647         sc = device_get_softc(bus);
648         /* We only have one child, the PCI bus, which needs our own node. */
649
650         return (sc->sc_node);
651 }
652
653 static int
654 ofw_pci_fill_ranges(phandle_t node, struct ofw_pci_range *ranges)
655 {
656         int host_address_cells = 1, pci_address_cells = 3, size_cells = 2;
657         cell_t *base_ranges;
658         ssize_t nbase_ranges;
659         int nranges;
660         int i, j, k;
661
662         OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
663             sizeof(host_address_cells));
664         OF_getencprop(node, "#address-cells", &pci_address_cells,
665             sizeof(pci_address_cells));
666         OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
667
668         nbase_ranges = OF_getproplen(node, "ranges");
669         if (nbase_ranges <= 0)
670                 return (-1);
671         nranges = nbase_ranges / sizeof(cell_t) /
672             (pci_address_cells + host_address_cells + size_cells);
673
674         base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
675         OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
676
677         for (i = 0, j = 0; i < nranges; i++) {
678                 ranges[i].pci_hi = base_ranges[j++];
679                 ranges[i].pci = 0;
680                 for (k = 0; k < pci_address_cells - 1; k++) {
681                         ranges[i].pci <<= 32;
682                         ranges[i].pci |= base_ranges[j++];
683                 }
684                 ranges[i].host = 0;
685                 for (k = 0; k < host_address_cells; k++) {
686                         ranges[i].host <<= 32;
687                         ranges[i].host |= base_ranges[j++];
688                 }
689                 ranges[i].size = 0;
690                 for (k = 0; k < size_cells; k++) {
691                         ranges[i].size <<= 32;
692                         ranges[i].size |= base_ranges[j++];
693                 }
694         }
695
696         free(base_ranges, M_DEVBUF);
697         return (nranges);
698 }
699
700 static struct rman *
701 ofw_pci_get_rman(struct ofw_pci_softc *sc, int type, u_int flags)
702 {
703
704         switch (type) {
705         case SYS_RES_IOPORT:
706                 return (&sc->sc_io_rman);
707         case SYS_RES_MEMORY:
708                 if (sc->sc_have_pmem  && (flags & RF_PREFETCHABLE))
709                         return (&sc->sc_pmem_rman);
710                 else
711                         return (&sc->sc_mem_rman);
712         default:
713                 break;
714         }
715
716         return (NULL);
717 }