]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/powerpc/ofw/ofw_machdep.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / powerpc / ofw / ofw_machdep.c
1 /*-
2  * Copyright (C) 1996 Wolfgang Solfrank.
3  * Copyright (C) 1996 TooLs GmbH.
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. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by TooLs GmbH.
17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/systm.h>
40 #include <sys/conf.h>
41 #include <sys/disk.h>
42 #include <sys/fcntl.h>
43 #include <sys/malloc.h>
44 #include <sys/smp.h>
45 #include <sys/stat.h>
46
47 #include <net/ethernet.h>
48
49 #include <dev/ofw/openfirm.h>
50 #include <dev/ofw/ofw_pci.h>
51 #include <dev/ofw/ofw_bus.h>
52
53 #include <vm/vm.h>
54 #include <vm/vm_param.h>
55 #include <vm/vm_page.h>
56
57 #include <machine/bus.h>
58 #include <machine/cpu.h>
59 #include <machine/md_var.h>
60 #include <machine/platform.h>
61 #include <machine/ofw_machdep.h>
62
63 static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ];
64 static struct mem_region OFfree[PHYS_AVAIL_SZ];
65
66 extern register_t ofmsr[5];
67 extern void     *openfirmware_entry;
68 static void     *fdt;
69 int             ofw_real_mode;
70
71 int             ofwcall(void *);
72 static void     ofw_quiesce(void);
73 static int      openfirmware(void *args);
74
75 /*
76  * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
77  */
78 register_t      ofw_sprg0_save;
79
80 static __inline void
81 ofw_sprg_prepare(void)
82 {
83         /*
84          * Assume that interrupt are disabled at this point, or
85          * SPRG1-3 could be trashed
86          */
87         __asm __volatile("mfsprg0 %0\n\t"
88                          "mtsprg0 %1\n\t"
89                          "mtsprg1 %2\n\t"
90                          "mtsprg2 %3\n\t"
91                          "mtsprg3 %4\n\t"
92                          : "=&r"(ofw_sprg0_save)
93                          : "r"(ofmsr[1]),
94                          "r"(ofmsr[2]),
95                          "r"(ofmsr[3]),
96                          "r"(ofmsr[4]));
97 }
98
99 static __inline void
100 ofw_sprg_restore(void)
101 {
102         /*
103          * Note that SPRG1-3 contents are irrelevant. They are scratch
104          * registers used in the early portion of trap handling when
105          * interrupts are disabled.
106          *
107          * PCPU data cannot be used until this routine is called !
108          */
109         __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
110 }
111
112 /*
113  * Memory region utilities: determine if two regions overlap,
114  * and merge two overlapping regions into one
115  */
116 static int
117 memr_overlap(struct mem_region *r1, struct mem_region *r2)
118 {
119         if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
120             (r2->mr_start + r2->mr_size) < r1->mr_start)
121                 return (FALSE);
122         
123         return (TRUE);  
124 }
125
126 static void
127 memr_merge(struct mem_region *from, struct mem_region *to)
128 {
129         vm_offset_t end;
130         end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
131         to->mr_start = ulmin(from->mr_start, to->mr_start);
132         to->mr_size = end - to->mr_start;
133 }
134
135 /*
136  * Quick sort callout for comparing memory regions.
137  */
138 static int      mr_cmp(const void *a, const void *b);
139
140 static int
141 mr_cmp(const void *a, const void *b)
142 {
143         const struct    mem_region *regiona;
144         const struct    mem_region *regionb;
145
146         regiona = a;
147         regionb = b;
148         if (regiona->mr_start < regionb->mr_start)
149                 return (-1);
150         else if (regiona->mr_start > regionb->mr_start)
151                 return (1);
152         else
153                 return (0);
154 }
155
156 static int
157 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
158 {
159         cell_t address_cells, size_cells;
160         cell_t OFmem[4 * PHYS_AVAIL_SZ];
161         int sz, i, j;
162         int apple_hack_mode;
163         phandle_t phandle;
164
165         sz = 0;
166         apple_hack_mode = 0;
167
168         /*
169          * Get #address-cells from root node, defaulting to 1 if it cannot
170          * be found.
171          */
172         phandle = OF_finddevice("/");
173         if (OF_getprop(phandle, "#address-cells", &address_cells, 
174             sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
175                 address_cells = 1;
176         if (OF_getprop(phandle, "#size-cells", &size_cells, 
177             sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
178                 size_cells = 1;
179
180         /*
181          * On Apple hardware, address_cells is always 1 for "available",
182          * even when it is explicitly set to 2. Then all memory above 4 GB
183          * should be added by hand to the available list. Detect Apple hardware
184          * by seeing if ofw_real_mode is set -- only Apple seems to use
185          * virtual-mode OF.
186          */
187         if (strcmp(prop, "available") == 0 && !ofw_real_mode)
188                 apple_hack_mode = 1;
189         
190         if (apple_hack_mode)
191                 address_cells = 1;
192
193         /*
194          * Get memory.
195          */
196         if (node == -1 || (sz = OF_getprop(node, prop,
197             OFmem, sizeof(OFmem))) <= 0)
198                 panic("Physical memory map not found");
199
200         i = 0;
201         j = 0;
202         while (i < sz/sizeof(cell_t)) {
203               #ifndef __powerpc64__
204                 /* On 32-bit PPC, ignore regions starting above 4 GB */
205                 if (address_cells > 1 && OFmem[i] > 0) {
206                         i += address_cells + size_cells;
207                         continue;
208                 }
209               #endif
210
211                 output[j].mr_start = OFmem[i++];
212                 if (address_cells == 2) {
213                         #ifdef __powerpc64__
214                         output[j].mr_start <<= 32;
215                         #endif
216                         output[j].mr_start += OFmem[i++];
217                 }
218                         
219                 output[j].mr_size = OFmem[i++];
220                 if (size_cells == 2) {
221                         #ifdef __powerpc64__
222                         output[j].mr_size <<= 32;
223                         #endif
224                         output[j].mr_size += OFmem[i++];
225                 }
226
227               #ifndef __powerpc64__
228                 /*
229                  * Check for memory regions extending above 32-bit
230                  * memory space, and restrict them to stay there.
231                  */
232                 if (((uint64_t)output[j].mr_start +
233                     (uint64_t)output[j].mr_size) >
234                     BUS_SPACE_MAXADDR_32BIT) {
235                         output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
236                             output[j].mr_start;
237                 }
238               #endif
239
240                 j++;
241         }
242         sz = j*sizeof(output[0]);
243
244         #ifdef __powerpc64__
245         if (apple_hack_mode) {
246                 /* Add in regions above 4 GB to the available list */
247                 struct mem_region himem[16];
248                 int hisz;
249
250                 hisz = parse_ofw_memory(node, "reg", himem);
251                 for (i = 0; i < hisz/sizeof(himem[0]); i++) {
252                         if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
253                                 output[j].mr_start = himem[i].mr_start;
254                                 output[j].mr_size = himem[i].mr_size;
255                                 j++;
256                         }
257                 }
258                 sz = j*sizeof(output[0]);
259         }
260         #endif
261
262         return (sz);
263 }
264
265 static int
266 parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem,
267                     struct mem_region *ofavail)
268 {
269         phandle_t phandle;
270         vm_offset_t base;
271         int i, idx, len, lasz, lmsz, res;
272         uint32_t lmb_size[2];
273         unsigned long *dmem, flags;
274
275         lmsz = *msz;
276         lasz = *asz;
277
278         phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
279         if (phandle == -1)
280                 /* No drconf node, return. */
281                 return (0);
282
283         res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size));
284         if (res == -1)
285                 return (0);
286
287         /* Parse the /ibm,dynamic-memory.
288            The first position gives the # of entries. The next two words
289            reflect the address of the memory block. The next four words are
290            the DRC index, reserved, list index and flags.
291            (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
292            
293             #el  Addr   DRC-idx  res   list-idx  flags
294            -------------------------------------------------
295            | 4 |   8   |   4   |   4   |   4   |   4   |....
296            -------------------------------------------------
297         */
298
299         len = OF_getproplen(phandle, "ibm,dynamic-memory");
300         if (len > 0) {
301
302                 /* We have to use a variable length array on the stack
303                    since we have very limited stack space.
304                 */
305                 cell_t arr[len/sizeof(cell_t)];
306
307                 res = OF_getprop(phandle, "ibm,dynamic-memory", &arr,
308                                  sizeof(arr));
309                 if (res == -1)
310                         return (0);
311
312                 /* Number of elements */
313                 idx = arr[0];
314
315                 /* First address. */
316                 dmem = (void*)&arr[1];
317         
318                 for (i = 0; i < idx; i++) {
319                         base = *dmem;
320                         dmem += 2;
321                         flags = *dmem;
322                         /* Use region only if available and not reserved. */
323                         if ((flags & 0x8) && !(flags & 0x80)) {
324                                 ofmem[lmsz].mr_start = base;
325                                 ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
326                                 ofavail[lasz].mr_start = base;
327                                 ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
328                                 lmsz++;
329                                 lasz++;
330                         }
331                         dmem++;
332                 }
333         }
334
335         *msz = lmsz;
336         *asz = lasz;
337
338         return (1);
339 }
340 /*
341  * This is called during powerpc_init, before the system is really initialized.
342  * It shall provide the total and the available regions of RAM.
343  * Both lists must have a zero-size entry as terminator.
344  * The available regions need not take the kernel into account, but needs
345  * to provide space for two additional entry beyond the terminating one.
346  */
347 void
348 ofw_mem_regions(struct mem_region **memp, int *memsz,
349                 struct mem_region **availp, int *availsz)
350 {
351         phandle_t phandle;
352         vm_offset_t maxphysaddr;
353         int asz, msz, fsz;
354         int i, j, res;
355         int still_merging;
356         char name[31];
357
358         asz = msz = 0;
359
360         /*
361          * Get memory from all the /memory nodes.
362          */
363         for (phandle = OF_child(OF_peer(0)); phandle != 0;
364             phandle = OF_peer(phandle)) {
365                 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
366                         continue;
367                 if (strncmp(name, "memory", sizeof(name)) != 0)
368                         continue;
369
370                 res = parse_ofw_memory(phandle, "reg", &OFmem[msz]);
371                 msz += res/sizeof(struct mem_region);
372                 if (OF_getproplen(phandle, "available") >= 0)
373                         res = parse_ofw_memory(phandle, "available",
374                             &OFavail[asz]);
375                 else
376                         res = parse_ofw_memory(phandle, "reg", &OFavail[asz]);
377                 asz += res/sizeof(struct mem_region);
378         }
379
380         /* Check for memory in ibm,dynamic-reconfiguration-memory */
381         parse_drconf_memory(&msz, &asz, OFmem, OFavail);
382
383         qsort(OFmem, msz, sizeof(*OFmem), mr_cmp);
384         qsort(OFavail, asz, sizeof(*OFavail), mr_cmp);
385
386         *memp = OFmem;
387         *memsz = msz;
388
389         /*
390          * On some firmwares (SLOF), some memory may be marked available that
391          * doesn't actually exist. This manifests as an extension of the last
392          * available segment past the end of physical memory, so truncate that
393          * one.
394          */
395         maxphysaddr = 0;
396         for (i = 0; i < msz; i++)
397                 if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr)
398                         maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size;
399
400         if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr)
401                 OFavail[asz - 1].mr_size = maxphysaddr -
402                     OFavail[asz - 1].mr_start;
403
404         /*
405          * OFavail may have overlapping regions - collapse these
406          * and copy out remaining regions to OFfree
407          */
408         do {
409                 still_merging = FALSE;
410                 for (i = 0; i < asz; i++) {
411                         if (OFavail[i].mr_size == 0)
412                                 continue;
413                         for (j = i+1; j < asz; j++) {
414                                 if (OFavail[j].mr_size == 0)
415                                         continue;
416                                 if (memr_overlap(&OFavail[j], &OFavail[i])) {
417                                         memr_merge(&OFavail[j], &OFavail[i]);
418                                         /* mark inactive */
419                                         OFavail[j].mr_size = 0;
420                                         still_merging = TRUE;
421                                 }
422                         }
423                 }
424         } while (still_merging == TRUE);
425
426         /* evict inactive ranges */
427         for (i = 0, fsz = 0; i < asz; i++) {
428                 if (OFavail[i].mr_size != 0) {
429                         OFfree[fsz] = OFavail[i];
430                         fsz++;
431                 }
432         }
433
434         *availp = OFfree;
435         *availsz = fsz;
436 }
437
438 void
439 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
440 {
441         if (ofmsr[0] & PSL_DR)
442                 ofw_real_mode = 0;
443         else
444                 ofw_real_mode = 1;
445
446         fdt = fdt_ptr;
447
448         #ifdef FDT_DTB_STATIC
449         /* Check for a statically included blob */
450         if (fdt == NULL)
451                 fdt = &fdt_static_dtb;
452         #endif
453 }
454
455 boolean_t
456 OF_bootstrap()
457 {
458         boolean_t status = FALSE;
459
460         if (openfirmware_entry != NULL) {
461                 if (ofw_real_mode) {
462                         status = OF_install(OFW_STD_REAL, 0);
463                 } else {
464                         #ifdef __powerpc64__
465                         status = OF_install(OFW_STD_32BIT, 0);
466                         #else
467                         status = OF_install(OFW_STD_DIRECT, 0);
468                         #endif
469                 }
470
471                 if (status != TRUE)
472                         return status;
473
474                 OF_init(openfirmware);
475
476                 /*
477                  * On some machines, we need to quiesce OF to turn off
478                  * background processes.
479                  */
480                 ofw_quiesce();
481         } else if (fdt != NULL) {
482                 status = OF_install(OFW_FDT, 0);
483
484                 if (status != TRUE)
485                         return status;
486
487                 OF_init(fdt);
488         } 
489
490         return (status);
491 }
492
493 static void
494 ofw_quiesce(void)
495 {
496         phandle_t rootnode;
497         char model[32];
498         struct {
499                 cell_t name;
500                 cell_t nargs;
501                 cell_t nreturns;
502         } args;
503
504         /*
505          * Only quiesce Open Firmware on PowerMac11,2 and 12,1. It is
506          * necessary there to shut down a background thread doing fan
507          * management, and is harmful on other machines.
508          *
509          * Note: we don't need to worry about which OF module we are
510          * using since this is called only from very early boot, within
511          * OF's boot context.
512          */
513
514         rootnode = OF_finddevice("/");
515         if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) {
516                 if (strcmp(model, "PowerMac11,2") == 0 ||
517                     strcmp(model, "PowerMac12,1") == 0) {
518                         args.name = (cell_t)(uintptr_t)"quiesce";
519                         args.nargs = 0;
520                         args.nreturns = 0;
521                         openfirmware(&args);
522                 }
523         }
524 }
525
526 static int
527 openfirmware_core(void *args)
528 {
529         int             result;
530         register_t      oldmsr;
531
532         /*
533          * Turn off exceptions - we really don't want to end up
534          * anywhere unexpected with PCPU set to something strange
535          * or the stack pointer wrong.
536          */
537         oldmsr = intr_disable();
538
539         ofw_sprg_prepare();
540
541 #if defined(AIM) && !defined(__powerpc64__)
542         /*
543          * Clear battable[] translations
544          */
545         if (!(cpu_features & PPC_FEATURE_64))
546                 __asm __volatile("mtdbatu 2, %0\n"
547                                  "mtdbatu 3, %0" : : "r" (0));
548         isync();
549 #endif
550
551         result = ofwcall(args);
552         ofw_sprg_restore();
553
554         intr_restore(oldmsr);
555
556         return (result);
557 }
558
559 #ifdef SMP
560 struct ofw_rv_args {
561         void *args;
562         int retval;
563         volatile int in_progress;
564 };
565
566 static void
567 ofw_rendezvous_dispatch(void *xargs)
568 {
569         struct ofw_rv_args *rv_args = xargs;
570
571         /* NOTE: Interrupts are disabled here */
572
573         if (PCPU_GET(cpuid) == 0) {
574                 /*
575                  * Execute all OF calls on CPU 0
576                  */
577                 rv_args->retval = openfirmware_core(rv_args->args);
578                 rv_args->in_progress = 0;
579         } else {
580                 /*
581                  * Spin with interrupts off on other CPUs while OF has
582                  * control of the machine.
583                  */
584                 while (rv_args->in_progress)
585                         cpu_spinwait();
586         }
587 }
588 #endif
589
590 static int
591 openfirmware(void *args)
592 {
593         int result;
594         #ifdef SMP
595         struct ofw_rv_args rv_args;
596
597         rv_args.args = args;
598         rv_args.in_progress = 1;
599         smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
600             smp_no_rendevous_barrier, &rv_args);
601         result = rv_args.retval;
602         #else
603         result = openfirmware_core(args);
604         #endif
605
606         return (result);
607 }
608
609 void
610 OF_reboot()
611 {
612         struct {
613                 cell_t name;
614                 cell_t nargs;
615                 cell_t nreturns;
616                 cell_t arg;
617         } args;
618
619         args.name = (cell_t)(uintptr_t)"interpret";
620         args.nargs = 1;
621         args.nreturns = 0;
622         args.arg = (cell_t)(uintptr_t)"reset-all";
623         openfirmware_core(&args); /* Don't do rendezvous! */
624
625         for (;;);       /* just in case */
626 }
627
628 void
629 OF_getetheraddr(device_t dev, u_char *addr)
630 {
631         phandle_t       node;
632
633         node = ofw_bus_get_node(dev);
634         OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
635 }
636
637 /*
638  * Return a bus handle and bus tag that corresponds to the register
639  * numbered regno for the device referenced by the package handle
640  * dev. This function is intended to be used by console drivers in
641  * early boot only. It works by mapping the address of the device's
642  * register in the address space of its parent and recursively walk
643  * the device tree upward this way.
644  */
645 static void
646 OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
647 {
648         char name[16];
649         uint32_t addr, size;
650         int pci, res;
651
652         res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
653         if (res == -1)
654                 addr = 2;
655         res = OF_getprop(node, "#size-cells", &size, sizeof(size));
656         if (res == -1)
657                 size = 1;
658         pci = 0;
659         if (addr == 3 && size == 2) {
660                 res = OF_getprop(node, "name", name, sizeof(name));
661                 if (res != -1) {
662                         name[sizeof(name) - 1] = '\0';
663                         pci = (strcmp(name, "pci") == 0) ? 1 : 0;
664                 }
665         }
666         if (addrp != NULL)
667                 *addrp = addr;
668         if (sizep != NULL)
669                 *sizep = size;
670         if (pcip != NULL)
671                 *pcip = pci;
672 }
673
674 int
675 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
676     bus_space_handle_t *handle)
677 {
678         uint32_t cell[32];
679         bus_addr_t addr, raddr, baddr;
680         bus_size_t size, rsize;
681         uint32_t c, nbridge, naddr, nsize;
682         phandle_t bridge, parent;
683         u_int spc, rspc;
684         int pci, pcib, res;
685
686         /* Sanity checking. */
687         if (dev == 0)
688                 return (EINVAL);
689         bridge = OF_parent(dev);
690         if (bridge == 0)
691                 return (EINVAL);
692         if (regno < 0)
693                 return (EINVAL);
694         if (tag == NULL || handle == NULL)
695                 return (EINVAL);
696
697         /* Get the requested register. */
698         OF_get_addr_props(bridge, &naddr, &nsize, &pci);
699         res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
700             cell, sizeof(cell));
701         if (res == -1)
702                 return (ENXIO);
703         if (res % sizeof(cell[0]))
704                 return (ENXIO);
705         res /= sizeof(cell[0]);
706         regno *= naddr + nsize;
707         if (regno + naddr + nsize > res)
708                 return (EINVAL);
709         spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
710         addr = 0;
711         for (c = 0; c < naddr; c++)
712                 addr = ((uint64_t)addr << 32) | cell[regno++];
713         size = 0;
714         for (c = 0; c < nsize; c++)
715                 size = ((uint64_t)size << 32) | cell[regno++];
716
717         /*
718          * Map the address range in the bridge's decoding window as given
719          * by the "ranges" property. If a node doesn't have such property
720          * then no mapping is done.
721          */
722         parent = OF_parent(bridge);
723         while (parent != 0) {
724                 OF_get_addr_props(parent, &nbridge, NULL, &pcib);
725                 res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
726                 if (res == -1)
727                         goto next;
728                 if (res % sizeof(cell[0]))
729                         return (ENXIO);
730                 res /= sizeof(cell[0]);
731                 regno = 0;
732                 while (regno < res) {
733                         rspc = (pci)
734                             ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
735                             : ~0;
736                         if (rspc != spc) {
737                                 regno += naddr + nbridge + nsize;
738                                 continue;
739                         }
740                         raddr = 0;
741                         for (c = 0; c < naddr; c++)
742                                 raddr = ((uint64_t)raddr << 32) | cell[regno++];
743                         rspc = (pcib)
744                             ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
745                             : ~0;
746                         baddr = 0;
747                         for (c = 0; c < nbridge; c++)
748                                 baddr = ((uint64_t)baddr << 32) | cell[regno++];
749                         rsize = 0;
750                         for (c = 0; c < nsize; c++)
751                                 rsize = ((uint64_t)rsize << 32) | cell[regno++];
752                         if (addr < raddr || addr >= raddr + rsize)
753                                 continue;
754                         addr = addr - raddr + baddr;
755                         if (rspc != ~0)
756                                 spc = rspc;
757                 }
758
759         next:
760                 bridge = parent;
761                 parent = OF_parent(bridge);
762                 OF_get_addr_props(bridge, &naddr, &nsize, &pci);
763         }
764
765         *tag = &bs_le_tag;
766         return (bus_space_map(*tag, addr, size, 0, handle));
767 }
768