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