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