ofw_machdep.c revision 215159
164987Smsmith/*-
273050Smsmith * Copyright (C) 1996 Wolfgang Solfrank.
364987Smsmith * Copyright (C) 1996 TooLs GmbH.
464987Smsmith * All rights reserved.
564987Smsmith *
664987Smsmith * Redistribution and use in source and binary forms, with or without
764987Smsmith * modification, are permitted provided that the following conditions
864987Smsmith * are met:
964987Smsmith * 1. Redistributions of source code must retain the above copyright
1064987Smsmith *    notice, this list of conditions and the following disclaimer.
1164987Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1264987Smsmith *    notice, this list of conditions and the following disclaimer in the
1364987Smsmith *    documentation and/or other materials provided with the distribution.
1464987Smsmith * 3. All advertising materials mentioning features or use of this software
1564987Smsmith *    must display the following acknowledgement:
1664987Smsmith *	This product includes software developed by TooLs GmbH.
1764987Smsmith * 4. The name of TooLs GmbH may not be used to endorse or promote products
1864987Smsmith *    derived from this software without specific prior written permission.
1964987Smsmith *
2064987Smsmith * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2164987Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2264987Smsmith * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2364987Smsmith * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2464987Smsmith * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2564987Smsmith * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2664987Smsmith * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2764987Smsmith * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2864987Smsmith * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2964987Smsmith * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3064987Smsmith *
3164987Smsmith * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
3264987Smsmith */
3364987Smsmith
3464987Smsmith#include <sys/cdefs.h>
3564987Smsmith__FBSDID("$FreeBSD: head/sys/powerpc/aim/ofw_machdep.c 215159 2010-11-12 04:18:19Z nwhitehorn $");
3664987Smsmith
3779695Smsmith#include <sys/param.h>
3873050Smsmith#include <sys/bus.h>
3973050Smsmith#include <sys/systm.h>
4064987Smsmith#include <sys/conf.h>
4164987Smsmith#include <sys/disk.h>
4264987Smsmith#include <sys/fcntl.h>
4364987Smsmith#include <sys/malloc.h>
4464987Smsmith#include <sys/smp.h>
4564987Smsmith#include <sys/stat.h>
4679695Smsmith
4779695Smsmith#include <net/ethernet.h>
4879695Smsmith
4979695Smsmith#include <dev/ofw/openfirm.h>
5079695Smsmith#include <dev/ofw/ofw_pci.h>
5164987Smsmith#include <dev/ofw/ofw_bus.h>
5279695Smsmith
5364987Smsmith#include <vm/vm.h>
5479695Smsmith#include <vm/vm_param.h>
5579695Smsmith#include <vm/vm_page.h>
5679695Smsmith
5764987Smsmith#include <machine/bus.h>
5873050Smsmith#include <machine/cpu.h>
5964987Smsmith#include <machine/md_var.h>
6064987Smsmith#include <machine/platform.h>
6164987Smsmith#include <machine/ofw_machdep.h>
6279695Smsmith
6379695Smsmith#define	OFMEM_REGIONS	32
6479695Smsmithstatic struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
6579695Smsmithstatic struct mem_region OFfree[OFMEM_REGIONS + 3];
6679695Smsmithstatic int nOFmem;
6779695Smsmith
6879695Smsmithextern register_t ofmsr[5];
6979695Smsmithextern struct	pmap ofw_pmap;
7079695Smsmithstatic int	(*ofwcall)(void *);
7179695Smsmithstatic void	*fdt;
7279695Smsmithint		ofw_real_mode;
7379695Smsmith
7479695Smsmithint		ofw_32bit_mode_entry(void *);
7564987Smsmithstatic void	ofw_quiesce(void);
7664987Smsmithstatic int	openfirmware(void *args);
7764987Smsmith
7864987Smsmith/*
7964987Smsmith * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
8064987Smsmith */
8164987Smsmithregister_t	ofw_sprg0_save;
8264987Smsmith
8364987Smsmithstatic __inline void
8479695Smsmithofw_sprg_prepare(void)
8564987Smsmith{
8664987Smsmith	/*
8764987Smsmith	 * Assume that interrupt are disabled at this point, or
8864987Smsmith	 * SPRG1-3 could be trashed
8964987Smsmith	 */
9064987Smsmith	__asm __volatile("mfsprg0 %0\n\t"
9164987Smsmith			 "mtsprg0 %1\n\t"
9279695Smsmith	    		 "mtsprg1 %2\n\t"
9364987Smsmith	    		 "mtsprg2 %3\n\t"
9464987Smsmith			 "mtsprg3 %4\n\t"
9579695Smsmith			 : "=&r"(ofw_sprg0_save)
9679695Smsmith			 : "r"(ofmsr[1]),
9773050Smsmith			 "r"(ofmsr[2]),
9873050Smsmith			 "r"(ofmsr[3]),
9979695Smsmith			 "r"(ofmsr[4]));
10064987Smsmith}
10164987Smsmith
10264987Smsmithstatic __inline void
10379695Smsmithofw_sprg_restore(void)
10479695Smsmith{
10579695Smsmith	/*
10679695Smsmith	 * Note that SPRG1-3 contents are irrelevant. They are scratch
10779695Smsmith	 * registers used in the early portion of trap handling when
10879695Smsmith	 * interrupts are disabled.
10979695Smsmith	 *
11079695Smsmith	 * PCPU data cannot be used until this routine is called !
11179695Smsmith	 */
11279695Smsmith	__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
11379695Smsmith}
11464987Smsmith
11564987Smsmith/*
11664987Smsmith * Memory region utilities: determine if two regions overlap,
11764987Smsmith * and merge two overlapping regions into one
11864987Smsmith */
11964987Smsmithstatic int
12064987Smsmithmemr_overlap(struct mem_region *r1, struct mem_region *r2)
12164987Smsmith{
12264987Smsmith	if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
12373050Smsmith	    (r2->mr_start + r2->mr_size) < r1->mr_start)
124110479Sscottl		return (FALSE);
12564987Smsmith
12679695Smsmith	return (TRUE);
12773050Smsmith}
12873050Smsmith
12973050Smsmithstatic void
13073050Smsmithmemr_merge(struct mem_region *from, struct mem_region *to)
13173050Smsmith{
13273050Smsmith	vm_offset_t end;
133110479Sscottl	end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
13479695Smsmith	to->mr_start = ulmin(from->mr_start, to->mr_start);
13579695Smsmith	to->mr_size = end - to->mr_start;
13679695Smsmith}
13779695Smsmith
13879695Smsmithstatic int
13979695Smsmithparse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
14079695Smsmith{
14179695Smsmith	cell_t address_cells, size_cells;
14279695Smsmith	cell_t OFmem[4*(OFMEM_REGIONS + 1)];
14379695Smsmith	int sz, i, j;
14479695Smsmith	int apple_hack_mode;
14579695Smsmith	phandle_t phandle;
14679695Smsmith
14779695Smsmith	sz = 0;
14879695Smsmith	apple_hack_mode = 0;
14979695Smsmith
15079695Smsmith	/*
15179695Smsmith	 * Get #address-cells from root node, defaulting to 1 if it cannot
15279695Smsmith	 * be found.
15373050Smsmith	 */
15473050Smsmith	phandle = OF_finddevice("/");
15573050Smsmith	if (OF_getprop(phandle, "#address-cells", &address_cells,
156111815Sphk	    sizeof(address_cells)) < sizeof(address_cells))
157111815Sphk		address_cells = 1;
158111815Sphk	if (OF_getprop(phandle, "#size-cells", &size_cells,
159111815Sphk	    sizeof(size_cells)) < sizeof(size_cells))
160111815Sphk		size_cells = 1;
16173050Smsmith
16273050Smsmith	/*
16364987Smsmith	 * On Apple hardware, address_cells is always 1 for "available",
16464987Smsmith	 * even when it is explicitly set to 2. Then all memory above 4 GB
16564987Smsmith	 * should be added by hand to the available list. Detect Apple hardware
16664987Smsmith	 * by seeing if ofw_real_mode is set -- only Apple seems to use
16764987Smsmith	 * virtual-mode OF.
16864987Smsmith	 */
16979695Smsmith	if (strcmp(prop, "available") == 0 && !ofw_real_mode)
17079695Smsmith		apple_hack_mode = 1;
17179695Smsmith
17279695Smsmith	if (apple_hack_mode)
17379695Smsmith		address_cells = 1;
17479695Smsmith
17579695Smsmith	/*
17679695Smsmith	 * Get memory.
17779695Smsmith	 */
17879695Smsmith	if ((node == -1) || (sz = OF_getprop(node, prop,
17979695Smsmith	    OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0)
18079695Smsmith		panic("Physical memory map not found");
18179695Smsmith
18279695Smsmith	i = 0;
18379695Smsmith	j = 0;
18479695Smsmith	while (i < sz/sizeof(cell_t)) {
18579695Smsmith	      #ifndef __powerpc64__
18664987Smsmith		/* On 32-bit PPC, ignore regions starting above 4 GB */
18779695Smsmith		if (address_cells > 1 && OFmem[i] > 0) {
18879695Smsmith			i += address_cells + size_cells;
18979695Smsmith			continue;
19079695Smsmith		}
19179695Smsmith	      #endif
19279695Smsmith
19379695Smsmith		output[j].mr_start = OFmem[i++];
19479695Smsmith		if (address_cells == 2) {
19579695Smsmith			#ifdef __powerpc64__
19679695Smsmith			output[j].mr_start <<= 32;
19779695Smsmith			#endif
19879695Smsmith			output[j].mr_start += OFmem[i++];
19979695Smsmith		}
20079695Smsmith
20179695Smsmith		output[j].mr_size = OFmem[i++];
20279695Smsmith		if (size_cells == 2) {
20379695Smsmith			#ifdef __powerpc64__
20479695Smsmith			output[j].mr_size <<= 32;
20579695Smsmith			#endif
20679695Smsmith			output[j].mr_size += OFmem[i++];
20779695Smsmith		}
20879695Smsmith
20979695Smsmith	      #ifndef __powerpc64__
21079695Smsmith		/*
21179695Smsmith		 * Check for memory regions extending above 32-bit
21279695Smsmith		 * memory space, and restrict them to stay there.
21379695Smsmith		 */
21464987Smsmith		if (((uint64_t)output[j].mr_start +
21564987Smsmith		    (uint64_t)output[j].mr_size) >
216105215Sphk		    BUS_SPACE_MAXADDR_32BIT) {
21779695Smsmith			output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
21864987Smsmith			    output[j].mr_start;
21979695Smsmith		}
22079695Smsmith	      #endif
22164987Smsmith
22264987Smsmith		j++;
22364987Smsmith	}
22479695Smsmith	sz = j*sizeof(output[0]);
22579695Smsmith
22679695Smsmith	#ifdef __powerpc64__
22779695Smsmith	if (apple_hack_mode) {
22879695Smsmith		/* Add in regions above 4 GB to the available list */
22979695Smsmith		struct mem_region himem[OFMEM_REGIONS];
23079695Smsmith		int hisz;
23164987Smsmith
23279695Smsmith		hisz = parse_ofw_memory(node, "reg", himem);
23379695Smsmith		for (i = 0; i < hisz/sizeof(himem[0]); i++) {
23479695Smsmith			if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
23579695Smsmith				output[j].mr_start = himem[i].mr_start;
23679695Smsmith				output[j].mr_size = himem[i].mr_size;
23779695Smsmith				j++;
23864987Smsmith			}
23964987Smsmith		}
24073050Smsmith		sz = j*sizeof(output[0]);
24173050Smsmith	}
24273050Smsmith	#endif
24364987Smsmith
24464987Smsmith	return (sz);
24564987Smsmith}
24664987Smsmith
24764987Smsmith/*
24864987Smsmith * This is called during powerpc_init, before the system is really initialized.
24964987Smsmith * It shall provide the total and the available regions of RAM.
25064987Smsmith * Both lists must have a zero-size entry as terminator.
25164987Smsmith * The available regions need not take the kernel into account, but needs
25264987Smsmith * to provide space for two additional entry beyond the terminating one.
25364987Smsmith */
25464987Smsmithvoid
25564987Smsmithofw_mem_regions(struct mem_region **memp, int *memsz,
25664987Smsmith		struct mem_region **availp, int *availsz)
25764987Smsmith{
25864987Smsmith	phandle_t phandle;
25964987Smsmith	int asz, msz, fsz;
26079695Smsmith	int i, j;
26164987Smsmith	int still_merging;
26264987Smsmith
26379695Smsmith	asz = msz = 0;
26464987Smsmith
26573050Smsmith	/*
26679695Smsmith	 * Get memory.
26764987Smsmith	 */
26864987Smsmith	phandle = OF_finddevice("/memory");
26964987Smsmith	if (phandle == -1)
27064987Smsmith		phandle = OF_finddevice("/memory@0");
27164987Smsmith
27279695Smsmith	msz = parse_ofw_memory(phandle, "reg", OFmem);
27364987Smsmith	nOFmem = msz / sizeof(struct mem_region);
27464987Smsmith	asz = parse_ofw_memory(phandle, "available", OFavail);
27579695Smsmith
27679695Smsmith	*memp = OFmem;
27779695Smsmith	*memsz = nOFmem;
27879695Smsmith
27979695Smsmith	/*
28079695Smsmith	 * OFavail may have overlapping regions - collapse these
28179695Smsmith	 * and copy out remaining regions to OFfree
28264987Smsmith	 */
28364987Smsmith	asz /= sizeof(struct mem_region);
28464987Smsmith	do {
28564987Smsmith		still_merging = FALSE;
28679695Smsmith		for (i = 0; i < asz; i++) {
28764987Smsmith			if (OFavail[i].mr_size == 0)
28864987Smsmith				continue;
28979695Smsmith			for (j = i+1; j < asz; j++) {
29064987Smsmith				if (OFavail[j].mr_size == 0)
29164987Smsmith					continue;
29279695Smsmith				if (memr_overlap(&OFavail[j], &OFavail[i])) {
29364987Smsmith					memr_merge(&OFavail[j], &OFavail[i]);
29464987Smsmith					/* mark inactive */
29564987Smsmith					OFavail[j].mr_size = 0;
29664987Smsmith					still_merging = TRUE;
29764987Smsmith				}
29879695Smsmith			}
29964987Smsmith		}
30064987Smsmith	} while (still_merging == TRUE);
30164987Smsmith
30264987Smsmith	/* evict inactive ranges */
30364987Smsmith	for (i = 0, fsz = 0; i < asz; i++) {
30464987Smsmith		if (OFavail[i].mr_size != 0) {
30564987Smsmith			OFfree[fsz] = OFavail[i];
30679695Smsmith			fsz++;
30764987Smsmith		}
30864987Smsmith	}
30964987Smsmith
31064987Smsmith	*availp = OFfree;
31164987Smsmith	*availsz = fsz;
31264987Smsmith}
31379695Smsmith
31464987Smsmithvoid
31564987SmsmithOF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
31664987Smsmith{
31773050Smsmith	if (ofmsr[0] & PSL_DR)
31873050Smsmith		ofw_real_mode = 0;
31973050Smsmith	else
32073050Smsmith		ofw_real_mode = 1;
32173050Smsmith
32273050Smsmith	ofwcall = NULL;
32373050Smsmith
32464987Smsmith	#ifdef __powerpc64__
32564987Smsmith		/*
32664987Smsmith		 * For PPC64, we need to use some hand-written
327110479Sscottl		 * asm trampolines to get to OF.
328110479Sscottl		 */
329110479Sscottl		if (openfirm != NULL)
330110479Sscottl			ofwcall = ofw_32bit_mode_entry;
33179695Smsmith	#else
33279695Smsmith		ofwcall = openfirm;
33379695Smsmith	#endif
33479695Smsmith
33579695Smsmith	fdt = fdt_ptr;
33679695Smsmith
33779695Smsmith	#ifdef FDT_DTB_STATIC
33879695Smsmith	/* Check for a statically included blob */
33979695Smsmith	if (fdt == NULL)
34079695Smsmith		fdt = &fdt_static_dtb;
34179695Smsmith	#endif
34279695Smsmith}
34379695Smsmith
34479695Smsmithboolean_t
34579695SmsmithOF_bootstrap()
34679695Smsmith{
34779695Smsmith	boolean_t status = FALSE;
34879695Smsmith
34979695Smsmith	if (ofwcall != NULL) {
35079695Smsmith		if (ofw_real_mode) {
35179695Smsmith			status = OF_install(OFW_STD_REAL, 0);
35279695Smsmith		} else {
35379695Smsmith			#ifdef __powerpc64__
35479695Smsmith			status = OF_install(OFW_STD_32BIT, 0);
35579695Smsmith			#else
35679695Smsmith			status = OF_install(OFW_STD_DIRECT, 0);
35779695Smsmith			#endif
35879695Smsmith		}
35979695Smsmith
36079695Smsmith		if (status != TRUE)
36179695Smsmith			return status;
36279695Smsmith
36379695Smsmith		OF_init(openfirmware);
36479695Smsmith
36579695Smsmith		/*
36679695Smsmith		 * On some machines, we need to quiesce OF to turn off
36779695Smsmith		 * background processes.
36879695Smsmith		 */
36979695Smsmith		ofw_quiesce();
37079695Smsmith	} else if (fdt != NULL) {
37179695Smsmith		status = OF_install(OFW_FDT, 0);
37279695Smsmith
37379695Smsmith		if (status != TRUE)
37479695Smsmith			return status;
37579695Smsmith
37679695Smsmith		OF_init(fdt);
37779695Smsmith	}
37879695Smsmith
37979695Smsmith	return (status);
38079695Smsmith}
38179695Smsmith
38279695Smsmithstatic void
38379695Smsmithofw_quiesce(void)
38479695Smsmith{
38579695Smsmith	phandle_t rootnode;
38679695Smsmith	char model[32];
38779695Smsmith	struct {
38879695Smsmith		cell_t name;
38979695Smsmith		cell_t nargs;
39079695Smsmith		cell_t nreturns;
39179695Smsmith	} args;
39279695Smsmith
39379695Smsmith	/*
39479695Smsmith	 * Only quiesce Open Firmware on PowerMac11,2 and 12,1. It is
39579695Smsmith	 * necessary there to shut down a background thread doing fan
39679695Smsmith	 * management, and is harmful on other machines.
39779695Smsmith	 *
39879695Smsmith	 * Note: we don't need to worry about which OF module we are
39979695Smsmith	 * using since this is called only from very early boot, within
40079695Smsmith	 * OF's boot context.
40179695Smsmith	 */
40279695Smsmith
40379695Smsmith	rootnode = OF_finddevice("/");
40479695Smsmith	if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) {
40579695Smsmith		if (strcmp(model, "PowerMac11,2") == 0 ||
40679695Smsmith		    strcmp(model, "PowerMac12,1") == 0) {
40779695Smsmith			args.name = (cell_t)(uintptr_t)"quiesce";
40879695Smsmith			args.nargs = 0;
40979695Smsmith			args.nreturns = 0;
41079695Smsmith			openfirmware(&args);
41179695Smsmith		}
41279695Smsmith	}
41379695Smsmith}
41479695Smsmith
41579695Smsmithstatic int
41679695Smsmithopenfirmware_core(void *args)
41779695Smsmith{
41879695Smsmith	int		result;
41979695Smsmith	register_t	oldmsr;
42079695Smsmith	#ifndef __powerpc64__
42179695Smsmith	register_t	srsave[16];
42279695Smsmith	u_int		i;
42379695Smsmith	#endif
42479695Smsmith
42579695Smsmith	/*
42679695Smsmith	 * Turn off exceptions - we really don't want to end up
42779695Smsmith	 * anywhere unexpected with PCPU set to something strange,
42879695Smsmith	 * the stack pointer wrong, or the OFW mapping enabled.
42979695Smsmith	 */
43079695Smsmith	oldmsr = intr_disable();
43179695Smsmith
43279695Smsmith	ofw_sprg_prepare();
43379695Smsmith
43479695Smsmith      #ifndef __powerpc64__
43579695Smsmith	if (pmap_bootstrapped && !ofw_real_mode) {
43679695Smsmith		/*
43779695Smsmith		 * Swap the kernel's address space with Open Firmware's
43879695Smsmith		 */
43979695Smsmith
44079695Smsmith		for (i = 0; i < 16; i++) {
44179695Smsmith			srsave[i] = mfsrin(i << ADDR_SR_SHFT);
44279695Smsmith			mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]);
44379695Smsmith		}
44479695Smsmith
44579695Smsmith		/*
44679695Smsmith		 * Clear battable[] translations
44779695Smsmith		 */
44879695Smsmith		if (!(cpu_features & PPC_FEATURE_64)) {
44979695Smsmith			__asm __volatile("mtdbatu 2, %0\n"
45079695Smsmith					 "mtdbatu 3, %0" : : "r" (0));
45179695Smsmith		}
45279695Smsmith		isync();
45379695Smsmith	}
45479695Smsmith      #endif
45579695Smsmith
45679695Smsmith       	result = ofwcall(args);
45779695Smsmith
45879695Smsmith      #ifndef __powerpc64__
45979695Smsmith	if (pmap_bootstrapped && !ofw_real_mode) {
46079695Smsmith		/*
46179695Smsmith		 * Restore the kernel's addr space. The isync() doesn;t
46279695Smsmith		 * work outside the loop unless mtsrin() is open-coded
46379695Smsmith		 * in an asm statement :(
46479695Smsmith		 */
46579695Smsmith
46679695Smsmith		for (i = 0; i < 16; i++) {
46779695Smsmith			mtsrin(i << ADDR_SR_SHFT, srsave[i]);
46879695Smsmith			isync();
46979695Smsmith		}
47079695Smsmith	}
47179695Smsmith      #endif
47279695Smsmith
47379695Smsmith	ofw_sprg_restore();
47479695Smsmith
47579695Smsmith	intr_restore(oldmsr);
47679695Smsmith
47779695Smsmith	return (result);
47879695Smsmith}
47979695Smsmith
48079695Smsmith#ifdef SMP
48179695Smsmithstruct ofw_rv_args {
48279695Smsmith	void *args;
48379695Smsmith	int retval;
48479695Smsmith	volatile int in_progress;
48579695Smsmith};
48679695Smsmith
48779695Smsmithstatic void
48879695Smsmithofw_rendezvous_dispatch(void *xargs)
48979695Smsmith{
49079695Smsmith	struct ofw_rv_args *rv_args = xargs;
49179695Smsmith
49279695Smsmith	/* NOTE: Interrupts are disabled here */
49379695Smsmith
49479695Smsmith	if (PCPU_GET(cpuid) == 0) {
49579695Smsmith		/*
49679695Smsmith		 * Execute all OF calls on CPU 0
49779695Smsmith		 */
49879695Smsmith		rv_args->retval = openfirmware_core(rv_args->args);
49979695Smsmith		rv_args->in_progress = 0;
50079695Smsmith	} else {
50179695Smsmith		/*
50279695Smsmith		 * Spin with interrupts off on other CPUs while OF has
50379695Smsmith		 * control of the machine.
50479695Smsmith		 */
50579695Smsmith		while (rv_args->in_progress)
50679695Smsmith			cpu_spinwait();
50779695Smsmith	}
50879695Smsmith}
50979695Smsmith#endif
51079695Smsmith
51179695Smsmithstatic int
51279695Smsmithopenfirmware(void *args)
51364987Smsmith{
51464987Smsmith	int result;
51564987Smsmith	#ifdef SMP
51664987Smsmith	struct ofw_rv_args rv_args;
51764987Smsmith	#endif
51879695Smsmith
51979695Smsmith	if (pmap_bootstrapped && ofw_real_mode)
52079695Smsmith		args = (void *)pmap_kextract((vm_offset_t)args);
52179695Smsmith
52279695Smsmith	#ifdef SMP
52379695Smsmith	rv_args.args = args;
52464987Smsmith	rv_args.in_progress = 1;
52579695Smsmith	smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
52679695Smsmith	    smp_no_rendevous_barrier, &rv_args);
52764987Smsmith	result = rv_args.retval;
52879695Smsmith	#else
52964987Smsmith	result = openfirmware_core(args);
53064987Smsmith	#endif
53179695Smsmith
53279695Smsmith	return (result);
53379695Smsmith}
53464987Smsmith
53564987Smsmithvoid
53664987SmsmithOF_reboot()
53764987Smsmith{
53864987Smsmith	struct {
53964987Smsmith		cell_t name;
54064987Smsmith		cell_t nargs;
54164987Smsmith		cell_t nreturns;
54264987Smsmith		cell_t arg;
54379695Smsmith	} args;
54479695Smsmith
54564987Smsmith	args.name = (cell_t)(uintptr_t)"interpret";
54664987Smsmith	args.nargs = 1;
54779695Smsmith	args.nreturns = 0;
54879695Smsmith	args.arg = (cell_t)(uintptr_t)"reset-all";
54979695Smsmith	openfirmware_core(&args); /* Don't do rendezvous! */
55079695Smsmith
55179695Smsmith	for (;;);	/* just in case */
55279695Smsmith}
55379695Smsmith
55479695Smsmithvoid
55579695SmsmithOF_getetheraddr(device_t dev, u_char *addr)
55679695Smsmith{
55779695Smsmith	phandle_t	node;
55879695Smsmith
55979695Smsmith	node = ofw_bus_get_node(dev);
56079695Smsmith	OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
56164987Smsmith}
56264987Smsmith
56379695Smsmith/*
56479695Smsmith * Return a bus handle and bus tag that corresponds to the register
56579695Smsmith * numbered regno for the device referenced by the package handle
56679695Smsmith * dev. This function is intended to be used by console drivers in
56779695Smsmith * early boot only. It works by mapping the address of the device's
56879695Smsmith * register in the address space of its parent and recursively walk
56979695Smsmith * the device tree upward this way.
57079695Smsmith */
57179695Smsmithstatic void
57279695SmsmithOF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
57379695Smsmith{
57479695Smsmith	char name[16];
57579695Smsmith	uint32_t addr, size;
57679695Smsmith	int pci, res;
57779695Smsmith
57879695Smsmith	res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
57979695Smsmith	if (res == -1)
58079695Smsmith		addr = 2;
58179695Smsmith	res = OF_getprop(node, "#size-cells", &size, sizeof(size));
58279695Smsmith	if (res == -1)
58379695Smsmith		size = 1;
58479695Smsmith	pci = 0;
58579695Smsmith	if (addr == 3 && size == 2) {
58679695Smsmith		res = OF_getprop(node, "name", name, sizeof(name));
58779695Smsmith		if (res != -1) {
58879695Smsmith			name[sizeof(name) - 1] = '\0';
58979695Smsmith			pci = (strcmp(name, "pci") == 0) ? 1 : 0;
59079695Smsmith		}
59179695Smsmith	}
59279695Smsmith	if (addrp != NULL)
59379695Smsmith		*addrp = addr;
59479695Smsmith	if (sizep != NULL)
59579695Smsmith		*sizep = size;
59679695Smsmith	if (pcip != NULL)
59779695Smsmith		*pcip = pci;
59879695Smsmith}
59979695Smsmith
60079695Smsmithint
60179695SmsmithOF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
60279695Smsmith    bus_space_handle_t *handle)
60379695Smsmith{
60479695Smsmith	uint32_t cell[32];
60579695Smsmith	bus_addr_t addr, raddr, baddr;
60679695Smsmith	bus_size_t size, rsize;
60779695Smsmith	uint32_t c, nbridge, naddr, nsize;
60879695Smsmith	phandle_t bridge, parent;
60979695Smsmith	u_int spc, rspc;
61079695Smsmith	int pci, pcib, res;
61179695Smsmith
61279695Smsmith	/* Sanity checking. */
61379695Smsmith	if (dev == 0)
61479695Smsmith		return (EINVAL);
61579695Smsmith	bridge = OF_parent(dev);
61679695Smsmith	if (bridge == 0)
61779695Smsmith		return (EINVAL);
61879695Smsmith	if (regno < 0)
61979695Smsmith		return (EINVAL);
62079695Smsmith	if (tag == NULL || handle == NULL)
62179695Smsmith		return (EINVAL);
62279695Smsmith
62379695Smsmith	/* Get the requested register. */
62479695Smsmith	OF_get_addr_props(bridge, &naddr, &nsize, &pci);
62579695Smsmith	res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
62679695Smsmith	    cell, sizeof(cell));
62779695Smsmith	if (res == -1)
62879695Smsmith		return (ENXIO);
62979695Smsmith	if (res % sizeof(cell[0]))
63079695Smsmith		return (ENXIO);
63179695Smsmith	res /= sizeof(cell[0]);
63279695Smsmith	regno *= naddr + nsize;
63379695Smsmith	if (regno + naddr + nsize > res)
63479695Smsmith		return (EINVAL);
63579695Smsmith	spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
63679695Smsmith	addr = 0;
63779695Smsmith	for (c = 0; c < naddr; c++)
63879695Smsmith		addr = ((uint64_t)addr << 32) | cell[regno++];
63979695Smsmith	size = 0;
64079695Smsmith	for (c = 0; c < nsize; c++)
64179695Smsmith		size = ((uint64_t)size << 32) | cell[regno++];
64279695Smsmith
64379695Smsmith	/*
64479695Smsmith	 * Map the address range in the bridge's decoding window as given
64579695Smsmith	 * by the "ranges" property. If a node doesn't have such property
64679695Smsmith	 * then no mapping is done.
64779695Smsmith	 */
64879695Smsmith	parent = OF_parent(bridge);
64979695Smsmith	while (parent != 0) {
65079695Smsmith		OF_get_addr_props(parent, &nbridge, NULL, &pcib);
65179695Smsmith		res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
65279695Smsmith		if (res == -1)
65379695Smsmith			goto next;
65479695Smsmith		if (res % sizeof(cell[0]))
65579695Smsmith			return (ENXIO);
65679695Smsmith		res /= sizeof(cell[0]);
65779695Smsmith		regno = 0;
65879695Smsmith		while (regno < res) {
65979695Smsmith			rspc = (pci)
66079695Smsmith			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
66179695Smsmith			    : ~0;
66279695Smsmith			if (rspc != spc) {
66379695Smsmith				regno += naddr + nbridge + nsize;
66479695Smsmith				continue;
66579695Smsmith			}
66679695Smsmith			raddr = 0;
66779695Smsmith			for (c = 0; c < naddr; c++)
66879695Smsmith				raddr = ((uint64_t)raddr << 32) | cell[regno++];
66979695Smsmith			rspc = (pcib)
67079695Smsmith			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
67179695Smsmith			    : ~0;
67279695Smsmith			baddr = 0;
67379695Smsmith			for (c = 0; c < nbridge; c++)
67479695Smsmith				baddr = ((uint64_t)baddr << 32) | cell[regno++];
67579695Smsmith			rsize = 0;
67679695Smsmith			for (c = 0; c < nsize; c++)
67779695Smsmith				rsize = ((uint64_t)rsize << 32) | cell[regno++];
67879695Smsmith			if (addr < raddr || addr >= raddr + rsize)
67979695Smsmith				continue;
680105215Sphk			addr = addr - raddr + baddr;
68179695Smsmith			if (rspc != ~0)
68279695Smsmith				spc = rspc;
68379695Smsmith		}
68479695Smsmith
68579695Smsmith	next:
686108926Sscottl		bridge = parent;
687108926Sscottl		parent = OF_parent(bridge);
688108926Sscottl		OF_get_addr_props(bridge, &naddr, &nsize, &pci);
68979695Smsmith	}
69079695Smsmith
69179695Smsmith	*tag = &bs_le_tag;
69279695Smsmith	return (bus_space_map(*tag, addr, size, 0, handle));
69379695Smsmith}
69479695Smsmith
69579695Smsmith