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