ofw_machdep.c revision 215067
1139825Simp/*-
277957Sbenno * Copyright (C) 1996 Wolfgang Solfrank.
377957Sbenno * Copyright (C) 1996 TooLs GmbH.
477957Sbenno * All rights reserved.
577957Sbenno *
677957Sbenno * Redistribution and use in source and binary forms, with or without
777957Sbenno * modification, are permitted provided that the following conditions
877957Sbenno * are met:
977957Sbenno * 1. Redistributions of source code must retain the above copyright
1077957Sbenno *    notice, this list of conditions and the following disclaimer.
1177957Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1277957Sbenno *    notice, this list of conditions and the following disclaimer in the
1377957Sbenno *    documentation and/or other materials provided with the distribution.
1477957Sbenno * 3. All advertising materials mentioning features or use of this software
1577957Sbenno *    must display the following acknowledgement:
1677957Sbenno *	This product includes software developed by TooLs GmbH.
1777957Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products
1877957Sbenno *    derived from this software without specific prior written permission.
1977957Sbenno *
2077957Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2177957Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2277957Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2377957Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2477957Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2577957Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2677957Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2777957Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2877957Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2977957Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3077957Sbenno *
3177957Sbenno * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
3277957Sbenno */
3377957Sbenno
34113038Sobrien#include <sys/cdefs.h>
35113038Sobrien__FBSDID("$FreeBSD: head/sys/powerpc/aim/ofw_machdep.c 215067 2010-11-09 23:53:47Z nwhitehorn $");
3677957Sbenno
3777957Sbenno#include <sys/param.h>
3877957Sbenno#include <sys/bus.h>
3977957Sbenno#include <sys/systm.h>
4077957Sbenno#include <sys/conf.h>
4177957Sbenno#include <sys/disk.h>
4277957Sbenno#include <sys/fcntl.h>
4377957Sbenno#include <sys/malloc.h>
44208364Snwhitehorn#include <sys/smp.h>
4577957Sbenno#include <sys/stat.h>
4677957Sbenno
4799665Sbenno#include <net/ethernet.h>
4899665Sbenno
4977957Sbenno#include <dev/ofw/openfirm.h>
50165151Smarcel#include <dev/ofw/ofw_pci.h>
51183882Snwhitehorn#include <dev/ofw/ofw_bus.h>
5277957Sbenno
5390643Sbenno#include <vm/vm.h>
5490643Sbenno#include <vm/vm_param.h>
5590643Sbenno#include <vm/vm_page.h>
5690643Sbenno
57160714Smarcel#include <machine/bus.h>
58199886Snwhitehorn#include <machine/cpu.h>
59160714Smarcel#include <machine/md_var.h>
60192067Snwhitehorn#include <machine/platform.h>
6199030Sbenno#include <machine/ofw_machdep.h>
6277957Sbenno
6377957Sbenno#define	OFMEM_REGIONS	32
6477957Sbennostatic struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
65123370Sgrehanstatic struct mem_region OFfree[OFMEM_REGIONS + 3];
66209975Snwhitehornstatic int nOFmem;
6777957Sbenno
68151891Sgrehanextern register_t ofmsr[5];
6990643Sbennoextern struct	pmap ofw_pmap;
7077957Sbennostatic int	(*ofwcall)(void *);
71186347Snwhitehornstatic void	*fdt;
72186347Snwhitehornint		ofw_real_mode;
7377957Sbenno
74209975Snwhitehornint		ofw_32bit_mode_entry(void *);
75208172Snwhitehornstatic void	ofw_quiesce(void);
76186347Snwhitehornstatic int	openfirmware(void *args);
77186347Snwhitehorn
7877957Sbenno/*
79151891Sgrehan * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
80151891Sgrehan */
81151891Sgrehanregister_t	ofw_sprg0_save;
82151891Sgrehan
83151891Sgrehanstatic __inline void
84151891Sgrehanofw_sprg_prepare(void)
85151891Sgrehan{
86151891Sgrehan	/*
87151891Sgrehan	 * Assume that interrupt are disabled at this point, or
88151891Sgrehan	 * SPRG1-3 could be trashed
89151891Sgrehan	 */
90151891Sgrehan	__asm __volatile("mfsprg0 %0\n\t"
91151891Sgrehan			 "mtsprg0 %1\n\t"
92151891Sgrehan	    		 "mtsprg1 %2\n\t"
93151891Sgrehan	    		 "mtsprg2 %3\n\t"
94151891Sgrehan			 "mtsprg3 %4\n\t"
95151891Sgrehan			 : "=&r"(ofw_sprg0_save)
96151891Sgrehan			 : "r"(ofmsr[1]),
97151891Sgrehan			 "r"(ofmsr[2]),
98151891Sgrehan			 "r"(ofmsr[3]),
99151891Sgrehan			 "r"(ofmsr[4]));
100151891Sgrehan}
101151891Sgrehan
102151891Sgrehanstatic __inline void
103151891Sgrehanofw_sprg_restore(void)
104151891Sgrehan{
105151891Sgrehan	/*
106151891Sgrehan	 * Note that SPRG1-3 contents are irrelevant. They are scratch
107151891Sgrehan	 * registers used in the early portion of trap handling when
108151891Sgrehan	 * interrupts are disabled.
109151891Sgrehan	 *
110151891Sgrehan	 * PCPU data cannot be used until this routine is called !
111151891Sgrehan	 */
112151891Sgrehan	__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
113151891Sgrehan}
114151891Sgrehan
115151891Sgrehan/*
116123370Sgrehan * Memory region utilities: determine if two regions overlap,
117123370Sgrehan * and merge two overlapping regions into one
118123370Sgrehan */
119123370Sgrehanstatic int
120123370Sgrehanmemr_overlap(struct mem_region *r1, struct mem_region *r2)
121123370Sgrehan{
122123370Sgrehan	if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
123123370Sgrehan	    (r2->mr_start + r2->mr_size) < r1->mr_start)
124123370Sgrehan		return (FALSE);
125123370Sgrehan
126123370Sgrehan	return (TRUE);
127123370Sgrehan}
128123370Sgrehan
129123370Sgrehanstatic void
130123370Sgrehanmemr_merge(struct mem_region *from, struct mem_region *to)
131123370Sgrehan{
132209975Snwhitehorn	vm_offset_t end;
133209975Snwhitehorn	end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
134209975Snwhitehorn	to->mr_start = ulmin(from->mr_start, to->mr_start);
135123370Sgrehan	to->mr_size = end - to->mr_start;
136123370Sgrehan}
137123370Sgrehan
138209975Snwhitehornstatic int
139209975Snwhitehornparse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
14077957Sbenno{
141209975Snwhitehorn	cell_t address_cells, size_cells;
142209975Snwhitehorn	cell_t OFmem[4*(OFMEM_REGIONS + 1)];
143209975Snwhitehorn	int sz, i, j;
144209975Snwhitehorn	int apple_hack_mode;
145190681Snwhitehorn	phandle_t phandle;
146190681Snwhitehorn
147209975Snwhitehorn	sz = 0;
148209975Snwhitehorn	apple_hack_mode = 0;
149190681Snwhitehorn
150190681Snwhitehorn	/*
151190681Snwhitehorn	 * Get #address-cells from root node, defaulting to 1 if it cannot
152190681Snwhitehorn	 * be found.
153190681Snwhitehorn	 */
154190681Snwhitehorn	phandle = OF_finddevice("/");
155190681Snwhitehorn	if (OF_getprop(phandle, "#address-cells", &address_cells,
156190681Snwhitehorn	    sizeof(address_cells)) < sizeof(address_cells))
157190681Snwhitehorn		address_cells = 1;
158209975Snwhitehorn	if (OF_getprop(phandle, "#size-cells", &size_cells,
159209975Snwhitehorn	    sizeof(size_cells)) < sizeof(size_cells))
160209975Snwhitehorn		size_cells = 1;
161209975Snwhitehorn
162209975Snwhitehorn	/*
163209975Snwhitehorn	 * On Apple hardware, address_cells is always 1 for "available",
164209975Snwhitehorn	 * even when it is explicitly set to 2. Then all memory above 4 GB
165209975Snwhitehorn	 * should be added by hand to the available list. Detect Apple hardware
166209975Snwhitehorn	 * by seeing if ofw_real_mode is set -- only Apple seems to use
167209975Snwhitehorn	 * virtual-mode OF.
168209975Snwhitehorn	 */
169209975Snwhitehorn	if (strcmp(prop, "available") == 0 && !ofw_real_mode)
170209975Snwhitehorn		apple_hack_mode = 1;
17177957Sbenno
172209975Snwhitehorn	if (apple_hack_mode)
173209975Snwhitehorn		address_cells = 1;
174209975Snwhitehorn
17577957Sbenno	/*
17677957Sbenno	 * Get memory.
17777957Sbenno	 */
178209975Snwhitehorn	if ((node == -1) || (sz = OF_getprop(node, prop,
179209975Snwhitehorn	    OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0)
180209975Snwhitehorn		panic("Physical memory map not found");
181190681Snwhitehorn
182209975Snwhitehorn	i = 0;
183209975Snwhitehorn	j = 0;
184209975Snwhitehorn	while (i < sz/sizeof(cell_t)) {
185209975Snwhitehorn	      #ifndef __powerpc64__
186209975Snwhitehorn		/* On 32-bit PPC, ignore regions starting above 4 GB */
187209975Snwhitehorn		if (address_cells > 1 && OFmem[i] > 0) {
188209975Snwhitehorn			i += address_cells + size_cells;
189209975Snwhitehorn			continue;
190190681Snwhitehorn		}
191209975Snwhitehorn	      #endif
192190681Snwhitehorn
193209975Snwhitehorn		output[j].mr_start = OFmem[i++];
194209975Snwhitehorn		if (address_cells == 2) {
195209975Snwhitehorn			#ifdef __powerpc64__
196209975Snwhitehorn			output[j].mr_start <<= 32;
197209975Snwhitehorn			#endif
198209975Snwhitehorn			output[j].mr_start += OFmem[i++];
199190681Snwhitehorn		}
200209975Snwhitehorn
201209975Snwhitehorn		output[j].mr_size = OFmem[i++];
202209975Snwhitehorn		if (size_cells == 2) {
203209975Snwhitehorn			#ifdef __powerpc64__
204209975Snwhitehorn			output[j].mr_size <<= 32;
205209975Snwhitehorn			#endif
206209975Snwhitehorn			output[j].mr_size += OFmem[i++];
207209975Snwhitehorn		}
208190681Snwhitehorn
209209975Snwhitehorn	      #ifndef __powerpc64__
210209975Snwhitehorn		/*
211209975Snwhitehorn		 * Check for memory regions extending above 32-bit
212209975Snwhitehorn		 * memory space, and restrict them to stay there.
213209975Snwhitehorn		 */
214209975Snwhitehorn		if (((uint64_t)output[j].mr_start +
215209975Snwhitehorn		    (uint64_t)output[j].mr_size) >
216209975Snwhitehorn		    BUS_SPACE_MAXADDR_32BIT) {
217209975Snwhitehorn			output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
218209975Snwhitehorn			    output[j].mr_start;
219209975Snwhitehorn		}
220209975Snwhitehorn	      #endif
221190681Snwhitehorn
222209975Snwhitehorn		j++;
223209975Snwhitehorn	}
224209975Snwhitehorn	sz = j*sizeof(output[0]);
225209975Snwhitehorn
226209975Snwhitehorn	#ifdef __powerpc64__
227209975Snwhitehorn	if (apple_hack_mode) {
228209975Snwhitehorn		/* Add in regions above 4 GB to the available list */
229209975Snwhitehorn		struct mem_region himem[OFMEM_REGIONS];
230209975Snwhitehorn		int hisz;
231209975Snwhitehorn
232209975Snwhitehorn		hisz = parse_ofw_memory(node, "reg", himem);
233209975Snwhitehorn		for (i = 0; i < hisz/sizeof(himem[0]); i++) {
234209975Snwhitehorn			if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
235209975Snwhitehorn				output[j].mr_start = himem[i].mr_start;
236209975Snwhitehorn				output[j].mr_size = himem[i].mr_size;
237209975Snwhitehorn				j++;
238190681Snwhitehorn			}
239190681Snwhitehorn		}
240209975Snwhitehorn		sz = j*sizeof(output[0]);
241190681Snwhitehorn	}
242209975Snwhitehorn	#endif
243190681Snwhitehorn
244209975Snwhitehorn	return (sz);
245209975Snwhitehorn}
246209975Snwhitehorn
247209975Snwhitehorn/*
248209975Snwhitehorn * This is called during powerpc_init, before the system is really initialized.
249209975Snwhitehorn * It shall provide the total and the available regions of RAM.
250209975Snwhitehorn * Both lists must have a zero-size entry as terminator.
251209975Snwhitehorn * The available regions need not take the kernel into account, but needs
252209975Snwhitehorn * to provide space for two additional entry beyond the terminating one.
253209975Snwhitehorn */
254209975Snwhitehornvoid
255209975Snwhitehornofw_mem_regions(struct mem_region **memp, int *memsz,
256209975Snwhitehorn		struct mem_region **availp, int *availsz)
257209975Snwhitehorn{
258209975Snwhitehorn	phandle_t phandle;
259209975Snwhitehorn	int asz, msz, fsz;
260209975Snwhitehorn	int i, j;
261209975Snwhitehorn	int still_merging;
262209975Snwhitehorn
263209975Snwhitehorn	asz = msz = 0;
264209975Snwhitehorn
265209975Snwhitehorn	/*
266209975Snwhitehorn	 * Get memory.
267209975Snwhitehorn	 */
268209975Snwhitehorn	phandle = OF_finddevice("/memory");
269209975Snwhitehorn	if (phandle == -1)
270209975Snwhitehorn		phandle = OF_finddevice("/memory@0");
271209975Snwhitehorn
272209975Snwhitehorn	msz = parse_ofw_memory(phandle, "reg", OFmem);
273209975Snwhitehorn	nOFmem = msz / sizeof(struct mem_region);
274209975Snwhitehorn	asz = parse_ofw_memory(phandle, "available", OFavail);
275209975Snwhitehorn
27677957Sbenno	*memp = OFmem;
277209975Snwhitehorn	*memsz = nOFmem;
278190681Snwhitehorn
279123370Sgrehan	/*
280123370Sgrehan	 * OFavail may have overlapping regions - collapse these
281123370Sgrehan	 * and copy out remaining regions to OFfree
282123370Sgrehan	 */
283123370Sgrehan	asz /= sizeof(struct mem_region);
284123370Sgrehan	do {
285123370Sgrehan		still_merging = FALSE;
286123370Sgrehan		for (i = 0; i < asz; i++) {
287123370Sgrehan			if (OFavail[i].mr_size == 0)
288123370Sgrehan				continue;
289123370Sgrehan			for (j = i+1; j < asz; j++) {
290123370Sgrehan				if (OFavail[j].mr_size == 0)
291123370Sgrehan					continue;
292123370Sgrehan				if (memr_overlap(&OFavail[j], &OFavail[i])) {
293123370Sgrehan					memr_merge(&OFavail[j], &OFavail[i]);
294123370Sgrehan					/* mark inactive */
295123370Sgrehan					OFavail[j].mr_size = 0;
296123370Sgrehan					still_merging = TRUE;
297123370Sgrehan				}
298123370Sgrehan			}
299123370Sgrehan		}
300123370Sgrehan	} while (still_merging == TRUE);
301123370Sgrehan
302123370Sgrehan	/* evict inactive ranges */
303123370Sgrehan	for (i = 0, fsz = 0; i < asz; i++) {
304123370Sgrehan		if (OFavail[i].mr_size != 0) {
305123370Sgrehan			OFfree[fsz] = OFavail[i];
306123370Sgrehan			fsz++;
307123370Sgrehan		}
308123370Sgrehan	}
309123370Sgrehan
310123370Sgrehan	*availp = OFfree;
311123370Sgrehan	*availsz = fsz;
31277957Sbenno}
31377957Sbenno
31477957Sbennovoid
315186347SnwhitehornOF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
31677957Sbenno{
317186347Snwhitehorn	if (ofmsr[0] & PSL_DR)
318186347Snwhitehorn		ofw_real_mode = 0;
319186347Snwhitehorn	else
320186347Snwhitehorn		ofw_real_mode = 1;
32177957Sbenno
322209975Snwhitehorn	ofwcall = NULL;
323209975Snwhitehorn
324209975Snwhitehorn	#ifdef __powerpc64__
325209975Snwhitehorn		/*
326209975Snwhitehorn		 * For PPC64, we need to use some hand-written
327209975Snwhitehorn		 * asm trampolines to get to OF.
328209975Snwhitehorn		 */
329209975Snwhitehorn		if (openfirm != NULL)
330209975Snwhitehorn			ofwcall = ofw_32bit_mode_entry;
331209975Snwhitehorn	#else
332209975Snwhitehorn		ofwcall = openfirm;
333209975Snwhitehorn	#endif
334209975Snwhitehorn
335186347Snwhitehorn	fdt = fdt_ptr;
336215067Snwhitehorn
337215067Snwhitehorn	#ifdef FDT_DTB_STATIC
338215067Snwhitehorn	/* Check for a statically included blob */
339215067Snwhitehorn	if (fdt == NULL)
340215067Snwhitehorn		fdt = &fdt_static_dtb;
341215067Snwhitehorn	#endif
34277957Sbenno}
34377957Sbenno
344186347Snwhitehornboolean_t
345186347SnwhitehornOF_bootstrap()
346186347Snwhitehorn{
347186347Snwhitehorn	boolean_t status = FALSE;
348186347Snwhitehorn
349186347Snwhitehorn	if (ofwcall != NULL) {
350209975Snwhitehorn		if (ofw_real_mode) {
351186347Snwhitehorn			status = OF_install(OFW_STD_REAL, 0);
352209975Snwhitehorn		} else {
353209975Snwhitehorn			#ifdef __powerpc64__
354209975Snwhitehorn			status = OF_install(OFW_STD_32BIT, 0);
355209975Snwhitehorn			#else
356186347Snwhitehorn			status = OF_install(OFW_STD_DIRECT, 0);
357209975Snwhitehorn			#endif
358209975Snwhitehorn		}
359186347Snwhitehorn
360186347Snwhitehorn		if (status != TRUE)
361186347Snwhitehorn			return status;
362186347Snwhitehorn
363186347Snwhitehorn		OF_init(openfirmware);
364208152Snwhitehorn
365208152Snwhitehorn		/*
366208152Snwhitehorn		 * On some machines, we need to quiesce OF to turn off
367208152Snwhitehorn		 * background processes.
368208152Snwhitehorn		 */
369208172Snwhitehorn		ofw_quiesce();
370215067Snwhitehorn	} else if (fdt != NULL) {
371186347Snwhitehorn		status = OF_install(OFW_FDT, 0);
372186347Snwhitehorn
373186347Snwhitehorn		if (status != TRUE)
374186347Snwhitehorn			return status;
375186347Snwhitehorn
376186347Snwhitehorn		OF_init(fdt);
377186347Snwhitehorn	}
378186347Snwhitehorn
379186347Snwhitehorn	return (status);
380186347Snwhitehorn}
381186347Snwhitehorn
382208172Snwhitehornstatic void
383208172Snwhitehornofw_quiesce(void)
384208172Snwhitehorn{
385208172Snwhitehorn	phandle_t rootnode;
386208172Snwhitehorn	char model[32];
387208172Snwhitehorn	struct {
388208172Snwhitehorn		cell_t name;
389208172Snwhitehorn		cell_t nargs;
390208172Snwhitehorn		cell_t nreturns;
391208172Snwhitehorn	} args;
392208172Snwhitehorn
393208172Snwhitehorn	/*
394208172Snwhitehorn	 * Only quiesce Open Firmware on PowerMac11,2 and 12,1. It is
395208172Snwhitehorn	 * necessary there to shut down a background thread doing fan
396208172Snwhitehorn	 * management, and is harmful on other machines.
397208172Snwhitehorn	 *
398208172Snwhitehorn	 * Note: we don't need to worry about which OF module we are
399208172Snwhitehorn	 * using since this is called only from very early boot, within
400208172Snwhitehorn	 * OF's boot context.
401208172Snwhitehorn	 */
402208172Snwhitehorn
403208172Snwhitehorn	rootnode = OF_finddevice("/");
404208172Snwhitehorn	if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) {
405208172Snwhitehorn		if (strcmp(model, "PowerMac11,2") == 0 ||
406208172Snwhitehorn		    strcmp(model, "PowerMac12,1") == 0) {
407208172Snwhitehorn			args.name = (cell_t)(uintptr_t)"quiesce";
408208172Snwhitehorn			args.nargs = 0;
409208172Snwhitehorn			args.nreturns = 0;
410208172Snwhitehorn			openfirmware(&args);
411208172Snwhitehorn		}
412208172Snwhitehorn	}
413208172Snwhitehorn}
414208172Snwhitehorn
415186347Snwhitehornstatic int
416208364Snwhitehornopenfirmware_core(void *args)
41777957Sbenno{
418209975Snwhitehorn	int		result;
419209975Snwhitehorn	register_t	oldmsr;
420209975Snwhitehorn	#ifndef __powerpc64__
421209975Snwhitehorn	register_t	srsave[16];
422209975Snwhitehorn	u_int		i;
423209975Snwhitehorn	#endif
42477957Sbenno
425209975Snwhitehorn	/*
426209975Snwhitehorn	 * Turn off exceptions - we really don't want to end up
427209975Snwhitehorn	 * anywhere unexpected with PCPU set to something strange,
428209975Snwhitehorn	 * the stack pointer wrong, or the OFW mapping enabled.
429209975Snwhitehorn	 */
430209975Snwhitehorn	oldmsr = intr_disable();
43177957Sbenno
432151891Sgrehan	ofw_sprg_prepare();
433151891Sgrehan
434209975Snwhitehorn      #ifndef __powerpc64__
435186347Snwhitehorn	if (pmap_bootstrapped && !ofw_real_mode) {
43699030Sbenno		/*
437133862Smarius		 * Swap the kernel's address space with Open Firmware's
43899030Sbenno		 */
439209975Snwhitehorn
44099030Sbenno		for (i = 0; i < 16; i++) {
44199030Sbenno			srsave[i] = mfsrin(i << ADDR_SR_SHFT);
44299030Sbenno			mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]);
44399030Sbenno		}
444103602Sgrehan
445103602Sgrehan		/*
446103602Sgrehan		 * Clear battable[] translations
447103602Sgrehan		 */
448199886Snwhitehorn		if (!(cpu_features & PPC_FEATURE_64)) {
449190681Snwhitehorn			__asm __volatile("mtdbatu 2, %0\n"
450190681Snwhitehorn					 "mtdbatu 3, %0" : : "r" (0));
451190681Snwhitehorn		}
45299030Sbenno		isync();
45399030Sbenno	}
454209975Snwhitehorn      #endif
45577957Sbenno
456151891Sgrehan       	result = ofwcall(args);
457151891Sgrehan
458209975Snwhitehorn      #ifndef __powerpc64__
459186347Snwhitehorn	if (pmap_bootstrapped && !ofw_real_mode) {
46099030Sbenno		/*
46199030Sbenno		 * Restore the kernel's addr space. The isync() doesn;t
46299030Sbenno		 * work outside the loop unless mtsrin() is open-coded
46399030Sbenno		 * in an asm statement :(
46499030Sbenno		 */
465209975Snwhitehorn
46699030Sbenno		for (i = 0; i < 16; i++) {
46799030Sbenno			mtsrin(i << ADDR_SR_SHFT, srsave[i]);
46899030Sbenno			isync();
46999030Sbenno		}
47099030Sbenno	}
471209975Snwhitehorn      #endif
47299030Sbenno
473151891Sgrehan	ofw_sprg_restore();
474151891Sgrehan
475209975Snwhitehorn	intr_restore(oldmsr);
47677957Sbenno
477208364Snwhitehorn	return (result);
478208364Snwhitehorn}
479208364Snwhitehorn
480208364Snwhitehorn#ifdef SMP
481208364Snwhitehornstruct ofw_rv_args {
482208364Snwhitehorn	void *args;
483208364Snwhitehorn	int retval;
484208364Snwhitehorn	volatile int in_progress;
485208364Snwhitehorn};
486208364Snwhitehorn
487208364Snwhitehornstatic void
488208364Snwhitehornofw_rendezvous_dispatch(void *xargs)
489208364Snwhitehorn{
490208364Snwhitehorn	struct ofw_rv_args *rv_args = xargs;
491208364Snwhitehorn
492208364Snwhitehorn	/* NOTE: Interrupts are disabled here */
493208364Snwhitehorn
494208364Snwhitehorn	if (PCPU_GET(cpuid) == 0) {
495208364Snwhitehorn		/*
496208364Snwhitehorn		 * Execute all OF calls on CPU 0
497208364Snwhitehorn		 */
498208364Snwhitehorn		rv_args->retval = openfirmware_core(rv_args->args);
499208364Snwhitehorn		rv_args->in_progress = 0;
500208364Snwhitehorn	} else {
501208364Snwhitehorn		/*
502208364Snwhitehorn		 * Spin with interrupts off on other CPUs while OF has
503208364Snwhitehorn		 * control of the machine.
504208364Snwhitehorn		 */
505208364Snwhitehorn		while (rv_args->in_progress)
506208364Snwhitehorn			cpu_spinwait();
507208364Snwhitehorn	}
508208364Snwhitehorn}
509208364Snwhitehorn#endif
510208364Snwhitehorn
511208364Snwhitehornstatic int
512208364Snwhitehornopenfirmware(void *args)
513208364Snwhitehorn{
514208364Snwhitehorn	int result;
515208364Snwhitehorn	#ifdef SMP
516208364Snwhitehorn	struct ofw_rv_args rv_args;
517208364Snwhitehorn	#endif
518208364Snwhitehorn
519208364Snwhitehorn	if (pmap_bootstrapped && ofw_real_mode)
520208364Snwhitehorn		args = (void *)pmap_kextract((vm_offset_t)args);
521208364Snwhitehorn
522208364Snwhitehorn	#ifdef SMP
523208364Snwhitehorn	rv_args.args = args;
524208364Snwhitehorn	rv_args.in_progress = 1;
525208364Snwhitehorn	smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
526208364Snwhitehorn	    smp_no_rendevous_barrier, &rv_args);
527208364Snwhitehorn	result = rv_args.retval;
528208364Snwhitehorn	#else
529208364Snwhitehorn	result = openfirmware_core(args);
530208364Snwhitehorn	#endif
531208364Snwhitehorn
53277957Sbenno	return (result);
53377957Sbenno}
53477957Sbenno
53577957Sbennovoid
536212054SnwhitehornOF_reboot()
537123353Sgallatin{
538212054Snwhitehorn	struct {
539212054Snwhitehorn		cell_t name;
540212054Snwhitehorn		cell_t nargs;
541212054Snwhitehorn		cell_t nreturns;
542212054Snwhitehorn		cell_t arg;
543212054Snwhitehorn	} args;
544123353Sgallatin
545212054Snwhitehorn	args.name = (cell_t)(uintptr_t)"interpret";
546212054Snwhitehorn	args.nargs = 1;
547212054Snwhitehorn	args.nreturns = 0;
548212054Snwhitehorn	args.arg = (cell_t)(uintptr_t)"reset-all";
549212054Snwhitehorn	openfirmware_core(&args); /* Don't do rendezvous! */
550123353Sgallatin
551123353Sgallatin	for (;;);	/* just in case */
552123353Sgallatin}
553123353Sgallatin
554123353Sgallatinvoid
55599665SbennoOF_getetheraddr(device_t dev, u_char *addr)
55699665Sbenno{
55799665Sbenno	phandle_t	node;
55899665Sbenno
559183882Snwhitehorn	node = ofw_bus_get_node(dev);
56099665Sbenno	OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
56199665Sbenno}
562133855Sssouhlal
563160714Smarcel/*
564165151Smarcel * Return a bus handle and bus tag that corresponds to the register
565165151Smarcel * numbered regno for the device referenced by the package handle
566165151Smarcel * dev. This function is intended to be used by console drivers in
567165151Smarcel * early boot only. It works by mapping the address of the device's
568165151Smarcel * register in the address space of its parent and recursively walk
569165151Smarcel * the device tree upward this way.
570160714Smarcel */
571165151Smarcelstatic void
572165151SmarcelOF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
573165151Smarcel{
574165151Smarcel	char name[16];
575165151Smarcel	uint32_t addr, size;
576165151Smarcel	int pci, res;
577165151Smarcel
578165151Smarcel	res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
579165151Smarcel	if (res == -1)
580165151Smarcel		addr = 2;
581165151Smarcel	res = OF_getprop(node, "#size-cells", &size, sizeof(size));
582165151Smarcel	if (res == -1)
583165151Smarcel		size = 1;
584165151Smarcel	pci = 0;
585165151Smarcel	if (addr == 3 && size == 2) {
586165151Smarcel		res = OF_getprop(node, "name", name, sizeof(name));
587165151Smarcel		if (res != -1) {
588165151Smarcel			name[sizeof(name) - 1] = '\0';
589165151Smarcel			pci = (strcmp(name, "pci") == 0) ? 1 : 0;
590165151Smarcel		}
591165151Smarcel	}
592165151Smarcel	if (addrp != NULL)
593165151Smarcel		*addrp = addr;
594165151Smarcel	if (sizep != NULL)
595165151Smarcel		*sizep = size;
596165151Smarcel	if (pcip != NULL)
597165151Smarcel		*pcip = pci;
598165151Smarcel}
599165151Smarcel
600133855Sssouhlalint
601165151SmarcelOF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
602160714Smarcel    bus_space_handle_t *handle)
603160714Smarcel{
604165151Smarcel	uint32_t cell[32];
605165151Smarcel	bus_addr_t addr, raddr, baddr;
606165151Smarcel	bus_size_t size, rsize;
607165151Smarcel	uint32_t c, nbridge, naddr, nsize;
608165151Smarcel	phandle_t bridge, parent;
609165151Smarcel	u_int spc, rspc;
610165151Smarcel	int pci, pcib, res;
611160714Smarcel
612165151Smarcel	/* Sanity checking. */
613165151Smarcel	if (dev == 0)
614165151Smarcel		return (EINVAL);
615165151Smarcel	bridge = OF_parent(dev);
616165151Smarcel	if (bridge == 0)
617165151Smarcel		return (EINVAL);
618165151Smarcel	if (regno < 0)
619165151Smarcel		return (EINVAL);
620165151Smarcel	if (tag == NULL || handle == NULL)
621165151Smarcel		return (EINVAL);
622165151Smarcel
623165151Smarcel	/* Get the requested register. */
624165151Smarcel	OF_get_addr_props(bridge, &naddr, &nsize, &pci);
625165151Smarcel	res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
626165151Smarcel	    cell, sizeof(cell));
627165151Smarcel	if (res == -1)
628165151Smarcel		return (ENXIO);
629165151Smarcel	if (res % sizeof(cell[0]))
630165151Smarcel		return (ENXIO);
631165151Smarcel	res /= sizeof(cell[0]);
632165151Smarcel	regno *= naddr + nsize;
633165151Smarcel	if (regno + naddr + nsize > res)
634165151Smarcel		return (EINVAL);
635165151Smarcel	spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
636165151Smarcel	addr = 0;
637165151Smarcel	for (c = 0; c < naddr; c++)
638165151Smarcel		addr = ((uint64_t)addr << 32) | cell[regno++];
639165151Smarcel	size = 0;
640165151Smarcel	for (c = 0; c < nsize; c++)
641165151Smarcel		size = ((uint64_t)size << 32) | cell[regno++];
642165151Smarcel
643165151Smarcel	/*
644165151Smarcel	 * Map the address range in the bridge's decoding window as given
645165151Smarcel	 * by the "ranges" property. If a node doesn't have such property
646165151Smarcel	 * then no mapping is done.
647165151Smarcel	 */
648165151Smarcel	parent = OF_parent(bridge);
649165151Smarcel	while (parent != 0) {
650165151Smarcel		OF_get_addr_props(parent, &nbridge, NULL, &pcib);
651165151Smarcel		res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
652165151Smarcel		if (res == -1)
653165151Smarcel			goto next;
654165151Smarcel		if (res % sizeof(cell[0]))
655165151Smarcel			return (ENXIO);
656165151Smarcel		res /= sizeof(cell[0]);
657165151Smarcel		regno = 0;
658165151Smarcel		while (regno < res) {
659165151Smarcel			rspc = (pci)
660165151Smarcel			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
661165151Smarcel			    : ~0;
662165151Smarcel			if (rspc != spc) {
663165151Smarcel				regno += naddr + nbridge + nsize;
664165151Smarcel				continue;
665165151Smarcel			}
666165151Smarcel			raddr = 0;
667165151Smarcel			for (c = 0; c < naddr; c++)
668165151Smarcel				raddr = ((uint64_t)raddr << 32) | cell[regno++];
669165151Smarcel			rspc = (pcib)
670165151Smarcel			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
671165151Smarcel			    : ~0;
672165151Smarcel			baddr = 0;
673165151Smarcel			for (c = 0; c < nbridge; c++)
674165151Smarcel				baddr = ((uint64_t)baddr << 32) | cell[regno++];
675165151Smarcel			rsize = 0;
676165151Smarcel			for (c = 0; c < nsize; c++)
677165151Smarcel				rsize = ((uint64_t)rsize << 32) | cell[regno++];
678165151Smarcel			if (addr < raddr || addr >= raddr + rsize)
679165151Smarcel				continue;
680165151Smarcel			addr = addr - raddr + baddr;
681165151Smarcel			if (rspc != ~0)
682165151Smarcel				spc = rspc;
683165151Smarcel		}
684165151Smarcel
685165151Smarcel	next:
686165151Smarcel		bridge = parent;
687165151Smarcel		parent = OF_parent(bridge);
688165151Smarcel		OF_get_addr_props(bridge, &naddr, &nsize, &pci);
689165151Smarcel	}
690165151Smarcel
691174782Smarcel	*tag = &bs_le_tag;
692165151Smarcel	return (bus_space_map(*tag, addr, size, 0, handle));
693160714Smarcel}
694160714Smarcel
695160714Smarcelint
696133855Sssouhlalmem_valid(vm_offset_t addr, int len)
697133855Sssouhlal{
698133855Sssouhlal	int i;
699133855Sssouhlal
700209975Snwhitehorn	for (i = 0; i < nOFmem; i++)
701133855Sssouhlal		if ((addr >= OFmem[i].mr_start)
702133855Sssouhlal		    && (addr + len < OFmem[i].mr_start + OFmem[i].mr_size))
703133855Sssouhlal			return (0);
704133855Sssouhlal
705133855Sssouhlal	return (EFAULT);
706133855Sssouhlal}
707190681Snwhitehorn
708