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