xref: /openbsd-src/sys/arch/sparc64/sparc64/autoconf.c (revision 6dfc32ac7c0a571fa1c58dca43c8775f112f31b3)
1*6dfc32acSmiod /*	$OpenBSD: autoconf.c,v 1.151 2024/05/17 20:05:08 miod Exp $	*/
2284584b0Sjason /*	$NetBSD: autoconf.c,v 1.51 2001/07/24 19:32:11 eeh Exp $ */
3284584b0Sjason 
4284584b0Sjason /*
5284584b0Sjason  * Copyright (c) 1996
6284584b0Sjason  *    The President and Fellows of Harvard College. All rights reserved.
7284584b0Sjason  * Copyright (c) 1992, 1993
8284584b0Sjason  *	The Regents of the University of California.  All rights reserved.
9284584b0Sjason  *
10284584b0Sjason  * This software was developed by the Computer Systems Engineering group
11284584b0Sjason  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
12284584b0Sjason  * contributed to Berkeley.
13284584b0Sjason  *
14284584b0Sjason  * All advertising materials mentioning features or use of this software
15284584b0Sjason  * must display the following acknowledgement:
16284584b0Sjason  *	This product includes software developed by Harvard University.
17284584b0Sjason  *	This product includes software developed by the University of
18284584b0Sjason  *	California, Lawrence Berkeley Laboratory.
19284584b0Sjason  *
20284584b0Sjason  * Redistribution and use in source and binary forms, with or without
21284584b0Sjason  * modification, are permitted provided that the following conditions
22284584b0Sjason  * are met:
23284584b0Sjason  * 1. Redistributions of source code must retain the above copyright
24284584b0Sjason  *    notice, this list of conditions and the following disclaimer.
25284584b0Sjason  * 2. Redistributions in binary form must reproduce the above copyright
26284584b0Sjason  *    notice, this list of conditions and the following disclaimer in the
27284584b0Sjason  *    documentation and/or other materials provided with the distribution.
2829295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
29284584b0Sjason  *    may be used to endorse or promote products derived from this software
30284584b0Sjason  *    without specific prior written permission.
31284584b0Sjason  *
32284584b0Sjason  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33284584b0Sjason  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34284584b0Sjason  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35284584b0Sjason  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36284584b0Sjason  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37284584b0Sjason  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38284584b0Sjason  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39284584b0Sjason  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40284584b0Sjason  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41284584b0Sjason  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42284584b0Sjason  * SUCH DAMAGE.
43284584b0Sjason  *
44284584b0Sjason  *	@(#)autoconf.c	8.4 (Berkeley) 10/1/93
45284584b0Sjason  */
46284584b0Sjason 
4757949900Sdlg #include "mpath.h"
4857949900Sdlg 
49284584b0Sjason #include <sys/param.h>
50284584b0Sjason #include <sys/systm.h>
51284584b0Sjason #include <sys/buf.h>
52284584b0Sjason #include <sys/disklabel.h>
53284584b0Sjason #include <sys/device.h>
54284584b0Sjason #include <sys/disk.h>
55284584b0Sjason #include <sys/conf.h>
56284584b0Sjason #include <sys/reboot.h>
57284584b0Sjason #include <sys/socket.h>
58284584b0Sjason #include <sys/malloc.h>
59284584b0Sjason #include <sys/queue.h>
60284584b0Sjason #include <sys/msgbuf.h>
61284584b0Sjason 
62284584b0Sjason #include <net/if.h>
63284584b0Sjason 
64284584b0Sjason #include <dev/cons.h>
6562ab431fSkettenis #include <dev/clock_subr.h>
66284584b0Sjason 
67284584b0Sjason #include <uvm/uvm_extern.h>
68284584b0Sjason 
69284584b0Sjason #include <machine/bus.h>
70237fd37fSstsp #include <machine/boot_flag.h>
71284584b0Sjason #include <machine/autoconf.h>
722c4be14aSkettenis #include <machine/hypervisor.h>
73e4edc0c7Skettenis #include <machine/mdesc.h>
74284584b0Sjason #include <machine/openfirm.h>
75284584b0Sjason #include <machine/sparc64.h>
76284584b0Sjason #include <machine/cpu.h>
77284584b0Sjason #include <machine/pmap.h>
78a62eb7c4Skettenis #include <machine/trap.h>
792c4be14aSkettenis #include <sparc64/sparc64/cache.h>
80b57f54d2Skettenis #include <sparc64/dev/vbusvar.h>
81b57f54d2Skettenis #include <sparc64/dev/cbusvar.h>
82284584b0Sjason 
83237fd37fSstsp #include <stand/boot/bootarg.h>
84237fd37fSstsp 
85284584b0Sjason #include <dev/ata/atavar.h>
86284584b0Sjason #include <dev/pci/pcivar.h>
87284584b0Sjason #include <dev/sbus/sbusvar.h>
88284584b0Sjason 
890300c697Sjason #include <scsi/scsi_all.h>
900300c697Sjason #include <scsi/scsiconf.h>
9157949900Sdlg #if NMPATH > 0
9257949900Sdlg #include <scsi/mpathvar.h>
9357949900Sdlg #endif
940300c697Sjason 
95284584b0Sjason #ifdef DDB
96284584b0Sjason #include <machine/db_machdep.h>
97284584b0Sjason #include <ddb/db_sym.h>
98284584b0Sjason #include <ddb/db_extern.h>
99284584b0Sjason #endif
100284584b0Sjason 
101237fd37fSstsp #include "softraid.h"
102237fd37fSstsp #if NSOFTRAID > 0
103237fd37fSstsp #include <sys/sensors.h>
104237fd37fSstsp #include <dev/softraidvar.h>
105237fd37fSstsp 
106237fd37fSstsp /* XXX */
107237fd37fSstsp #undef DPRINTF
108237fd37fSstsp #undef DNPRINTF
109237fd37fSstsp #endif
110237fd37fSstsp 
111284584b0Sjason int printspl = 0;
112284584b0Sjason 
113284584b0Sjason /*
114284584b0Sjason  * The following several variables are related to
115284584b0Sjason  * the configuration process, and are used in initializing
116284584b0Sjason  * the machine.
117284584b0Sjason  */
118284584b0Sjason int	stdinnode;	/* node ID of ROM's console input device */
119284584b0Sjason int	fbnode;		/* node ID of ROM's console output device */
120284584b0Sjason int	optionsnode;	/* node ID of ROM's options */
121284584b0Sjason 
122284584b0Sjason static	int rootnode;
123284584b0Sjason 
124c5632f19Sjason static	char *str2hex(char *, long *);
125c4071fd1Smillert static	int mbprint(void *, const char *);
126c4071fd1Smillert int	mainbus_match(struct device *, void *, void *);
127c4071fd1Smillert static	void mainbus_attach(struct device *, struct device *, void *);
12804235f00Skettenis int	get_ncpus(void);
129284584b0Sjason 
1300300c697Sjason struct device *booted_device;
131404b377eSkettenis struct	bootpath bootpath[16];
132284584b0Sjason int	nbootpath;
133fb1ca35cSkettenis int	bootnode;
134c4071fd1Smillert static	void bootpath_build(void);
135c4071fd1Smillert static	void bootpath_print(struct bootpath *);
136fb1ca35cSkettenis void bootpath_nodes(struct bootpath *, int);
137284584b0Sjason 
138237fd37fSstsp struct openbsd_bootdata obd __attribute__((section(".openbsd.bootdata")));
139237fd37fSstsp 
140c4071fd1Smillert void nail_bootdev(struct device *, struct bootpath *);
1410300c697Sjason 
142284584b0Sjason /* Global interrupt mappings for all device types.  Match against the OBP
143284584b0Sjason  * 'device_type' property.
144284584b0Sjason  */
145284584b0Sjason struct intrmap intrmap[] = {
146284584b0Sjason 	{ "block",	PIL_FD },	/* Floppy disk */
147284584b0Sjason 	{ "serial",	PIL_SER },	/* zs */
148284584b0Sjason 	{ "scsi",	PIL_SCSI },
1493a39115dSbrad 	{ "scsi-2",	PIL_SCSI },
150284584b0Sjason 	{ "network",	PIL_NET },
151284584b0Sjason 	{ "display",	PIL_VIDEO },
152284584b0Sjason 	{ "audio",	PIL_AUD },
153284584b0Sjason 	{ "ide",	PIL_SCSI },
154284584b0Sjason /* The following devices don't have device types: */
155284584b0Sjason 	{ "SUNW,CS4231",	PIL_AUD },
156284584b0Sjason 	{ NULL,		0 }
157284584b0Sjason };
158284584b0Sjason 
1590ddf3f06Skettenis #ifdef SUN4V
1600ddf3f06Skettenis void	sun4v_soft_state_init(void);
1610ddf3f06Skettenis void	sun4v_set_soft_state(int, const char *);
1620ddf3f06Skettenis 
1630ddf3f06Skettenis #define __align32 __attribute__((__aligned__(32)))
1640ddf3f06Skettenis char sun4v_soft_state_booting[] __align32 = "OpenBSD booting";
1650ddf3f06Skettenis char sun4v_soft_state_running[] __align32 = "OpenBSD running";
16601555c0fSkettenis 
16701555c0fSkettenis void	sun4v_interrupt_init(void);
168090b5ccfSkettenis void	sun4v_sdio_init(void);
1690ddf3f06Skettenis #endif
17025b7217fSjason 
171d00b7f60Smiod extern void us_tlb_flush_pte(vaddr_t, uint64_t);
172d00b7f60Smiod extern void us3_tlb_flush_pte(vaddr_t, uint64_t);
173d00b7f60Smiod extern void sun4v_tlb_flush_pte(vaddr_t, uint64_t);
174d00b7f60Smiod extern void us_tlb_flush_ctx(uint64_t);
175d00b7f60Smiod extern void us3_tlb_flush_ctx(uint64_t);
176d00b7f60Smiod extern void sun4v_tlb_flush_ctx(uint64_t);
177d00b7f60Smiod 
178d00b7f60Smiod void (*sp_tlb_flush_pte)(vaddr_t, uint64_t) = us_tlb_flush_pte;
179d00b7f60Smiod void (*sp_tlb_flush_ctx)(uint64_t) = us_tlb_flush_ctx;
180d00b7f60Smiod 
181284584b0Sjason #ifdef DEBUG
182284584b0Sjason #define ACDB_BOOTDEV	0x1
183284584b0Sjason #define	ACDB_PROBE	0x2
184284584b0Sjason int autoconf_debug = 0x0;
185284584b0Sjason #define DPRINTF(l, s)   do { if (autoconf_debug & l) printf s; } while (0)
186284584b0Sjason #else
187284584b0Sjason #define DPRINTF(l, s)
188284584b0Sjason #endif
189284584b0Sjason 
190284584b0Sjason /*
191284584b0Sjason  * Convert hex ASCII string to a value.  Returns updated pointer.
192284584b0Sjason  * Depends on ASCII order (this *is* machine-dependent code, you know).
193284584b0Sjason  */
194284584b0Sjason static char *
str2hex(char * str,long * vp)195c5632f19Sjason str2hex(char *str, long *vp)
196284584b0Sjason {
197c5632f19Sjason 	long v;
198c5632f19Sjason 	int c;
199c5632f19Sjason 
200c5632f19Sjason 	if (*str == 'w') {
201c5632f19Sjason 		for (v = 1;; v++) {
202c5632f19Sjason 			if (str[v] >= '0' && str[v] <= '9')
203c5632f19Sjason 				continue;
204c5632f19Sjason 			if (str[v] >= 'a' && str[v] <= 'f')
205c5632f19Sjason 				continue;
206c5632f19Sjason 			if (str[v] >= 'A' && str[v] <= 'F')
207c5632f19Sjason 				continue;
208c5632f19Sjason 			if (str[v] == '\0' || str[v] == ',')
209c5632f19Sjason 				break;
210c5632f19Sjason 			*vp = 0;
211c5632f19Sjason 			return (str + v);
212c5632f19Sjason 		}
213c5632f19Sjason 		str++;
214c5632f19Sjason 	}
215284584b0Sjason 
216284584b0Sjason 	for (v = 0;; v = v * 16 + c, str++) {
217284584b0Sjason 		c = *(u_char *)str;
218284584b0Sjason 		if (c <= '9') {
219284584b0Sjason 			if ((c -= '0') < 0)
220284584b0Sjason 				break;
221284584b0Sjason 		} else if (c <= 'F') {
222284584b0Sjason 			if ((c -= 'A' - 10) < 10)
223284584b0Sjason 				break;
224284584b0Sjason 		} else if (c <= 'f') {
225284584b0Sjason 			if ((c -= 'a' - 10) < 10)
226284584b0Sjason 				break;
227284584b0Sjason 		} else
228284584b0Sjason 			break;
229284584b0Sjason 	}
230284584b0Sjason 	*vp = v;
231284584b0Sjason 	return (str);
232284584b0Sjason }
233284584b0Sjason 
23406fa7dd9Skettenis /*
23506fa7dd9Skettenis  * Hunt through the device tree for CPUs.  There should be no need to
23606fa7dd9Skettenis  * go more than four levels deep; an UltraSPARC-IV on Seregeti shows
23706fa7dd9Skettenis  * up as /ssm@0,0/cmp@0,0/cpu@0 and a SPARC64-VI will show up as
23806fa7dd9Skettenis  * /cmp@0,0/core@0/cpu@0.
23906fa7dd9Skettenis  */
24004235f00Skettenis int
get_ncpus(void)24104235f00Skettenis get_ncpus(void)
24204235f00Skettenis {
24306fa7dd9Skettenis 	int node, child, stack[4], depth, ncpus;
24404235f00Skettenis 	char buf[32];
24504235f00Skettenis 
24606fa7dd9Skettenis 	stack[0] = findroot();
24706fa7dd9Skettenis 	depth = 0;
24804235f00Skettenis 
24904235f00Skettenis 	ncpus = 0;
25006fa7dd9Skettenis 	for (;;) {
25106fa7dd9Skettenis 		node = stack[depth];
25206fa7dd9Skettenis 
25306fa7dd9Skettenis 		if (node == 0 || node == -1) {
25406fa7dd9Skettenis 			if (--depth < 0)
255663f3520Sderaadt 				goto done;
25606fa7dd9Skettenis 
25706fa7dd9Skettenis 			stack[depth] = OF_peer(stack[depth]);
25804235f00Skettenis 			continue;
25904235f00Skettenis 		}
26004235f00Skettenis 
26106fa7dd9Skettenis 		if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 &&
26206fa7dd9Skettenis 		    strcmp(buf, "cpu") == 0)
26304235f00Skettenis 			ncpus++;
26404235f00Skettenis 
26506fa7dd9Skettenis 		child = OF_child(node);
26606fa7dd9Skettenis 		if (child != 0 && child != -1 && depth < 3)
26706fa7dd9Skettenis 			stack[++depth] = child;
26806fa7dd9Skettenis 		else
26906fa7dd9Skettenis 			stack[depth] = OF_peer(stack[depth]);
27004235f00Skettenis 	}
27104235f00Skettenis 
272663f3520Sderaadt done:
273663f3520Sderaadt 	ncpusfound = ncpus;
274663f3520Sderaadt #ifdef MULTIPROCESSOR
275663f3520Sderaadt 	return (ncpus);
27604235f00Skettenis #else
27704235f00Skettenis 	return (1);
27804235f00Skettenis #endif
27904235f00Skettenis }
280f626355dSkettenis 
281284584b0Sjason /*
282284584b0Sjason  * locore.s code calls bootstrap() just before calling main().
283284584b0Sjason  *
284284584b0Sjason  * What we try to do is as follows:
285284584b0Sjason  *
286284584b0Sjason  * 1) We will try to re-allocate the old message buffer.
287284584b0Sjason  *
288284584b0Sjason  * 2) We will then get the list of the total and available
289284584b0Sjason  *	physical memory and available virtual memory from the
290284584b0Sjason  *	prom.
291284584b0Sjason  *
292284584b0Sjason  * 3) We will pass the list to pmap_bootstrap to manage them.
293284584b0Sjason  *
294284584b0Sjason  * We will try to run out of the prom until we get to cpu_init().
295284584b0Sjason  */
296284584b0Sjason void
bootstrap(int nctx)297ba134ca3Sstsp bootstrap(int nctx)
298284584b0Sjason {
299284584b0Sjason 	extern int end;	/* End of kernel */
300f0ec91c2Skettenis 	struct trapvec *romtba;
301b4c7a3a8Skettenis #if defined(SUN4US) || defined(SUN4V)
30290572c87Skettenis 	char buf[32];
30390572c87Skettenis #endif
304462ff407Skettenis 	int impl = 0;
30504235f00Skettenis 	int ncpus;
306284584b0Sjason 
307baf89de9Skettenis 	/* Initialize the PROM console so printf will not panic. */
308baf89de9Skettenis 	(*cn_tab->cn_init)(cn_tab);
309baf89de9Skettenis 
310284584b0Sjason 	/*
311284584b0Sjason 	 * Initialize ddb first and register OBP callbacks.
312284584b0Sjason 	 * We can do this because ddb_init() does not allocate anything,
313d0b398a2Sjmc 	 * just initializes some pointers to important things
314284584b0Sjason 	 * like the symtab.
315284584b0Sjason 	 *
316284584b0Sjason 	 * By doing this first and installing the OBP callbacks
317284584b0Sjason 	 * we get to do symbolic debugging of pmap_bootstrap().
318284584b0Sjason 	 */
319284584b0Sjason #ifdef DDB
3206ecd5bf4Sjason 	db_machine_init();
321284584b0Sjason 	ddb_init();
322284584b0Sjason 	/* This can only be installed on an 64-bit system cause otherwise our stack is screwed */
323284584b0Sjason 	OF_set_symbol_lookup(OF_sym2val, OF_val2sym);
324284584b0Sjason #endif
325284584b0Sjason 
326b4c7a3a8Skettenis #if defined (SUN4US) || defined(SUN4V)
327b4c7a3a8Skettenis 	if (OF_getprop(findroot(), "compatible", buf, sizeof(buf)) > 0) {
328b4c7a3a8Skettenis 		if (strcmp(buf, "sun4us") == 0)
329b4c7a3a8Skettenis 			cputyp = CPU_SUN4US;
330b4c7a3a8Skettenis 		if (strcmp(buf, "sun4v") == 0)
33190572c87Skettenis 			cputyp = CPU_SUN4V;
332b4c7a3a8Skettenis 	}
33390572c87Skettenis #endif
33490572c87Skettenis 
335462ff407Skettenis 	/* We cannot read %ver on sun4v systems. */
336462ff407Skettenis 	if (CPU_ISSUN4U || CPU_ISSUN4US)
337462ff407Skettenis 		impl = (getver() & VER_IMPL) >> VER_IMPL_SHIFT;
338462ff407Skettenis 
339462ff407Skettenis 	if (impl >= IMPL_CHEETAH) {
340462ff407Skettenis 		extern vaddr_t dlflush_start;
341462ff407Skettenis 		vaddr_t *pva;
342462ff407Skettenis 		u_int32_t insn;
343462ff407Skettenis 
344462ff407Skettenis 		for (pva = &dlflush_start; *pva; pva++) {
345462ff407Skettenis 			insn = *(u_int32_t *)(*pva);
346462ff407Skettenis 			insn &= ~(ASI_DCACHE_TAG << 5);
347462ff407Skettenis 			insn |= (ASI_DCACHE_INVALIDATE << 5);
348462ff407Skettenis 			*(u_int32_t *)(*pva) = insn;
349462ff407Skettenis 			flush((void *)(*pva));
350462ff407Skettenis 		}
351462ff407Skettenis 
352462ff407Skettenis 		cacheinfo.c_dcache_flush_page = us3_dcache_flush_page;
353d00b7f60Smiod 		sp_tlb_flush_pte = us3_tlb_flush_pte;
354d00b7f60Smiod 		sp_tlb_flush_ctx = us3_tlb_flush_ctx;
355462ff407Skettenis 	}
356462ff407Skettenis 
357462ff407Skettenis 	if ((impl >= IMPL_ZEUS && impl <= IMPL_JUPITER) || CPU_ISSUN4V) {
35831b3c1c3Skettenis 		extern vaddr_t dlflush_start;
3592c4be14aSkettenis 		vaddr_t *pva;
3602c4be14aSkettenis 
3612c4be14aSkettenis 		for (pva = &dlflush_start; *pva; pva++) {
3622c4be14aSkettenis 			*(u_int32_t *)(*pva) = 0x01000000; /* nop */
3632c4be14aSkettenis 			flush((void *)(*pva));
3642c4be14aSkettenis 		}
3652c4be14aSkettenis 
366b4c7a3a8Skettenis 		cacheinfo.c_dcache_flush_page = no_dcache_flush_page;
367b4c7a3a8Skettenis 	}
368b4c7a3a8Skettenis 
369958674eeSkettenis #ifdef MULTIPROCESSOR
370958674eeSkettenis 	if (impl >= IMPL_OLYMPUS_C && impl <= IMPL_JUPITER) {
371958674eeSkettenis 		struct sun4u_patch {
372958674eeSkettenis 			u_int32_t addr;
373958674eeSkettenis 			u_int32_t insn;
374958674eeSkettenis 		} *p;
375958674eeSkettenis 
376958674eeSkettenis 		extern struct sun4u_patch sun4u_mtp_patch;
377958674eeSkettenis 		extern struct sun4u_patch sun4u_mtp_patch_end;
378958674eeSkettenis 
379958674eeSkettenis 		for (p = &sun4u_mtp_patch; p < &sun4u_mtp_patch_end; p++) {
380958674eeSkettenis 			*(u_int32_t *)(vaddr_t)p->addr = p->insn;
381958674eeSkettenis 			flush((void *)(vaddr_t)p->addr);
382958674eeSkettenis 		}
383958674eeSkettenis 	}
384958674eeSkettenis #endif
385958674eeSkettenis 
386b4c7a3a8Skettenis #ifdef SUN4V
387b4c7a3a8Skettenis 	if (CPU_ISSUN4V) {
38864958104Skettenis 		struct sun4v_patch {
38964958104Skettenis 			u_int32_t addr;
39064958104Skettenis 			u_int32_t insn;
39131b3c1c3Skettenis 		} *p;
39264958104Skettenis 
39331b3c1c3Skettenis 		extern struct sun4v_patch sun4v_patch;
39431b3c1c3Skettenis 		extern struct sun4v_patch sun4v_patch_end;
39531b3c1c3Skettenis 
39631b3c1c3Skettenis 		for (p = &sun4v_patch; p < &sun4v_patch_end; p++) {
39731b3c1c3Skettenis 			*(u_int32_t *)(vaddr_t)p->addr = p->insn;
39831b3c1c3Skettenis 			flush((void *)(vaddr_t)p->addr);
39931b3c1c3Skettenis 		}
40031b3c1c3Skettenis 
40131b3c1c3Skettenis #ifdef MULTIPROCESSOR
40264958104Skettenis 		extern struct sun4v_patch sun4v_mp_patch;
40364958104Skettenis 		extern struct sun4v_patch sun4v_mp_patch_end;
40464958104Skettenis 
40564958104Skettenis 		for (p = &sun4v_mp_patch; p < &sun4v_mp_patch_end; p++) {
40664958104Skettenis 			*(u_int32_t *)(vaddr_t)p->addr = p->insn;
40764958104Skettenis 			flush((void *)(vaddr_t)p->addr);
40864958104Skettenis 		}
40964958104Skettenis #endif
41064958104Skettenis 
411d00b7f60Smiod 		sp_tlb_flush_pte = sun4v_tlb_flush_pte;
412d00b7f60Smiod 		sp_tlb_flush_ctx = sun4v_tlb_flush_ctx;
4132c4be14aSkettenis 	}
4142c4be14aSkettenis #endif
4152c4be14aSkettenis 
416f0ec91c2Skettenis 	/*
417f0ec91c2Skettenis 	 * Copy over the OBP breakpoint trap vector; OpenFirmware 5.x
418f0ec91c2Skettenis 	 * needs it to be able to return to the ok prompt.
419f0ec91c2Skettenis 	 */
420f0ec91c2Skettenis 	romtba = (struct trapvec *)sparc_rdpr(tba);
421f0ec91c2Skettenis 	bcopy(&romtba[T_MON_BREAKPOINT], &trapbase[T_MON_BREAKPOINT],
422f0ec91c2Skettenis 	    sizeof(struct trapvec));
423f0ec91c2Skettenis 	flush((void *)trapbase);
424f0ec91c2Skettenis 
42504235f00Skettenis 	ncpus = get_ncpus();
42604235f00Skettenis 	pmap_bootstrap(KERNBASE, (u_long)&end, nctx, ncpus);
4270ddf3f06Skettenis 
4286a5bfaa2Skettenis 	if (obd.version == BOOTDATA_VERSION &&
429e653d891Skn 	    obd.len >= BOOTDATA_LEN_BOOTHOWTO)
4306a5bfaa2Skettenis 		boothowto = obd.boothowto;
4316a5bfaa2Skettenis 
4320ddf3f06Skettenis #ifdef SUN4V
4330ddf3f06Skettenis 	if (CPU_ISSUN4V) {
4340ddf3f06Skettenis 		sun4v_soft_state_init();
4350ddf3f06Skettenis 		sun4v_set_soft_state(SIS_TRANSITION, sun4v_soft_state_booting);
43601555c0fSkettenis 		sun4v_interrupt_init();
437090b5ccfSkettenis 		sun4v_sdio_init();
4380ddf3f06Skettenis 	}
4390ddf3f06Skettenis #endif
440284584b0Sjason }
441284584b0Sjason 
44245a28fb1Sjason void
bootpath_nodes(struct bootpath * bp,int nbp)443fb1ca35cSkettenis bootpath_nodes(struct bootpath *bp, int nbp)
44445a28fb1Sjason {
445fb1ca35cSkettenis 	int chosen;
44645a28fb1Sjason 	int i;
44745a28fb1Sjason 	char buf[128], *cp, c;
44845a28fb1Sjason 
44945a28fb1Sjason 	chosen = OF_finddevice("/chosen");
45045a28fb1Sjason 	OF_getprop(chosen, "bootpath", buf, sizeof(buf));
45145a28fb1Sjason 	cp = buf;
45245a28fb1Sjason 
45345a28fb1Sjason 	for (i = 0; i < nbp; i++, bp++) {
45445a28fb1Sjason 		if (*cp == '\0')
45545a28fb1Sjason 			return;
45645a28fb1Sjason 		while (*cp != '\0' && *cp == '/')
45745a28fb1Sjason 			cp++;
45845a28fb1Sjason 		while (*cp && *cp != '/')
45945a28fb1Sjason 			cp++;
46045a28fb1Sjason 		c = *cp;
46145a28fb1Sjason 		*cp = '\0';
462fb1ca35cSkettenis 		bootnode = bp->node = OF_finddevice(buf);
46345a28fb1Sjason 		*cp = c;
46445a28fb1Sjason 	}
46545a28fb1Sjason }
46645a28fb1Sjason 
467284584b0Sjason /*
468284584b0Sjason  * bootpath_build: build a bootpath. Used when booting a generic
469284584b0Sjason  * kernel to find our root device.  Newer proms give us a bootpath,
470284584b0Sjason  * for older proms we have to create one.  An element in a bootpath
471284584b0Sjason  * has 4 fields: name (device name), val[0], val[1], and val[2]. Note that:
472284584b0Sjason  * Interpretation of val[] is device-dependent. Some examples:
473284584b0Sjason  *
474284584b0Sjason  * if (val[0] == -1) {
475284584b0Sjason  *	val[1] is a unit number    (happens most often with old proms)
476284584b0Sjason  * } else {
477284584b0Sjason  *	[sbus device] val[0] is a sbus slot, and val[1] is an sbus offset
478284584b0Sjason  *	[scsi disk] val[0] is target, val[1] is lun, val[2] is partition
479284584b0Sjason  *	[scsi tape] val[0] is target, val[1] is lun, val[2] is file #
480284584b0Sjason  *	[pci device] val[0] is device, val[1] is function, val[2] might be partition
481284584b0Sjason  * }
482284584b0Sjason  *
483284584b0Sjason  */
484284584b0Sjason 
485284584b0Sjason static void
bootpath_build(void)4860aac5001Snaddy bootpath_build(void)
487284584b0Sjason {
488284584b0Sjason 	register char *cp, *pp;
489284584b0Sjason 	register struct bootpath *bp;
490284584b0Sjason 	register long chosen;
491284584b0Sjason 	char buf[128];
492284584b0Sjason 
493284584b0Sjason 	bzero((void *)bootpath, sizeof(bootpath));
494284584b0Sjason 	bp = bootpath;
495284584b0Sjason 
496284584b0Sjason 	/*
497284584b0Sjason 	 * Grab boot path from PROM
498284584b0Sjason 	 */
499284584b0Sjason 	chosen = OF_finddevice("/chosen");
500284584b0Sjason 	OF_getprop(chosen, "bootpath", buf, sizeof(buf));
501284584b0Sjason 	cp = buf;
502284584b0Sjason 	while (cp != NULL && *cp == '/') {
503284584b0Sjason 		/* Step over '/' */
504284584b0Sjason 		++cp;
505284584b0Sjason 		/* Extract name */
506284584b0Sjason 		pp = bp->name;
507284584b0Sjason 		while (*cp != '@' && *cp != '/' && *cp != '\0')
508284584b0Sjason 			*pp++ = *cp++;
509284584b0Sjason 		*pp = '\0';
510284584b0Sjason 		if (*cp == '@') {
511284584b0Sjason 			cp = str2hex(++cp, &bp->val[0]);
512284584b0Sjason 			if (*cp == ',')
513284584b0Sjason 				cp = str2hex(++cp, &bp->val[1]);
514a59e3f8dSmiod 			if (*cp == ':') {
515a59e3f8dSmiod 				/*
516a59e3f8dSmiod 				 * We only store one character here, as we will
517a59e3f8dSmiod 				 * only use this field to compute a partition
518a59e3f8dSmiod 				 * index for block devices.  However, it might
519a59e3f8dSmiod 				 * be an ethernet media specification, so be
520a59e3f8dSmiod 				 * sure to skip all letters.
521a59e3f8dSmiod 				 */
522a59e3f8dSmiod 				bp->val[2] = *++cp - 'a';
523a59e3f8dSmiod 				while (*cp != '\0' && *cp != '/')
524a59e3f8dSmiod 					cp++;
525a59e3f8dSmiod 			}
526284584b0Sjason 		} else {
527284584b0Sjason 			bp->val[0] = -1; /* no #'s: assume unit 0, no
5288243e839Sjmc 					    sbus offset/address */
529284584b0Sjason 		}
530284584b0Sjason 		++bp;
531284584b0Sjason 		++nbootpath;
532284584b0Sjason 	}
533284584b0Sjason 	bp->name[0] = 0;
534284584b0Sjason 
535fb1ca35cSkettenis 	bootpath_nodes(bootpath, nbootpath);
536284584b0Sjason 
537284584b0Sjason 	/* Setup pointer to boot flags */
538284584b0Sjason 	OF_getprop(chosen, "bootargs", buf, sizeof(buf));
539284584b0Sjason 	cp = buf;
540284584b0Sjason 
541284584b0Sjason 	/* Find start of boot flags */
542284584b0Sjason 	while (*cp) {
543284584b0Sjason 		while(*cp == ' ' || *cp == '\t') cp++;
544284584b0Sjason 		if (*cp == '-' || *cp == '\0')
545284584b0Sjason 			break;
546284584b0Sjason 		while(*cp != ' ' && *cp != '\t' && *cp != '\0') cp++;
547284584b0Sjason 
548284584b0Sjason 	}
549284584b0Sjason 	if (*cp != '-')
550284584b0Sjason 		return;
551284584b0Sjason 
552284584b0Sjason 	for (;*++cp;) {
553284584b0Sjason 		int fl;
554284584b0Sjason 
555284584b0Sjason 		fl = 0;
556284584b0Sjason 		switch(*cp) {
557284584b0Sjason 		case 'a':
558284584b0Sjason 			fl |= RB_ASKNAME;
559284584b0Sjason 			break;
560284584b0Sjason 		case 'b':
561284584b0Sjason 			fl |= RB_HALT;
562284584b0Sjason 			break;
563284584b0Sjason 		case 'c':
564284584b0Sjason 			fl |= RB_CONFIG;
565284584b0Sjason 			break;
566284584b0Sjason 		case 'd':
567284584b0Sjason 			fl |= RB_KDB;
568284584b0Sjason 			break;
569284584b0Sjason 		case 's':
570284584b0Sjason 			fl |= RB_SINGLE;
571284584b0Sjason 			break;
572284584b0Sjason 		default:
573284584b0Sjason 			break;
574284584b0Sjason 		}
575284584b0Sjason 		if (!fl) {
576284584b0Sjason 			printf("unknown option `%c'\n", *cp);
577284584b0Sjason 			continue;
578284584b0Sjason 		}
579284584b0Sjason 		boothowto |= fl;
580284584b0Sjason 
581284584b0Sjason 		/* specialties */
582284584b0Sjason 		if (*cp == 'd') {
583baf89de9Skettenis #if defined(DDB)
584e97088d6Smpi 			db_enter();
585284584b0Sjason #else
586284584b0Sjason 			printf("kernel has no debugger\n");
587284584b0Sjason #endif
588284584b0Sjason 		}
589284584b0Sjason 	}
590284584b0Sjason }
591284584b0Sjason 
592284584b0Sjason /*
593284584b0Sjason  * print out the bootpath
594284584b0Sjason  * the %x isn't 0x%x because the Sun EPROMs do it this way, and
595284584b0Sjason  * consistency with the EPROMs is probably better here.
596284584b0Sjason  */
597284584b0Sjason 
598284584b0Sjason static void
bootpath_print(struct bootpath * bp)599ba134ca3Sstsp bootpath_print(struct bootpath *bp)
600284584b0Sjason {
601284584b0Sjason 	printf("bootpath: ");
602284584b0Sjason 	while (bp->name[0]) {
603284584b0Sjason 		if (bp->val[0] == -1)
6041b84c71fSkettenis 			printf("/%s%lx", bp->name, bp->val[1]);
605284584b0Sjason 		else
606c5632f19Sjason 			printf("/%s@%lx,%lx", bp->name, bp->val[0], bp->val[1]);
607284584b0Sjason 		if (bp->val[2] != 0)
6081b84c71fSkettenis 			printf(":%c", (int)bp->val[2] + 'a');
609284584b0Sjason 		bp++;
610284584b0Sjason 	}
611284584b0Sjason 	printf("\n");
612284584b0Sjason }
613284584b0Sjason 
614284584b0Sjason 
615284584b0Sjason /*
616284584b0Sjason  * save or read a bootpath pointer from the boothpath store.
617284584b0Sjason  *
618284584b0Sjason  * XXX. required because of SCSI... we don't have control over the "sd"
619284584b0Sjason  * device, so we can't set boot device there.   we patch in with
620e5fd22c3Smiod  * device_register(), and use this to recover the bootpath.
621284584b0Sjason  */
622284584b0Sjason struct bootpath *
bootpath_store(int storep,struct bootpath * bp)623ba134ca3Sstsp bootpath_store(int storep, struct bootpath *bp)
624284584b0Sjason {
625284584b0Sjason 	static struct bootpath *save;
626284584b0Sjason 	struct bootpath *retval;
627284584b0Sjason 
628284584b0Sjason 	retval = save;
629284584b0Sjason 	if (storep)
630284584b0Sjason 		save = bp;
631284584b0Sjason 
632284584b0Sjason 	return (retval);
633284584b0Sjason }
634284584b0Sjason 
635284584b0Sjason /*
636284584b0Sjason  * Determine mass storage and memory configuration for a machine.
637284584b0Sjason  * We get the PROM's root device and make sure we understand it, then
638f75609fcSmiod  * attach it as `mainbus0'.
639284584b0Sjason  */
640284584b0Sjason void
cpu_configure(void)6410aac5001Snaddy cpu_configure(void)
642284584b0Sjason {
643e4edc0c7Skettenis #ifdef SUN4V
644465290deSkettenis 	int pause = 0;
645465290deSkettenis 
646465290deSkettenis 	if (CPU_ISSUN4V) {
647465290deSkettenis 		const char *prop;
648465290deSkettenis 		size_t len;
649465290deSkettenis 		int idx;
650465290deSkettenis 
651e4edc0c7Skettenis 		mdesc_init();
652465290deSkettenis 		idx = mdesc_find_node("cpu");
653465290deSkettenis 		prop = mdesc_get_prop_data(idx, "hwcap-list", &len);
654465290deSkettenis 		if (prop) {
655465290deSkettenis 			while (len > 0) {
656465290deSkettenis 				if (strcmp(prop, "pause") == 0)
657465290deSkettenis 					pause = 1;
658465290deSkettenis 				len -= strlen(prop) + 1;
659465290deSkettenis 				prop += strlen(prop) + 1;
660465290deSkettenis 			}
661465290deSkettenis 		}
662465290deSkettenis 	}
663465290deSkettenis 
664465290deSkettenis 	if (pause) {
665465290deSkettenis 		struct sun4v_patch {
666465290deSkettenis 			u_int32_t addr;
667465290deSkettenis 			u_int32_t insn;
668465290deSkettenis 		} *p;
669465290deSkettenis 		paddr_t pa;
670465290deSkettenis 
671465290deSkettenis 		extern struct sun4v_patch sun4v_pause_patch;
672465290deSkettenis 		extern struct sun4v_patch sun4v_pause_patch_end;
673465290deSkettenis 
674465290deSkettenis 		/*
675465290deSkettenis 		 * Use physical addresses to patch since kernel .text
676465290deSkettenis 		 * is already mapped read-only at this point.
677465290deSkettenis 		 */
678465290deSkettenis 		for (p = &sun4v_pause_patch; p < &sun4v_pause_patch_end; p++) {
679465290deSkettenis 			pmap_extract(pmap_kernel(), (vaddr_t)p->addr, &pa);
680465290deSkettenis 			stwa(pa, ASI_PHYS_NON_CACHED, p->insn);
681465290deSkettenis 			flush((void *)(vaddr_t)p->addr);
682465290deSkettenis 		}
683465290deSkettenis 	}
684e4edc0c7Skettenis #endif
685e4edc0c7Skettenis 
686237fd37fSstsp 	if (obd.version == BOOTDATA_VERSION &&
687e653d891Skn 	    obd.len >= BOOTDATA_LEN_BOOTHOWTO) {
688237fd37fSstsp #if NSOFTRAID > 0
689237fd37fSstsp 		memcpy(sr_bootuuid.sui_id, obd.sr_uuid,
690237fd37fSstsp 		    sizeof(sr_bootuuid.sui_id));
691237fd37fSstsp 		memcpy(sr_bootkey, obd.sr_maskkey, sizeof(sr_bootkey));
692237fd37fSstsp #endif
693237fd37fSstsp 		explicit_bzero(obd.sr_maskkey, sizeof(obd.sr_maskkey));
694237fd37fSstsp 	}
695237fd37fSstsp 
696284584b0Sjason 	/* build the bootpath */
697284584b0Sjason 	bootpath_build();
698284584b0Sjason 
69925b7217fSjason 	if (boothowto & RB_CONFIG) {
70025b7217fSjason #ifdef BOOT_CONFIG
70125b7217fSjason 		user_config();
70225b7217fSjason #else
70325b7217fSjason 		printf("kernel does not support -c; continuing..\n");
70425b7217fSjason #endif
70525b7217fSjason 	}
70625b7217fSjason 
707284584b0Sjason 	/* block clock interrupts and anything below */
708284584b0Sjason 	splclock();
709284584b0Sjason 	/* Enable device interrupts */
710284584b0Sjason         setpstate(getpstate()|PSTATE_IE);
711284584b0Sjason 
712284584b0Sjason 	if (config_rootfound("mainbus", NULL) == NULL)
713284584b0Sjason 		panic("mainbus not configured");
714284584b0Sjason 
715284584b0Sjason 	/* Enable device interrupts */
716284584b0Sjason         setpstate(getpstate()|PSTATE_IE);
717284584b0Sjason 
718284584b0Sjason 	(void)spl0();
719e01d3f6aSart 	cold = 0;
7200ddf3f06Skettenis 
7210ddf3f06Skettenis #ifdef SUN4V
7220ddf3f06Skettenis 	if (CPU_ISSUN4V)
7230ddf3f06Skettenis 		sun4v_set_soft_state(SIS_NORMAL, sun4v_soft_state_running);
7240ddf3f06Skettenis #endif
725e01d3f6aSart }
726e01d3f6aSart 
7270ddf3f06Skettenis #ifdef SUN4V
7280ddf3f06Skettenis 
72901555c0fSkettenis #define HSVC_GROUP_INTERRUPT	0x002
7300ddf3f06Skettenis #define HSVC_GROUP_SOFT_STATE	0x003
731090b5ccfSkettenis #define HSVC_GROUP_SDIO		0x108
7320ddf3f06Skettenis 
7330ddf3f06Skettenis int sun4v_soft_state_initialized = 0;
7340ddf3f06Skettenis 
7350ddf3f06Skettenis void
sun4v_soft_state_init(void)7360ddf3f06Skettenis sun4v_soft_state_init(void)
7370ddf3f06Skettenis {
7380ddf3f06Skettenis 	uint64_t minor;
7390ddf3f06Skettenis 
7400ddf3f06Skettenis 	if (prom_set_sun4v_api_version(HSVC_GROUP_SOFT_STATE, 1, 0, &minor))
7410ddf3f06Skettenis 		return;
7420ddf3f06Skettenis 
7430ddf3f06Skettenis 	prom_sun4v_soft_state_supported();
7440ddf3f06Skettenis 	sun4v_soft_state_initialized = 1;
7450ddf3f06Skettenis }
7460ddf3f06Skettenis 
7470ddf3f06Skettenis void
sun4v_set_soft_state(int state,const char * desc)7480ddf3f06Skettenis sun4v_set_soft_state(int state, const char *desc)
7490ddf3f06Skettenis {
7500ddf3f06Skettenis 	paddr_t pa;
7510ddf3f06Skettenis 	int err;
7520ddf3f06Skettenis 
7530ddf3f06Skettenis 	if (!sun4v_soft_state_initialized)
7540ddf3f06Skettenis 		return;
7550ddf3f06Skettenis 
7560ddf3f06Skettenis 	if (!pmap_extract(pmap_kernel(), (vaddr_t)desc, &pa))
757cf04bd29Skrw 		panic("sun4v_set_soft_state: pmap_extract failed");
7580ddf3f06Skettenis 
7590ddf3f06Skettenis 	err = hv_soft_state_set(state, pa);
7600ddf3f06Skettenis 	if (err != H_EOK)
7610ddf3f06Skettenis 		printf("soft_state_set: %d\n", err);
7620ddf3f06Skettenis }
76301555c0fSkettenis 
76401555c0fSkettenis void
sun4v_interrupt_init(void)76501555c0fSkettenis sun4v_interrupt_init(void)
76601555c0fSkettenis {
76701555c0fSkettenis 	uint64_t minor;
76801555c0fSkettenis 
76901555c0fSkettenis 	if (prom_set_sun4v_api_version(HSVC_GROUP_INTERRUPT, 3, 0, &minor))
77001555c0fSkettenis 		return;
77101555c0fSkettenis 
77201555c0fSkettenis 	sun4v_group_interrupt_major = 3;
77301555c0fSkettenis }
77401555c0fSkettenis 
775090b5ccfSkettenis void
sun4v_sdio_init(void)776090b5ccfSkettenis sun4v_sdio_init(void)
777090b5ccfSkettenis {
778090b5ccfSkettenis 	uint64_t minor;
779090b5ccfSkettenis 
780090b5ccfSkettenis 	if (prom_set_sun4v_api_version(HSVC_GROUP_SDIO, 1, 0, &minor))
781090b5ccfSkettenis 		return;
782090b5ccfSkettenis 
783090b5ccfSkettenis 	sun4v_group_sdio_major = 1;
784090b5ccfSkettenis }
785090b5ccfSkettenis 
7860ddf3f06Skettenis #endif
7870ddf3f06Skettenis 
788e01d3f6aSart void
diskconf(void)789e01d3f6aSart diskconf(void)
790e01d3f6aSart {
79125b7217fSjason 	struct bootpath *bp;
7927dc861caSderaadt 	struct device *bootdv;
7937dc861caSderaadt 
7947dc861caSderaadt 	bootpath_print(bootpath);
795284584b0Sjason 
796284584b0Sjason 	bp = nbootpath == 0 ? NULL : &bootpath[nbootpath-1];
79725b7217fSjason 	bootdv = (bp == NULL) ? NULL : bp->dev;
798284584b0Sjason 
79957949900Sdlg #if NMPATH > 0
80057949900Sdlg 	if (bootdv != NULL)
80157949900Sdlg 		bootdv = mpath_bootdv(bootdv);
80257949900Sdlg #endif
80357949900Sdlg 
8047dc861caSderaadt 	setroot(bootdv, bp->val[2], RB_USERREQ | RB_HALT);
8057dc861caSderaadt 	dumpconf();
80625b7217fSjason }
807284584b0Sjason 
808284584b0Sjason char *
clockfreq(long freq)809ba134ca3Sstsp clockfreq(long freq)
810284584b0Sjason {
811284584b0Sjason 	char *p;
812284584b0Sjason 	static char buf[10];
813284584b0Sjason 
814284584b0Sjason 	freq /= 1000;
8152a108914Sho 	snprintf(buf, sizeof buf, "%ld", freq / 1000);
816284584b0Sjason 	freq %= 1000;
817284584b0Sjason 	if (freq) {
818284584b0Sjason 		freq += 1000;	/* now in 1000..1999 */
819284584b0Sjason 		p = buf + strlen(buf);
8202a108914Sho 		snprintf(p, buf + sizeof buf - p, "%ld", freq);
821284584b0Sjason 		*p = '.';	/* now buf = %d.%3d */
822284584b0Sjason 	}
823284584b0Sjason 	return (buf);
824284584b0Sjason }
825284584b0Sjason 
826284584b0Sjason static int
mbprint(void * aux,const char * name)827ba134ca3Sstsp mbprint(void *aux, const char *name)
828284584b0Sjason {
829284584b0Sjason 	struct mainbus_attach_args *ma = aux;
830284584b0Sjason 
831284584b0Sjason 	if (name)
8321b7dfce2Skettenis 		printf("\"%s\" at %s", ma->ma_name, name);
833284584b0Sjason 	if (ma->ma_address)
834284584b0Sjason 		printf(" addr 0x%08lx", (u_long)ma->ma_address[0]);
835284584b0Sjason 	if (ma->ma_pri)
836284584b0Sjason 		printf(" ipl %d", ma->ma_pri);
837284584b0Sjason 	return (UNCONF);
838284584b0Sjason }
839284584b0Sjason 
840284584b0Sjason int
findroot(void)8410aac5001Snaddy findroot(void)
842284584b0Sjason {
843ba134ca3Sstsp 	int node;
844284584b0Sjason 
845284584b0Sjason 	if ((node = rootnode) == 0 && (node = OF_peer(0)) == 0)
846284584b0Sjason 		panic("no PROM root device");
847284584b0Sjason 	rootnode = node;
848284584b0Sjason 	return (node);
849284584b0Sjason }
850284584b0Sjason 
851284584b0Sjason /*
852284584b0Sjason  * Given a `first child' node number, locate the node with the given name.
853284584b0Sjason  * Return the node number, or 0 if not found.
854284584b0Sjason  */
855284584b0Sjason int
findnode(int first,const char * name)856ba134ca3Sstsp findnode(int first, const char *name)
857284584b0Sjason {
858284584b0Sjason 	int node;
859284584b0Sjason 	char buf[32];
860284584b0Sjason 
861284584b0Sjason 	for (node = first; node; node = OF_peer(node)) {
862284584b0Sjason 		if ((OF_getprop(node, "name", buf, sizeof(buf)) > 0) &&
863284584b0Sjason 			(strcmp(buf, name) == 0))
864284584b0Sjason 			return (node);
865284584b0Sjason 	}
866284584b0Sjason 	return (0);
867284584b0Sjason }
868284584b0Sjason 
869284584b0Sjason int
mainbus_match(struct device * parent,void * cf,void * aux)870ba134ca3Sstsp mainbus_match(struct device *parent, void *cf, void *aux)
871284584b0Sjason {
872284584b0Sjason 	return (1);
873284584b0Sjason }
874284584b0Sjason 
875284584b0Sjason /*
876284584b0Sjason  * Attach the mainbus.
877284584b0Sjason  *
878c9e42332Smjc  * Our main job is to attach the CPU (the root node we got in cpu_configure())
879284584b0Sjason  * and iterate down the list of `mainbus devices' (children of that node).
880284584b0Sjason  * We also record the `node id' of the default frame buffer, if any.
881284584b0Sjason  */
882284584b0Sjason static void
mainbus_attach(struct device * parent,struct device * dev,void * aux)883ba134ca3Sstsp mainbus_attach(struct device *parent, struct device *dev, void *aux)
884284584b0Sjason {
885284584b0Sjason extern struct sparc_bus_dma_tag mainbus_dma_tag;
886eb79e960Shenric extern bus_space_tag_t mainbus_space_tag;
887284584b0Sjason 
888284584b0Sjason 	struct mainbus_attach_args ma;
88925c1a9d6Skettenis 	char buf[64];
890284584b0Sjason 	const char *const *ssp, *sp = NULL;
8919079f3edSkettenis 	int node0, node, rv, len;
892284584b0Sjason 
893284584b0Sjason 	static const char *const openboot_special[] = {
894284584b0Sjason 		/* ignore these (end with NULL) */
895284584b0Sjason 		/*
896284584b0Sjason 		 * These are _root_ devices to ignore. Others must be handled
897284584b0Sjason 		 * elsewhere.
898284584b0Sjason 		 */
899284584b0Sjason 		"virtual-memory",
900284584b0Sjason 		"aliases",
901284584b0Sjason 		"memory",
902284584b0Sjason 		"openprom",
903284584b0Sjason 		"options",
904284584b0Sjason 		"packages",
905284584b0Sjason 		"chosen",
9066f6544cdSmiod 		"counter-timer",
907284584b0Sjason 		NULL
908284584b0Sjason 	};
909284584b0Sjason 
91025c1a9d6Skettenis 	/*
91125c1a9d6Skettenis 	 * Print the "banner-name" property in dmesg.  It provides a
91225c1a9d6Skettenis 	 * description of the machine that is generally more
91325c1a9d6Skettenis 	 * informative than the "name" property.  However, if the
91425c1a9d6Skettenis 	 * "banner-name" property is missing, fall back on the "name"
91536fd90dcSjsg 	 * property.
91625c1a9d6Skettenis 	 */
91725c1a9d6Skettenis 	if (OF_getprop(findroot(), "banner-name", buf, sizeof(buf)) > 0 ||
91825c1a9d6Skettenis 	    OF_getprop(findroot(), "name", buf, sizeof(buf)) > 0)
91925c1a9d6Skettenis 		printf(": %s\n", buf);
92025c1a9d6Skettenis 	else
92125c1a9d6Skettenis 		printf("\n");
9228677f810Sgwk 
92325c1a9d6Skettenis 	/*
92425c1a9d6Skettenis 	 * Base the hw.product and hw.vendor strings on the "name"
92525c1a9d6Skettenis 	 * property.  They describe the hardware in a much more
92625c1a9d6Skettenis 	 * consistent way than the "banner-property".
92725c1a9d6Skettenis 	 */
92825c1a9d6Skettenis 	if ((len = OF_getprop(findroot(), "name", buf, sizeof(buf))) > 0) {
92925c1a9d6Skettenis 		hw_prod = malloc(len, M_DEVBUF, M_NOWAIT);
93025c1a9d6Skettenis 		if (hw_prod)
93125c1a9d6Skettenis 			strlcpy(hw_prod, buf, len);
93225c1a9d6Skettenis 
93325c1a9d6Skettenis 		if (strncmp(buf, "SUNW,", 5) == 0)
9348677f810Sgwk 			hw_vendor = "Sun";
93525c1a9d6Skettenis 		if (strncmp(buf, "FJSV,", 5) == 0)
93625c1a9d6Skettenis 			hw_vendor = "Fujitsu";
93725c1a9d6Skettenis 		if (strncmp(buf, "TAD,", 4) == 0)
93825c1a9d6Skettenis 			hw_vendor = "Tadpole";
93933be661fSkettenis 		if (strncmp(buf, "NATE,", 5) == 0)
94033be661fSkettenis 			hw_vendor = "Naturetech";
941f0aa7c20Sdlg 		if (strncmp(buf, "ORCL,", 5) == 0)
942f0aa7c20Sdlg 			hw_vendor = "Oracle";
94325c1a9d6Skettenis 
94425c1a9d6Skettenis 		/*
94525c1a9d6Skettenis 		 * The Momentum Leopard-V advertises itself as
94625c1a9d6Skettenis 		 * SUNW,UltraSPARC-IIi-Engine, but can be
94725c1a9d6Skettenis 		 * distinguished by looking at the "model" property.
94825c1a9d6Skettenis 		 */
94925c1a9d6Skettenis 		if (OF_getprop(findroot(), "model", buf, sizeof(buf)) > 0 &&
95025c1a9d6Skettenis 		    strncmp(buf, "MOMENTUM,", 9) == 0)
95125c1a9d6Skettenis 			hw_vendor = "Momentum";
9520833435bSgwk 	}
953284584b0Sjason 
954284584b0Sjason 	/* Establish the first component of the boot path */
955284584b0Sjason 	bootpath_store(1, bootpath);
956284584b0Sjason 
95704235f00Skettenis 	/* We configure the CPUs first. */
9588fad7323Skettenis 
95904235f00Skettenis 	node = findroot();
960a42faf19Skettenis 	for (node0 = OF_child(node); node0; node0 = OF_peer(node0)) {
961a42faf19Skettenis 		if (OF_getprop(node0, "name", buf, sizeof(buf)) <= 0)
962a42faf19Skettenis 			continue;
963a42faf19Skettenis 	}
96404235f00Skettenis 
9659079f3edSkettenis 	for (node = OF_child(node); node; node = OF_peer(node)) {
966fc121a76Skettenis 		if (!checkstatus(node))
967fc121a76Skettenis 			continue;
968fc121a76Skettenis 
9698fad7323Skettenis 		/*
9708fad7323Skettenis 		 * UltraSPARC-IV cpus appear as two "cpu" nodes below
9719079f3edSkettenis 		 * a "cmp" node.
9728fad7323Skettenis 		 */
9738fad7323Skettenis 		if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0)
9748fad7323Skettenis 			continue;
97504235f00Skettenis 		if (strcmp(buf, "cmp") == 0) {
9769079f3edSkettenis 			bzero(&ma, sizeof(ma));
9779079f3edSkettenis 			ma.ma_node = node;
9789079f3edSkettenis 			ma.ma_name = buf;
9799079f3edSkettenis 			getprop(node, "reg", sizeof(*ma.ma_reg),
9809079f3edSkettenis 			    &ma.ma_nreg, (void **)&ma.ma_reg);
9819079f3edSkettenis 			config_found(dev, &ma, mbprint);
9829079f3edSkettenis 			continue;
9838fad7323Skettenis 		}
9848fad7323Skettenis 
98504235f00Skettenis 		if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0)
986284584b0Sjason 			continue;
987284584b0Sjason 		if (strcmp(buf, "cpu") == 0) {
988284584b0Sjason 			bzero(&ma, sizeof(ma));
989284584b0Sjason 			ma.ma_node = node;
990f18899c8Skettenis 			OF_getprop(node, "name", buf, sizeof(buf));
991f18899c8Skettenis 			if (strcmp(buf, "cpu") == 0)
992f18899c8Skettenis 				OF_getprop(node, "compatible", buf, sizeof(buf));
993f18899c8Skettenis 			ma.ma_name = buf;
994f626355dSkettenis 			getprop(node, "reg", sizeof(*ma.ma_reg),
995f626355dSkettenis 			    &ma.ma_nreg, (void **)&ma.ma_reg);
996f18899c8Skettenis 			config_found(dev, &ma, mbprint);
9979079f3edSkettenis 			continue;
998284584b0Sjason 		}
999284584b0Sjason 	}
1000038ea04cSkettenis 
1001284584b0Sjason 	node = findroot();	/* re-init root node */
1002284584b0Sjason 
1003284584b0Sjason 	/* Find the "options" node */
1004284584b0Sjason 	node0 = OF_child(node);
1005284584b0Sjason 	optionsnode = findnode(node0, "options");
1006284584b0Sjason 	if (optionsnode == 0)
1007284584b0Sjason 		panic("no options in OPENPROM");
1008284584b0Sjason 
1009a42faf19Skettenis 	for (node0 = OF_child(node); node0; node0 = OF_peer(node0)) {
1010a42faf19Skettenis 		if (OF_getprop(node0, "name", buf, sizeof(buf)) <= 0)
1011a42faf19Skettenis 			continue;
1012a42faf19Skettenis 	}
1013a42faf19Skettenis 
1014284584b0Sjason 	/*
1015284584b0Sjason 	 * Configure the devices, in PROM order.  Skip
1016284584b0Sjason 	 * PROM entries that are not for devices, or which must be
1017284584b0Sjason 	 * done before we get here.
1018284584b0Sjason 	 */
1019a42faf19Skettenis 	for (node = OF_child(node); node; node = OF_peer(node)) {
1020284584b0Sjason 		int portid;
1021284584b0Sjason 
1022284584b0Sjason 		DPRINTF(ACDB_PROBE, ("Node: %x", node));
1023f18899c8Skettenis 		if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 &&
1024284584b0Sjason 		    strcmp(buf, "cpu") == 0)
1025284584b0Sjason 			continue;
10269079f3edSkettenis 		if (OF_getprop(node, "name", buf, sizeof(buf)) > 0 &&
10279079f3edSkettenis 		    strcmp(buf, "cmp") == 0)
10289079f3edSkettenis 			continue;
1029284584b0Sjason 		DPRINTF(ACDB_PROBE, (" name %s\n", buf));
1030284584b0Sjason 		for (ssp = openboot_special; (sp = *ssp) != NULL; ssp++)
1031284584b0Sjason 			if (strcmp(buf, sp) == 0)
1032284584b0Sjason 				break;
1033284584b0Sjason 		if (sp != NULL)
1034284584b0Sjason 			continue; /* an "early" device already configured */
1035284584b0Sjason 
10365adfdce9Skettenis 		if (!checkstatus(node))
10375adfdce9Skettenis 			continue;
10385adfdce9Skettenis 
1039284584b0Sjason 		bzero(&ma, sizeof ma);
1040eb79e960Shenric 		ma.ma_bustag = mainbus_space_tag;
1041284584b0Sjason 		ma.ma_dmatag = &mainbus_dma_tag;
1042284584b0Sjason 		ma.ma_name = buf;
1043284584b0Sjason 		ma.ma_node = node;
1044284584b0Sjason 		if (OF_getprop(node, "upa-portid", &portid, sizeof(portid)) !=
1045774c92c2Sjason 		    sizeof(portid)) {
1046774c92c2Sjason 			if (OF_getprop(node, "portid", &portid,
1047774c92c2Sjason 			    sizeof(portid)) != sizeof(portid))
1048284584b0Sjason 				portid = -1;
1049774c92c2Sjason 		}
1050284584b0Sjason 		ma.ma_upaid = portid;
1051284584b0Sjason 
1052284584b0Sjason 		if (getprop(node, "reg", sizeof(*ma.ma_reg),
1053284584b0Sjason 			     &ma.ma_nreg, (void **)&ma.ma_reg) != 0)
1054284584b0Sjason 			continue;
1055284584b0Sjason #ifdef DEBUG
1056284584b0Sjason 		if (autoconf_debug & ACDB_PROBE) {
1057284584b0Sjason 			if (ma.ma_nreg)
1058284584b0Sjason 				printf(" reg %08lx.%08lx\n",
1059284584b0Sjason 					(long)ma.ma_reg->ur_paddr,
1060284584b0Sjason 					(long)ma.ma_reg->ur_len);
1061284584b0Sjason 			else
1062284584b0Sjason 				printf(" no reg\n");
1063284584b0Sjason 		}
1064284584b0Sjason #endif
1065284584b0Sjason 		rv = getprop(node, "interrupts", sizeof(*ma.ma_interrupts),
1066284584b0Sjason 			&ma.ma_ninterrupts, (void **)&ma.ma_interrupts);
1067284584b0Sjason 		if (rv != 0 && rv != ENOENT) {
1068f8e6c425Stedu 			free(ma.ma_reg, M_DEVBUF, 0);
1069284584b0Sjason 			continue;
1070284584b0Sjason 		}
1071284584b0Sjason #ifdef DEBUG
1072284584b0Sjason 		if (autoconf_debug & ACDB_PROBE) {
1073284584b0Sjason 			if (ma.ma_interrupts)
1074284584b0Sjason 				printf(" interrupts %08x\n",
1075284584b0Sjason 					*ma.ma_interrupts);
1076284584b0Sjason 			else
1077284584b0Sjason 				printf(" no interrupts\n");
1078284584b0Sjason 		}
1079284584b0Sjason #endif
1080284584b0Sjason 		rv = getprop(node, "address", sizeof(*ma.ma_address),
1081284584b0Sjason 			&ma.ma_naddress, (void **)&ma.ma_address);
1082284584b0Sjason 		if (rv != 0 && rv != ENOENT) {
1083f8e6c425Stedu 			free(ma.ma_reg, M_DEVBUF, 0);
1084f8e6c425Stedu 			free(ma.ma_interrupts, M_DEVBUF, 0);
1085284584b0Sjason 			continue;
1086284584b0Sjason 		}
1087284584b0Sjason #ifdef DEBUG
1088284584b0Sjason 		if (autoconf_debug & ACDB_PROBE) {
1089284584b0Sjason 			if (ma.ma_naddress)
1090284584b0Sjason 				printf(" address %08x\n",
1091284584b0Sjason 					*ma.ma_address);
1092284584b0Sjason 			else
1093284584b0Sjason 				printf(" no address\n");
1094284584b0Sjason 		}
1095284584b0Sjason #endif
1096f18899c8Skettenis 		config_found(dev, &ma, mbprint);
1097f8e6c425Stedu 		free(ma.ma_reg, M_DEVBUF, 0);
1098f8e6c425Stedu 		free(ma.ma_interrupts, M_DEVBUF, 0);
1099f8e6c425Stedu 		free(ma.ma_address, M_DEVBUF, 0);
1100284584b0Sjason 	}
1101adb3c397Skettenis 
1102adb3c397Skettenis 	extern int prom_cngetc(dev_t);
1103adb3c397Skettenis 
1104adb3c397Skettenis 	/* Attach PROM console if no other console attached. */
1105adb3c397Skettenis 	if (cn_tab->cn_getc == prom_cngetc) {
1106284584b0Sjason 		bzero(&ma, sizeof ma);
1107284584b0Sjason 		ma.ma_name = "pcons";
1108f18899c8Skettenis 		config_found(dev, &ma, mbprint);
1109adb3c397Skettenis 	}
111062ab431fSkettenis 
111162ab431fSkettenis 	extern todr_chip_handle_t todr_handle;
111262ab431fSkettenis 
111362ab431fSkettenis 	if (todr_handle == NULL) {
111462ab431fSkettenis 		bzero(&ma, sizeof ma);
111562ab431fSkettenis 		ma.ma_name = "prtc";
111662ab431fSkettenis 		config_found(dev, &ma, mbprint);
111762ab431fSkettenis 	}
1118284584b0Sjason }
1119284584b0Sjason 
1120eb7eaf8dSmpi const struct cfattach mainbus_ca = {
1121284584b0Sjason 	sizeof(struct device), mainbus_match, mainbus_attach
1122284584b0Sjason };
1123284584b0Sjason 
1124284584b0Sjason int
getprop(int node,char * name,size_t size,int * nitem,void ** bufp)1125ba134ca3Sstsp getprop(int node, char *name, size_t size, int *nitem, void **bufp)
1126284584b0Sjason {
1127284584b0Sjason 	void	*buf;
1128284584b0Sjason 	long	len;
1129284584b0Sjason 
1130284584b0Sjason 	*nitem = 0;
1131284584b0Sjason 	len = getproplen(node, name);
1132284584b0Sjason 	if (len <= 0)
1133284584b0Sjason 		return (ENOENT);
1134284584b0Sjason 
1135284584b0Sjason 	if ((len % size) != 0)
1136284584b0Sjason 		return (EINVAL);
1137284584b0Sjason 
1138284584b0Sjason 	buf = *bufp;
1139284584b0Sjason 	if (buf == NULL) {
1140284584b0Sjason 		/* No storage provided, so we allocate some */
114183d5679cSderaadt 		buf = malloc(len + 1, M_DEVBUF, M_NOWAIT);
1142284584b0Sjason 		if (buf == NULL)
1143284584b0Sjason 			return (ENOMEM);
1144284584b0Sjason 	}
1145284584b0Sjason 
1146284584b0Sjason 	OF_getprop(node, name, buf, len);
1147284584b0Sjason 	*bufp = buf;
1148284584b0Sjason 	*nitem = len / size;
1149284584b0Sjason 	return (0);
1150284584b0Sjason }
1151284584b0Sjason 
1152284584b0Sjason 
1153284584b0Sjason /*
1154284584b0Sjason  * Internal form of proplen().  Returns the property length.
1155284584b0Sjason  */
1156284584b0Sjason long
getproplen(int node,char * name)1157ba134ca3Sstsp getproplen(int node, char *name)
1158284584b0Sjason {
1159284584b0Sjason 	return (OF_getproplen(node, name));
1160284584b0Sjason }
1161284584b0Sjason 
1162284584b0Sjason /*
1163284584b0Sjason  * Return a string property.  There is a (small) limit on the length;
1164284584b0Sjason  * the string is fetched into a static buffer which is overwritten on
1165284584b0Sjason  * subsequent calls.
1166284584b0Sjason  */
1167284584b0Sjason char *
getpropstring(int node,char * name)1168ba134ca3Sstsp getpropstring(int node, char *name)
1169284584b0Sjason {
1170284584b0Sjason 	static char stringbuf[32];
1171284584b0Sjason 
1172284584b0Sjason 	return (getpropstringA(node, name, stringbuf));
1173284584b0Sjason }
1174284584b0Sjason 
1175284584b0Sjason /* Alternative getpropstring(), where caller provides the buffer */
1176284584b0Sjason char *
getpropstringA(int node,char * name,char * buffer)1177ba134ca3Sstsp getpropstringA(int node, char *name, char *buffer)
1178284584b0Sjason {
1179284584b0Sjason 	int blen;
1180284584b0Sjason 
1181284584b0Sjason 	if (getprop(node, name, 1, &blen, (void **)&buffer) != 0)
1182284584b0Sjason 		blen = 0;
1183284584b0Sjason 
1184284584b0Sjason 	buffer[blen] = '\0';	/* usually unnecessary */
1185284584b0Sjason 	return (buffer);
1186284584b0Sjason }
1187284584b0Sjason 
1188284584b0Sjason /*
1189284584b0Sjason  * Fetch an integer (or pointer) property.
1190284584b0Sjason  * The return value is the property, or the default if there was none.
1191284584b0Sjason  */
1192284584b0Sjason int
getpropint(int node,char * name,int deflt)1193ba134ca3Sstsp getpropint(int node, char *name, int deflt)
1194284584b0Sjason {
1195284584b0Sjason 	int intbuf;
1196284584b0Sjason 
1197284584b0Sjason 	if (OF_getprop(node, name, &intbuf, sizeof(intbuf)) != sizeof(intbuf))
1198284584b0Sjason 		return (deflt);
1199284584b0Sjason 
1200284584b0Sjason 	return (intbuf);
1201284584b0Sjason }
1202284584b0Sjason 
1203fa65087eSkettenis int
getpropspeed(int node,char * name)1204ba134ca3Sstsp getpropspeed(int node, char *name)
1205fa65087eSkettenis {
1206fa65087eSkettenis 	char buf[128];
1207fa65087eSkettenis 	int i, speed = 0;
1208fa65087eSkettenis 
1209fa65087eSkettenis 	if (OF_getprop(node, name, buf, sizeof(buf)) != -1) {
1210fa65087eSkettenis 		for (i = 0; i < sizeof(buf); i++) {
1211fa65087eSkettenis 			if (buf[i] < '0' || buf[i] > '9')
1212fa65087eSkettenis 				break;
1213fa65087eSkettenis 			speed *= 10;
1214fa65087eSkettenis 			speed += buf[i] - '0';
1215fa65087eSkettenis 		}
1216fa65087eSkettenis 	}
1217fa65087eSkettenis 
1218fa65087eSkettenis 	if (speed == 0)
1219fa65087eSkettenis 		speed = 9600;
1220fa65087eSkettenis 
1221fa65087eSkettenis 	return (speed);
1222fa65087eSkettenis }
1223fa65087eSkettenis 
1224284584b0Sjason /*
1225284584b0Sjason  * OPENPROM functions.  These are here mainly to hide the OPENPROM interface
1226284584b0Sjason  * from the rest of the kernel.
1227284584b0Sjason  */
1228284584b0Sjason int
firstchild(int node)1229ba134ca3Sstsp firstchild(int node)
1230284584b0Sjason {
1231284584b0Sjason 
1232284584b0Sjason 	return OF_child(node);
1233284584b0Sjason }
1234284584b0Sjason 
1235284584b0Sjason int
nextsibling(int node)1236ba134ca3Sstsp nextsibling(int node)
1237284584b0Sjason {
1238284584b0Sjason 
1239284584b0Sjason 	return OF_peer(node);
1240284584b0Sjason }
1241284584b0Sjason 
12425adfdce9Skettenis int
checkstatus(int node)12435adfdce9Skettenis checkstatus(int node)
12445adfdce9Skettenis {
12455adfdce9Skettenis 	char buf[32];
12465adfdce9Skettenis 
12475adfdce9Skettenis 	/* If there is no "status" property, assume everything is fine. */
12485adfdce9Skettenis 	if (OF_getprop(node, "status", buf, sizeof(buf)) <= 0)
12495adfdce9Skettenis 		return 1;
12505adfdce9Skettenis 
12515adfdce9Skettenis 	/*
12525adfdce9Skettenis 	 * If OpenBoot Diagnostics discovers a problem with a device
12535adfdce9Skettenis 	 * it will mark it with "fail" or "fail-xxx", where "xxx" is
12545adfdce9Skettenis 	 * additional human-readable information about the particular
12555adfdce9Skettenis 	 * fault-condition.
12565adfdce9Skettenis 	 */
12575adfdce9Skettenis 	if (strcmp(buf, "disabled") == 0 || strncmp(buf, "fail", 4) == 0)
12585adfdce9Skettenis 		return 0;
12595adfdce9Skettenis 
12605adfdce9Skettenis 	return 1;
12615adfdce9Skettenis }
1262284584b0Sjason 
1263ba134ca3Sstsp /* returns 1 if node has given property */
1264284584b0Sjason int
node_has_property(int node,const char * prop)1265ba134ca3Sstsp node_has_property(int node, const char *prop)
1266284584b0Sjason {
1267284584b0Sjason 	return (OF_getproplen(node, (caddr_t)prop) != -1);
1268284584b0Sjason }
1269284584b0Sjason 
1270284584b0Sjason /*
1271284584b0Sjason  * Try to figure out where the PROM stores the cursor row & column
1272284584b0Sjason  * variables.  Returns nonzero on error.
1273284584b0Sjason  */
1274284584b0Sjason int
romgetcursoraddr(int ** rowp,int ** colp)1275ba134ca3Sstsp romgetcursoraddr(int **rowp, int **colp)
1276284584b0Sjason {
127788ee6abdSmiod 	cell_t row = 0, col = 0;
1278965e62f5Sjason 
1279965e62f5Sjason 	OF_interpret("stdout @ is my-self addr line# addr column# ",
1280965e62f5Sjason 	    2, &col, &row);
1281284584b0Sjason 
1282284584b0Sjason 	/*
1283f75609fcSmiod 	 * We are running on a 64-bit big-endian machine, so these things
1284f75609fcSmiod 	 * point to 64-bit big-endian values.  To convert them to pointers
1285f75609fcSmiod 	 * to int, add 4 to the address.
1286284584b0Sjason 	 */
128788ee6abdSmiod 	if (row == 0 || col == 0)
1288965e62f5Sjason 		return (-1);
1289965e62f5Sjason 	*rowp = (int *)(row + 4);
1290965e62f5Sjason 	*colp = (int *)(col + 4);
1291965e62f5Sjason 	return (0);
1292284584b0Sjason }
1293284584b0Sjason 
1294284584b0Sjason void
callrom(void)12950aac5001Snaddy callrom(void)
1296284584b0Sjason {
1297284584b0Sjason 
12982df76cc2Sguenther 	__asm volatile("wrpr	%%g0, 0, %%tl" : );
1299284584b0Sjason 	OF_enter();
1300284584b0Sjason }
1301284584b0Sjason 
1302284584b0Sjason /*
1303284584b0Sjason  * find a device matching "name" and unit number
1304284584b0Sjason  */
1305284584b0Sjason struct device *
getdevunit(const char * name,int unit)1306*6dfc32acSmiod getdevunit(const char *name, int unit)
1307284584b0Sjason {
13085cf5f4a3Smiod 	struct device *dev = TAILQ_FIRST(&alldevs);
1309284584b0Sjason 	char num[10], fullname[16];
1310284584b0Sjason 	int lunit;
1311284584b0Sjason 
1312284584b0Sjason 	/* compute length of name and decimal expansion of unit number */
13132a108914Sho 	snprintf(num, sizeof num, "%d", unit);
1314284584b0Sjason 	lunit = strlen(num);
1315284584b0Sjason 	if (strlen(name) + lunit >= sizeof(fullname) - 1)
1316284584b0Sjason 		panic("config_attach: device name too long");
1317284584b0Sjason 
13182a108914Sho 	strlcpy(fullname, name, sizeof fullname);
13192a108914Sho 	strlcat(fullname, num, sizeof fullname);
1320284584b0Sjason 
1321284584b0Sjason 	while (strcmp(dev->dv_xname, fullname) != 0) {
13225cf5f4a3Smiod 		if ((dev = TAILQ_NEXT(dev, dv_list)) == NULL)
1323284584b0Sjason 			return NULL;
1324284584b0Sjason 	}
1325284584b0Sjason 	return dev;
1326284584b0Sjason }
13270300c697Sjason 
13280300c697Sjason void
device_register(struct device * dev,void * aux)1329fb1ca35cSkettenis device_register(struct device *dev, void *aux)
13300300c697Sjason {
1331fb1ca35cSkettenis 	struct mainbus_attach_args *ma = aux;
1332fb1ca35cSkettenis 	struct pci_attach_args *pa = aux;
1333fb1ca35cSkettenis 	struct sbus_attach_args *sa = aux;
1334b57f54d2Skettenis 	struct vbus_attach_args *va = aux;
1335b57f54d2Skettenis 	struct cbus_attach_args *ca = aux;
13360300c697Sjason 	struct bootpath *bp = bootpath_store(0, NULL);
1337fb1ca35cSkettenis 	struct device *busdev = dev->dv_parent;
1338fb1ca35cSkettenis 	const char *devname = dev->dv_cfdata->cf_driver->cd_name;
1339fb1ca35cSkettenis 	const char *busname;
1340fb1ca35cSkettenis 	int node = -1;
13410300c697Sjason 
13420300c697Sjason 	/*
1343fb1ca35cSkettenis 	 * There is no point in continuing if we've exhausted all
1344fb1ca35cSkettenis 	 * bootpath components.
13450300c697Sjason 	 */
13460300c697Sjason 	if (bp == NULL)
13470300c697Sjason 		return;
13480300c697Sjason 
13490300c697Sjason 	DPRINTF(ACDB_BOOTDEV,
1350fb1ca35cSkettenis 	    ("\n%s: device_register: devname %s(%s) component %s\n",
1351fb1ca35cSkettenis 	    dev->dv_xname, devname, dev->dv_xname, bp->name));
13520300c697Sjason 
1353fb1ca35cSkettenis 	/*
1354fb1ca35cSkettenis 	 * Ignore mainbus0 itself, it certainly is not a boot device.
1355fb1ca35cSkettenis 	 */
1356fb1ca35cSkettenis 	if (busdev == NULL)
13570300c697Sjason 		return;
13580300c697Sjason 
13590300c697Sjason 	/*
1360fb1ca35cSkettenis 	 * We don't know the type of 'aux'; it depends on the bus this
1361fb1ca35cSkettenis 	 * device attaches to.  We are only interested in certain bus
1362fb1ca35cSkettenis 	 * types; this is only used to find the boot device.
13630300c697Sjason 	 */
1364fb1ca35cSkettenis 	busname = busdev->dv_cfdata->cf_driver->cd_name;
13656e697324Skettenis 	if (strcmp(busname, "mainbus") == 0 ||
13666e697324Skettenis 	    strcmp(busname, "ssm") == 0 || strcmp(busname, "upa") == 0)
1367fb1ca35cSkettenis 		node = ma->ma_node;
1368e8dd11dfSkettenis 	else if (strcmp(busname, "sbus") == 0 ||
1369e8dd11dfSkettenis 	    strcmp(busname, "dma") == 0 || strcmp(busname, "ledma") == 0)
1370e8dd11dfSkettenis 		node = sa->sa_node;
1371b57f54d2Skettenis 	else if (strcmp(busname, "vbus") == 0)
1372b57f54d2Skettenis 		node = va->va_node;
1373b57f54d2Skettenis 	else if (strcmp(busname, "cbus") == 0)
1374b57f54d2Skettenis 		node = ca->ca_node;
1375fb1ca35cSkettenis 	else if (strcmp(busname, "pci") == 0)
1376fb1ca35cSkettenis 		node = PCITAG_NODE(pa->pa_tag);
1377fb1ca35cSkettenis 
1378fb1ca35cSkettenis 	if (node == bootnode) {
13794ca9d95fSkettenis 		if (strcmp(devname, "vdsk") == 0) {
13804ca9d95fSkettenis 			/*
13814ca9d95fSkettenis 			 * For virtual disks, don't nail the boot
13824ca9d95fSkettenis 			 * device just yet.  Instead, we add fake a
13834ca9d95fSkettenis 			 * SCSI target/lun, such that we match it the
13844ca9d95fSkettenis 			 * next time around.
13854ca9d95fSkettenis 			 */
13864ca9d95fSkettenis 			bp->dev = dev;
13874ca9d95fSkettenis 			(bp + 1)->val[0] = 0;
13884ca9d95fSkettenis 			(bp + 1)->val[1] = 0;
13894ca9d95fSkettenis 			nbootpath++;
13904ca9d95fSkettenis 			bootpath_store(1, bp + 1);
13914ca9d95fSkettenis 			return;
13924ca9d95fSkettenis 		}
13934ca9d95fSkettenis 
13940300c697Sjason 		nail_bootdev(dev, bp);
13950300c697Sjason 		return;
13960300c697Sjason 	}
1397fb1ca35cSkettenis 
1398fb1ca35cSkettenis 	if (node == bp->node) {
1399fb1ca35cSkettenis 		bp->dev = dev;
1400fb1ca35cSkettenis 		DPRINTF(ACDB_BOOTDEV, ("\t-- matched component %s to %s\n",
1401fb1ca35cSkettenis 		    bp->name, dev->dv_xname));
1402fb1ca35cSkettenis 		bootpath_store(1, bp + 1);
1403fb1ca35cSkettenis 		return;
1404fb1ca35cSkettenis 	}
1405fb1ca35cSkettenis 
1406fb1ca35cSkettenis 	if (strcmp(devname, "scsibus") == 0) {
1407b446ce28Skettenis 		/*
1408b446ce28Skettenis 		 * Booting from anything but the first (physical) port
1409b446ce28Skettenis 		 * isn't supported by OBP.
1410b446ce28Skettenis 		 */
1411b446ce28Skettenis 		if (strcmp(bp->name, "fp") == 0 && bp->val[0] == 0) {
1412fb1ca35cSkettenis 			DPRINTF(ACDB_BOOTDEV, ("\t-- matched component %s to %s\n",
1413fb1ca35cSkettenis 			    bp->name, dev->dv_xname));
1414c5632f19Sjason 			bootpath_store(1, bp + 1);
1415c5632f19Sjason 			return;
1416c5632f19Sjason 		}
1417fb1ca35cSkettenis 	}
1418fb1ca35cSkettenis 
141957949900Sdlg 	if (strcmp(busname, "scsibus") == 0) {
14200300c697Sjason 		/*
14210300c697Sjason 		 * A SCSI disk or cd; retrieve target/lun information
14220300c697Sjason 		 * from parent and match with current bootpath component.
14230300c697Sjason 		 * Note that we also have look back past the `scsibus'
14240300c697Sjason 		 * device to determine whether this target is on the
14250300c697Sjason 		 * correct controller in our boot path.
14260300c697Sjason 		 */
1427a0837789Sdlg 		struct scsi_attach_args *sa = aux;
14280300c697Sjason 		struct scsi_link *sl = sa->sa_sc_link;
14290300c697Sjason 		u_int target = bp->val[0];
14300300c697Sjason 		u_int lun = bp->val[1];
14310300c697Sjason 
1432c5632f19Sjason 		if (bp->val[0] & 0xffffffff00000000 && bp->val[0] != -1) {
14332df63a3eSkn 			/* Hardware RAID or Fibre channel? */
1434fb1ca35cSkettenis 			if (bp->val[0] == sl->port_wwn && lun == sl->lun) {
1435c5632f19Sjason 				nail_bootdev(dev, bp);
1436c5632f19Sjason 			}
143763effabaSjmatthew 
143863effabaSjmatthew 			/*
143963effabaSjmatthew 			 * sata devices on some controllers don't get
144063effabaSjmatthew 			 * port_wwn filled in, so look at devid too.
144163effabaSjmatthew 			 */
144263effabaSjmatthew 			if (sl->id && sl->id->d_len == 8 &&
144363effabaSjmatthew 			    sl->id->d_type == DEVID_NAA &&
144463effabaSjmatthew 			    memcmp(sl->id + 1, &bp->val[0], 8) == 0)
144563effabaSjmatthew 				nail_bootdev(dev, bp);
1446c5632f19Sjason 			return;
1447c5632f19Sjason 		}
1448c5632f19Sjason 
1449fb1ca35cSkettenis 		/* Check the controller that this scsibus is on. */
1450f25330fcSkrw 		if ((bp-1)->dev != sl->bus->sc_dev.dv_parent)
14510300c697Sjason 			return;
14520300c697Sjason 
14530300c697Sjason 		/*
14540300c697Sjason 		 * Bounds check: we know the target and lun widths.
14550300c697Sjason 		 */
14560b29cb40Skrw 		if (target >= sl->bus->sb_adapter_buswidth ||
14570b29cb40Skrw 		    lun >= sl->bus->sb_luns) {
14580300c697Sjason 			printf("SCSI disk bootpath component not accepted: "
14590300c697Sjason 			       "target %u; lun %u\n", target, lun);
14600300c697Sjason 			return;
14610300c697Sjason 		}
14620300c697Sjason 
1463fb1ca35cSkettenis 		if (target == sl->target && lun == sl->lun) {
14640300c697Sjason 			nail_bootdev(dev, bp);
14650300c697Sjason 			return;
14660300c697Sjason 		}
1467fb1ca35cSkettenis 	}
1468fb1ca35cSkettenis 
1469fb1ca35cSkettenis 	if (strcmp("wd", devname) == 0) {
14700300c697Sjason 		/* IDE disks. */
14710300c697Sjason 		struct ata_atapi_attach *aa = aux;
1472e34882ceSkettenis 		u_int channel, drive;
14730300c697Sjason 
1474e34882ceSkettenis 		if (strcmp(bp->name, "ata") == 0 &&
1475e34882ceSkettenis 		    bp->val[0] == aa->aa_channel) {
1476e34882ceSkettenis 			channel = bp->val[0]; bp++;
1477e34882ceSkettenis 			drive = bp->val[0];
1478e34882ceSkettenis 		} else {
1479e34882ceSkettenis 			channel = bp->val[0] / 2;
1480e34882ceSkettenis 			drive = bp->val[0] % 2;
1481e34882ceSkettenis 		}
1482e34882ceSkettenis 
1483e34882ceSkettenis 		if (channel == aa->aa_channel &&
1484e34882ceSkettenis 		    drive == aa->aa_drv_data->drive) {
14850300c697Sjason 			nail_bootdev(dev, bp);
14860300c697Sjason 			return;
14870300c697Sjason 		}
14880300c697Sjason 	}
14890300c697Sjason }
14900300c697Sjason 
14910300c697Sjason void
nail_bootdev(struct device * dev,struct bootpath * bp)1492ba134ca3Sstsp nail_bootdev(struct device *dev, struct bootpath *bp)
14930300c697Sjason {
14940300c697Sjason 
14950300c697Sjason 	if (bp->dev != NULL)
14960300c697Sjason 		panic("device_register: already got a boot device: %s",
14970300c697Sjason 			bp->dev->dv_xname);
14980300c697Sjason 
14990300c697Sjason 	/*
15000300c697Sjason 	 * Mark this bootpath component by linking it to the matched
15010300c697Sjason 	 * device. We pick up the device pointer in cpu_rootconf().
15020300c697Sjason 	 */
15030300c697Sjason 	booted_device = bp->dev = dev;
1504fb1ca35cSkettenis 	DPRINTF(ACDB_BOOTDEV, ("\t-- found bootdevice: %s\n",dev->dv_xname));
15050300c697Sjason 
15060300c697Sjason 	/*
15070300c697Sjason 	 * Then clear the current bootpath component, so we don't spuriously
15080300c697Sjason 	 * match similar instances on other busses, e.g. a disk on
15090300c697Sjason 	 * another SCSI bus with the same target.
15100300c697Sjason 	 */
15110300c697Sjason 	bootpath_store(1, NULL);
15120300c697Sjason }
15137dc861caSderaadt 
15143ad05d8aSmiod const struct nam2blk nam2blk[] = {
15157dc861caSderaadt 	{ "rd",		 5 },
151668b8e131Snaddy 	{ "sd",		 7 },
1517894da477Stodd 	{ "vnd",	 8 },
151868b8e131Snaddy 	{ "wd",		12 },
151968b8e131Snaddy 	{ "fd",		16 },
152068b8e131Snaddy 	{ "cd",		18 },
152132c041f0Sderaadt 	{ NULL,		-1 }
15227dc861caSderaadt };
1523