ofw_machdep.c revision 199886
150477Speter/*-
233548Sjkh * Copyright (C) 1996 Wolfgang Solfrank.
32893Sdfr * Copyright (C) 1996 TooLs GmbH.
42893Sdfr * All rights reserved.
533548Sjkh *
633548Sjkh * Redistribution and use in source and binary forms, with or without
72893Sdfr * modification, are permitted provided that the following conditions
82893Sdfr * are met:
92893Sdfr * 1. Redistributions of source code must retain the above copyright
102893Sdfr *    notice, this list of conditions and the following disclaimer.
112893Sdfr * 2. Redistributions in binary form must reproduce the above copyright
122893Sdfr *    notice, this list of conditions and the following disclaimer in the
132893Sdfr *    documentation and/or other materials provided with the distribution.
142893Sdfr * 3. All advertising materials mentioning features or use of this software
152893Sdfr *    must display the following acknowledgement:
162893Sdfr *	This product includes software developed by TooLs GmbH.
172893Sdfr * 4. The name of TooLs GmbH may not be used to endorse or promote products
182893Sdfr *    derived from this software without specific prior written permission.
192893Sdfr *
202893Sdfr * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
212893Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
222893Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
232893Sdfr * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
242893Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
252893Sdfr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
262893Sdfr * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
272893Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
282893Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
292893Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
302893Sdfr *
312893Sdfr * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
322893Sdfr */
332893Sdfr
342893Sdfr#include <sys/cdefs.h>
35139776Simp__FBSDID("$FreeBSD: head/sys/powerpc/aim/ofw_machdep.c 199886 2009-11-28 17:33:19Z nwhitehorn $");
362893Sdfr
378876Srgrimes#include <sys/param.h>
382893Sdfr#include <sys/bus.h>
392893Sdfr#include <sys/systm.h>
408876Srgrimes#include <sys/conf.h>
412893Sdfr#include <sys/disk.h>
428876Srgrimes#include <sys/fcntl.h>
432893Sdfr#include <sys/malloc.h>
442893Sdfr#include <sys/stat.h>
452893Sdfr
462893Sdfr#include <net/ethernet.h>
478876Srgrimes
482893Sdfr#include <dev/ofw/openfirm.h>
492893Sdfr#include <dev/ofw/ofw_pci.h>
502893Sdfr#include <dev/ofw/ofw_bus.h>
512893Sdfr
522893Sdfr#include <vm/vm.h>
53171754Sbde#include <vm/vm_param.h>
5440651Sbde#include <vm/vm_page.h>
55177785Skib
56171754Sbde#include <machine/bus.h>
57171754Sbde#include <machine/cpu.h>
58171748Sbde#include <machine/md_var.h>
59171754Sbde#include <machine/platform.h>
60171754Sbde#include <machine/ofw_machdep.h>
61171748Sbde
622893Sdfr#define	OFMEM_REGIONS	32
63164033Srwatsonstatic struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
642893Sdfrstatic struct mem_region OFfree[OFMEM_REGIONS + 3];
65171754Sbde
662893Sdfrstruct mem_region64 {
672893Sdfr        vm_offset_t     mr_start_hi;
68171754Sbde        vm_offset_t     mr_start_lo;
69171754Sbde        vm_size_t       mr_size;
70171754Sbde};
71171754Sbde
7277162Sruextern register_t ofmsr[5];
7377162Sruextern struct	pmap ofw_pmap;
7477162Srustatic int	(*ofwcall)(void *);
7577162Srustatic void	*fdt;
76171754Sbdeint		ofw_real_mode;
772893Sdfr
78172757Sbdestatic int	openfirmware(void *args);
79138471Sphk
80172798Sbde/*
81172757Sbde * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
82172757Sbde */
83172757Sbderegister_t	ofw_sprg0_save;
84172757Sbde
85172757Sbdestatic __inline void
86138471Sphkofw_sprg_prepare(void)
87138471Sphk{
88138471Sphk	/*
8956674Snyan	 * Assume that interrupt are disabled at this point, or
9056674Snyan	 * SPRG1-3 could be trashed
9156674Snyan	 */
9256674Snyan	__asm __volatile("mfsprg0 %0\n\t"
9356674Snyan			 "mtsprg0 %1\n\t"
9456674Snyan	    		 "mtsprg1 %2\n\t"
9556674Snyan	    		 "mtsprg2 %3\n\t"
9656674Snyan			 "mtsprg3 %4\n\t"
9756674Snyan			 : "=&r"(ofw_sprg0_save)
9856674Snyan			 : "r"(ofmsr[1]),
9956674Snyan			 "r"(ofmsr[2]),
100151897Srwatson			 "r"(ofmsr[3]),
101151897Srwatson			 "r"(ofmsr[4]));
10230309Sphk}
103171757Sbde
104120492Sfjoestatic __inline void
105138471Sphkofw_sprg_restore(void)
106183754Sattilio{
107170188Strhodes	/*
108138471Sphk	 * Note that SPRG1-3 contents are irrelevant. They are scratch
109101777Sphk	 * registers used in the early portion of trap handling when
110101777Sphk	 * interrupts are disabled.
111101777Sphk	 *
112101777Sphk	 * PCPU data cannot be used until this routine is called !
11312338Sbde	 */
114134345Stjr	__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
115134345Stjr}
116134345Stjr
11733548Sjkh/*
118166558Srodrigc * Memory region utilities: determine if two regions overlap,
11933548Sjkh * and merge two overlapping regions into one
12033548Sjkh */
121138471Sphkstatic int
122138471Sphkmemr_overlap(struct mem_region *r1, struct mem_region *r2)
12333548Sjkh{
124138471Sphk	if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
125138471Sphk	    (r2->mr_start + r2->mr_size) < r1->mr_start)
126138471Sphk		return (FALSE);
127138471Sphk
128138471Sphk	return (TRUE);
129138471Sphk}
130138471Sphk
131138471Sphkstatic void
132138471Sphkmemr_merge(struct mem_region *from, struct mem_region *to)
133138471Sphk{
134138471Sphk	int end;
135138471Sphk	end = imax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
136138471Sphk	to->mr_start = imin(from->mr_start, to->mr_start);
137138471Sphk	to->mr_size = end - to->mr_start;
138138471Sphk}
139138471Sphk
140134345Stjr/*
141134345Stjr * This is called during powerpc_init, before the system is really initialized.
142134345Stjr * It shall provide the total and the available regions of RAM.
143134345Stjr * Both lists must have a zero-size entry as terminator.
144134345Stjr * The available regions need not take the kernel into account, but needs
145134345Stjr * to provide space for two additional entry beyond the terminating one.
146134345Stjr */
147134345Stjrvoid
148134345Stjrofw_mem_regions(struct mem_region **memp, int *memsz,
149134345Stjr		struct mem_region **availp, int *availsz)
150138471Sphk{
151138471Sphk	phandle_t phandle;
152138471Sphk	int asz, msz, fsz;
153138471Sphk	int i, j;
154138471Sphk	int still_merging;
155138471Sphk	cell_t address_cells;
156138471Sphk
157138471Sphk	asz = msz = 0;
158138471Sphk
159138471Sphk	/*
160152595Srodrigc	 * Get #address-cells from root node, defaulting to 1 if it cannot
161152595Srodrigc	 * be found.
162138471Sphk	 */
163138471Sphk	phandle = OF_finddevice("/");
164152595Srodrigc	if (OF_getprop(phandle, "#address-cells", &address_cells,
165152595Srodrigc	    sizeof(address_cells)) < sizeof(address_cells))
166138471Sphk		address_cells = 1;
167138471Sphk
16833548Sjkh	/*
169152610Srodrigc	 * Get memory.
170152610Srodrigc	 */
171152610Srodrigc	if ((phandle = OF_finddevice("/memory")) == -1
172138471Sphk	    || (asz = OF_getprop(phandle, "available",
173138471Sphk		  OFavail, sizeof OFavail[0] * OFMEM_REGIONS)) <= 0)
17433548Sjkh	{
17533548Sjkh		if (ofw_real_mode) {
17633548Sjkh			/* XXX MAMBO */
17733548Sjkh			printf("Physical memory unknown -- guessing 128 MB\n");
17833548Sjkh
17933548Sjkh			/* Leave the first 0xA000000 bytes for the kernel */
18033548Sjkh			OFavail[0].mr_start = 0xA00000;
18133548Sjkh			OFavail[0].mr_size = 0x75FFFFF;
18233548Sjkh			asz = sizeof(OFavail[0]);
18333548Sjkh		} else {
18433548Sjkh			panic("no memory?");
18533548Sjkh		}
186144058Sjeff	}
187191990Sattilio
18833548Sjkh	if (address_cells == 2) {
189171757Sbde	    struct mem_region64 OFmem64[OFMEM_REGIONS + 1];
190171757Sbde	    if ((phandle == -1) || (msz = OF_getprop(phandle, "reg",
19133548Sjkh			  OFmem64, sizeof OFmem64[0] * OFMEM_REGIONS)) <= 0) {
19233548Sjkh		if (ofw_real_mode) {
19333548Sjkh			/* XXX MAMBO */
19433548Sjkh			OFmem64[0].mr_start_hi = 0;
19533548Sjkh			OFmem64[0].mr_start_lo = 0x0;
19633548Sjkh			OFmem64[0].mr_size = 0x7FFFFFF;
197138471Sphk			msz = sizeof(OFmem64[0]);
198191990Sattilio		} else {
199138471Sphk			panic("Physical memory map not found");
200138471Sphk		}
201138471Sphk	    }
202138471Sphk
203138471Sphk	    for (i = 0, j = 0; i < msz/sizeof(OFmem64[0]); i++) {
204138471Sphk		if (OFmem64[i].mr_start_hi == 0) {
205138471Sphk			OFmem[i].mr_start = OFmem64[i].mr_start_lo;
206138471Sphk			OFmem[i].mr_size = OFmem64[i].mr_size;
207138471Sphk
208138471Sphk			/*
209138471Sphk			 * Check for memory regions extending above 32-bit
210138471Sphk			 * memory space, and restrict them to stay there.
211138471Sphk			 */
212138471Sphk			if (((uint64_t)OFmem[i].mr_start +
213138471Sphk			    (uint64_t)OFmem[i].mr_size) >
214138471Sphk			    BUS_SPACE_MAXADDR_32BIT) {
215138471Sphk				OFmem[i].mr_size = BUS_SPACE_MAXADDR_32BIT -
216171757Sbde				    OFmem[i].mr_start;
217171757Sbde			}
218171757Sbde			j++;
219171757Sbde		}
220138471Sphk	    }
221171757Sbde	    msz = j*sizeof(OFmem[0]);
222171757Sbde	} else {
223171757Sbde	    if ((msz = OF_getprop(phandle, "reg",
224138471Sphk			  OFmem, sizeof OFmem[0] * OFMEM_REGIONS)) <= 0)
225138471Sphk		panic("Physical memory map not found");
226138471Sphk	}
227138471Sphk
228138471Sphk	*memp = OFmem;
229138471Sphk	*memsz = msz / sizeof(struct mem_region);
2302893Sdfr
2318876Srgrimes
2322893Sdfr	/*
2338876Srgrimes	 * OFavail may have overlapping regions - collapse these
2342893Sdfr	 * and copy out remaining regions to OFfree
23512144Sphk	 */
236191990Sattilio	asz /= sizeof(struct mem_region);
2372893Sdfr	do {
2382893Sdfr		still_merging = FALSE;
239191990Sattilio		for (i = 0; i < asz; i++) {
24033548Sjkh			if (OFavail[i].mr_size == 0)
24133548Sjkh				continue;
242132902Sphk			for (j = i+1; j < asz; j++) {
243138689Sphk				if (OFavail[j].mr_size == 0)
244184413Strasz					continue;
245138471Sphk				if (memr_overlap(&OFavail[j], &OFavail[i])) {
2462893Sdfr					memr_merge(&OFavail[j], &OFavail[i]);
247191990Sattilio					/* mark inactive */
248138471Sphk					OFavail[j].mr_size = 0;
249138471Sphk					still_merging = TRUE;
250138471Sphk				}
2512893Sdfr			}
25233548Sjkh		}
25333548Sjkh	} while (still_merging == TRUE);
2542893Sdfr
2552893Sdfr	/* evict inactive ranges */
25633548Sjkh	for (i = 0, fsz = 0; i < asz; i++) {
257158924Srodrigc		if (OFavail[i].mr_size != 0) {
258165022Srodrigc			OFfree[fsz] = OFavail[i];
259165022Srodrigc			fsz++;
260165022Srodrigc		}
261165022Srodrigc	}
262165022Srodrigc
263165022Srodrigc	*availp = OFfree;
264165022Srodrigc	*availsz = fsz;
265138689Sphk}
266165022Srodrigc
267138689Sphkvoid
268137036SphkOF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
269138471Sphk{
270191990Sattilio	if (ofmsr[0] & PSL_DR)
271133287Sphk		ofw_real_mode = 0;
272133287Sphk	else
2732893Sdfr		ofw_real_mode = 1;
2742893Sdfr
2752893Sdfr	ofwcall = openfirm;
276132023Salfred	fdt = fdt_ptr;
277138471Sphk}
278138471Sphk
279172883Sdelphijboolean_t
280172883SdelphijOF_bootstrap()
281172883Sdelphij{
282172883Sdelphij	boolean_t status = FALSE;
283172883Sdelphij
284172883Sdelphij	if (ofwcall != NULL) {
285172883Sdelphij		if (ofw_real_mode)
286172883Sdelphij			status = OF_install(OFW_STD_REAL, 0);
287172883Sdelphij		else
288172883Sdelphij			status = OF_install(OFW_STD_DIRECT, 0);
289172883Sdelphij
290172883Sdelphij		if (status != TRUE)
291137036Sphk			return status;
292137036Sphk
293171551Sbde		OF_init(openfirmware);
294137036Sphk	} else {
295137036Sphk		status = OF_install(OFW_FDT, 0);
296172883Sdelphij
297172883Sdelphij		if (status != TRUE)
298171551Sbde			return status;
299172883Sdelphij
300171551Sbde		OF_init(fdt);
301172883Sdelphij	}
302172883Sdelphij
303172883Sdelphij	return (status);
304172883Sdelphij}
305172883Sdelphij
306172883Sdelphijstatic int
307172883Sdelphijopenfirmware(void *args)
308172883Sdelphij{
309172883Sdelphij	long	oldmsr;
310138471Sphk	int	result;
311138471Sphk	u_int	srsave[16];
31233548Sjkh	u_int   i;
31333548Sjkh
31433548Sjkh	if (pmap_bootstrapped && ofw_real_mode)
31533548Sjkh		args = (void *)pmap_kextract((vm_offset_t)args);
316164033Srwatson
317175202Sattilio	__asm __volatile(	"\t"
318164033Srwatson		"sync\n\t"
319171757Sbde		"mfmsr  %0\n\t"
320164033Srwatson		"mtmsr  %1\n\t"
321164033Srwatson		"isync\n"
322164033Srwatson		: "=r" (oldmsr)
323175294Sattilio		: "r" (ofmsr[0])
324164033Srwatson	);
32533548Sjkh
326175294Sattilio	ofw_sprg_prepare();
327137036Sphk
328137036Sphk	if (pmap_bootstrapped && !ofw_real_mode) {
329137036Sphk		/*
330137036Sphk		 * Swap the kernel's address space with Open Firmware's
331137036Sphk		 */
332137036Sphk		for (i = 0; i < 16; i++) {
333137036Sphk			srsave[i] = mfsrin(i << ADDR_SR_SHFT);
334123963Sbde			mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]);
335172883Sdelphij		}
336172883Sdelphij
337172883Sdelphij		/*
338172883Sdelphij		 * Clear battable[] translations
339172883Sdelphij		 */
340165836Srodrigc		if (!(cpu_features & PPC_FEATURE_64)) {
341123963Sbde			__asm __volatile("mtdbatu 2, %0\n"
342123873Strhodes					 "mtdbatu 3, %0" : : "r" (0));
343123873Strhodes		}
344172883Sdelphij		isync();
34533548Sjkh	}
3462893Sdfr
3472893Sdfr       	result = ofwcall(args);
34833548Sjkh
349125796Sbde	if (pmap_bootstrapped && !ofw_real_mode) {
3502893Sdfr		/*
351138471Sphk		 * Restore the kernel's addr space. The isync() doesn;t
352138471Sphk		 * work outside the loop unless mtsrin() is open-coded
353149720Sssouhlal		 * in an asm statement :(
354132902Sphk		 */
35533548Sjkh		for (i = 0; i < 16; i++) {
35633548Sjkh			mtsrin(i << ADDR_SR_SHFT, srsave[i]);
357132902Sphk			isync();
358132902Sphk		}
3598876Srgrimes	}
36055756Sphk
361149720Sssouhlal	ofw_sprg_restore();
36255756Sphk
3632893Sdfr	__asm(	"\t"
3642893Sdfr		"mtmsr  %0\n\t"
36533548Sjkh		"isync\n"
36633548Sjkh		: : "r" (oldmsr)
3672893Sdfr	);
368184413Strasz
369164033Srwatson	return (result);
370184413Strasz}
371184413Strasz
372164033Srwatsonvoid
373164033SrwatsonOF_halt()
374164033Srwatson{
375164033Srwatson	int retval;	/* dummy, this may not be needed */
376164033Srwatson
37733548Sjkh	OF_interpret("shut-down", 1, &retval);
37833548Sjkh	for (;;);	/* just in case */
379183754Sattilio}
38033548Sjkh
38133548Sjkhvoid
38233548SjkhOF_reboot()
38333548Sjkh{
3842893Sdfr	int retval;	/* dummy, this may not be needed */
38533548Sjkh
3862893Sdfr	OF_interpret("reset-all", 1, &retval);
387149720Sssouhlal	for (;;);	/* just in case */
3882893Sdfr}
3892893Sdfr
3902893Sdfrvoid
39133548SjkhOF_getetheraddr(device_t dev, u_char *addr)
39233548Sjkh{
39333548Sjkh	phandle_t	node;
394138471Sphk
39533548Sjkh	node = ofw_bus_get_node(dev);
396134345Stjr	OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
397191990Sattilio}
3982893Sdfr
3992893Sdfr/*
400171757Sbde * Return a bus handle and bus tag that corresponds to the register
401138471Sphk * numbered regno for the device referenced by the package handle
4022893Sdfr * dev. This function is intended to be used by console drivers in
403138471Sphk * early boot only. It works by mapping the address of the device's
4042893Sdfr * register in the address space of its parent and recursively walk
40533548Sjkh * the device tree upward this way.
4062893Sdfr */
4072893Sdfrstatic void
40812144SphkOF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
409183754Sattilio{
4102893Sdfr	char name[16];
41133548Sjkh	uint32_t addr, size;
41233548Sjkh	int pci, res;
413189120Sjhb
4142893Sdfr	res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
4152893Sdfr	if (res == -1)
4162893Sdfr		addr = 2;
41733548Sjkh	res = OF_getprop(node, "#size-cells", &size, sizeof(size));
41833548Sjkh	if (res == -1)
41955188Sbp		size = 1;
420171757Sbde	pci = 0;
421137036Sphk	if (addr == 3 && size == 2) {
422137036Sphk		res = OF_getprop(node, "name", name, sizeof(name));
4232893Sdfr		if (res != -1) {
424189120Sjhb			name[sizeof(name) - 1] = '\0';
425189120Sjhb			pci = (strcmp(name, "pci") == 0) ? 1 : 0;
426171551Sbde		}
427189120Sjhb	}
428189120Sjhb	if (addrp != NULL)
429189120Sjhb		*addrp = addr;
430137036Sphk	if (sizep != NULL)
431137036Sphk		*sizep = size;
432171551Sbde	if (pcip != NULL)
433137036Sphk		*pcip = pci;
434137036Sphk}
435175294Sattilio
4363152Sphkint
437189120SjhbOF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
43833548Sjkh    bus_space_handle_t *handle)
439137036Sphk{
44033548Sjkh	uint32_t cell[32];
4412893Sdfr	bus_addr_t addr, raddr, baddr;
44233548Sjkh	bus_size_t size, rsize;
44333548Sjkh	uint32_t c, nbridge, naddr, nsize;
44456674Snyan	phandle_t bridge, parent;
445171408Sbde	u_int spc, rspc;
4462893Sdfr	int pci, pcib, res;
447171408Sbde
4483152Sphk	/* Sanity checking. */
4492893Sdfr	if (dev == 0)
45033548Sjkh		return (EINVAL);
45133548Sjkh	bridge = OF_parent(dev);
45233548Sjkh	if (bridge == 0)
45333548Sjkh		return (EINVAL);
454105655Sjhb	if (regno < 0)
45533548Sjkh		return (EINVAL);
45656674Snyan	if (tag == NULL || handle == NULL)
45787068Sjhb		return (EINVAL);
45887068Sjhb
45987068Sjhb	/* Get the requested register. */
46087068Sjhb	OF_get_addr_props(bridge, &naddr, &nsize, &pci);
46187068Sjhb	res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
46256674Snyan	    cell, sizeof(cell));
4632893Sdfr	if (res == -1)
464111119Simp		return (ENXIO);
4652893Sdfr	if (res % sizeof(cell[0]))
466137036Sphk		return (ENXIO);
467137036Sphk	res /= sizeof(cell[0]);
4682893Sdfr	regno *= naddr + nsize;
4692893Sdfr	if (regno + naddr + nsize > res)
470171551Sbde		return (EINVAL);
471173728Smaxim	spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
472171551Sbde	addr = 0;
473171551Sbde	for (c = 0; c < naddr; c++)
474171551Sbde		addr = ((uint64_t)addr << 32) | cell[regno++];
475171551Sbde	size = 0;
476171551Sbde	for (c = 0; c < nsize; c++)
477171551Sbde		size = ((uint64_t)size << 32) | cell[regno++];
478171551Sbde
479166340Srodrigc	/*
480166340Srodrigc	 * Map the address range in the bridge's decoding window as given
481166340Srodrigc	 * by the "ranges" property. If a node doesn't have such property
482166340Srodrigc	 * then no mapping is done.
483166340Srodrigc	 */
484166340Srodrigc	parent = OF_parent(bridge);
485166340Srodrigc	while (parent != 0) {
486166340Srodrigc		OF_get_addr_props(parent, &nbridge, NULL, &pcib);
487166340Srodrigc		res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
488166340Srodrigc		if (res == -1)
489166340Srodrigc			goto next;
490171757Sbde		if (res % sizeof(cell[0]))
491166340Srodrigc			return (ENXIO);
492166340Srodrigc		res /= sizeof(cell[0]);
4932893Sdfr		regno = 0;
4942893Sdfr		while (regno < res) {
4952893Sdfr			rspc = (pci)
4962893Sdfr			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
49733548Sjkh			    : ~0;
4982893Sdfr			if (rspc != spc) {
499113979Sjhb				regno += naddr + nbridge + nsize;
500113979Sjhb				continue;
501113979Sjhb			}
502113979Sjhb			raddr = 0;
5032893Sdfr			for (c = 0; c < naddr; c++)
5042893Sdfr				raddr = ((uint64_t)raddr << 32) | cell[regno++];
5052893Sdfr			rspc = (pcib)
5062893Sdfr			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
5072893Sdfr			    : ~0;
5082893Sdfr			baddr = 0;
5092893Sdfr			for (c = 0; c < nbridge; c++)
51033548Sjkh				baddr = ((uint64_t)baddr << 32) | cell[regno++];
5112893Sdfr			rsize = 0;
51256674Snyan			for (c = 0; c < nsize; c++)
51356674Snyan				rsize = ((uint64_t)rsize << 32) | cell[regno++];
51456674Snyan			if (addr < raddr || addr >= raddr + rsize)
515176431Smarcel				continue;
516176431Smarcel			addr = addr - raddr + baddr;
517176431Smarcel			if (rspc != ~0)
518176431Smarcel				spc = rspc;
519176431Smarcel		}
520176431Smarcel
521176431Smarcel	next:
52287068Sjhb		bridge = parent;
52387068Sjhb		parent = OF_parent(bridge);
52487068Sjhb		OF_get_addr_props(bridge, &naddr, &nsize, &pci);
5252893Sdfr	}
5262893Sdfr
5272893Sdfr	*tag = &bs_le_tag;
5282893Sdfr	return (bus_space_map(*tag, addr, size, 0, handle));
5292893Sdfr}
5302893Sdfr
5312893Sdfrint
5322893Sdfrmem_valid(vm_offset_t addr, int len)
533166340Srodrigc{
534171757Sbde	int i;
535166340Srodrigc
536166340Srodrigc	for (i = 0; i < OFMEM_REGIONS; i++)
537166340Srodrigc		if ((addr >= OFmem[i].mr_start)
538166340Srodrigc		    && (addr + len < OFmem[i].mr_start + OFmem[i].mr_size))
539166340Srodrigc			return (0);
540166340Srodrigc
541166340Srodrigc	return (EFAULT);
542166340Srodrigc}
543166340Srodrigc
544166340Srodrigc