xref: /illumos-gate/usr/src/uts/sun4u/os/fillsysinfo.c (revision f166393f4d30d59a005967d6c6d2869ef830b75d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/errno.h>
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/cpu.h>
33 #include <sys/cpuvar.h>
34 #include <sys/clock.h>
35 
36 #include <sys/promif.h>
37 #include <sys/promimpl.h>
38 #include <sys/systm.h>
39 #include <sys/machsystm.h>
40 #include <sys/debug.h>
41 #include <sys/sunddi.h>
42 #include <sys/modctl.h>
43 #include <sys/spitregs.h>
44 #include <sys/cheetahregs.h>
45 #include <sys/cpu_module.h>
46 #include <sys/kobj.h>
47 #include <sys/cmp.h>
48 #include <sys/async.h>
49 #include <vm/page.h>
50 
51 /*
52  * The OpenBoot Standalone Interface supplies the kernel with
53  * implementation dependent parameters through the devinfo/property mechanism
54  */
55 typedef enum { XDRBOOL, XDRINT, XDRSTRING } xdrs;
56 
57 /*
58  * structure describing properties that we are interested in querying the
59  * OBP for.
60  */
61 struct getprop_info {
62 	char	*name;
63 	xdrs	type;
64 	uint_t	*var;
65 };
66 
67 /*
68  * structure used to convert between a string returned by the OBP & a type
69  * used within the kernel. We prefer to paramaterize rather than type.
70  */
71 struct convert_info {
72 	char	*name;
73 	uint_t	var;
74 	char	*realname;
75 };
76 
77 /*
78  * structure describing nodes that we are interested in querying the OBP for
79  * properties.
80  */
81 struct node_info {
82 	char			*name;
83 	int			size;
84 	struct getprop_info	*prop;
85 	struct getprop_info	*prop_end;
86 	unsigned int		*value;
87 };
88 
89 /*
90  * macro definitions for routines that form the OBP interface
91  */
92 #define	NEXT			prom_nextnode
93 #define	CHILD			prom_childnode
94 #define	GETPROP			prom_getprop
95 #define	GETPROPLEN		prom_getproplen
96 
97 
98 /* 0=quiet; 1=verbose; 2=debug */
99 int	debug_fillsysinfo = 0;
100 #define	VPRINTF if (debug_fillsysinfo) prom_printf
101 
102 int ncpunode;
103 struct cpu_node cpunodes[NCPU];
104 
105 static void	check_cpus_ver(void);
106 static void	check_cpus_set(void);
107 void	fill_cpu(dnode_t);
108 void	fill_cpu_ddi(dev_info_t *);
109 void	empty_cpu(int);
110 void	plat_fill_mc(dnode_t);
111 #pragma weak plat_fill_mc
112 
113 uint64_t	system_clock_freq;
114 
115 /*
116  * list of well known devices that must be mapped, and the variables that
117  * contain their addresses.
118  */
119 caddr_t		v_auxio_addr = NULL;
120 caddr_t		v_eeprom_addr = NULL;
121 caddr_t		v_timecheck_addr = NULL;
122 caddr_t 	v_rtc_addr_reg = NULL;
123 volatile unsigned char	*v_rtc_data_reg = NULL;
124 volatile uint8_t	*v_pmc_addr_reg = NULL;
125 volatile uint8_t	*v_pmc_data_reg = NULL;
126 
127 int		niobus = 0;
128 uint_t		niommu_tsbs = 0;
129 
130 /*
131  * Hardware watchdog support.
132  */
133 #define	CHOSEN_EEPROM	"eeprom"
134 #define	WATCHDOG_ENABLE "watchdog-enable"
135 static dnode_t 		chosen_eeprom;
136 
137 /*
138  * Appropriate tod module will be dynamically selected while booting
139  * based on finding a device tree node with a "device_type" property value
140  * of "tod". If such a node describing tod is not found, for backward
141  * compatibility, a node with a "name" property value of "eeprom" and
142  * "model" property value of "mk48t59" will be used. Failing to find a
143  * node matching either of the above criteria will result in no tod module
144  * being selected; this will cause the boot process to halt.
145  */
146 char	*tod_module_name;
147 
148 /*
149  * If this variable is non-zero, cpr should return "not supported" when
150  * it is queried even though it would normally be supported on this platform.
151  */
152 int cpr_supported_override;
153 
154 /*
155  * Some platforms may need to support CPR even in the absence of the
156  * energystar-v* property (Enchilada server, for example).  If this
157  * variable is non-zero, cpr should proceed even in the absence
158  * of the energystar-v* property.
159  */
160 int cpr_platform_enable = 0;
161 
162 /*
163  * Some nodes have functions that need to be called when they're seen.
164  */
165 static void	have_sbus(dnode_t);
166 static void	have_pci(dnode_t);
167 static void	have_eeprom(dnode_t);
168 static void	have_auxio(dnode_t);
169 static void	have_rtc(dnode_t);
170 static void	have_tod(dnode_t);
171 static void	have_pmc(dnode_t);
172 
173 static struct wkdevice {
174 	char *wk_namep;
175 	void (*wk_func)(dnode_t);
176 	caddr_t *wk_vaddrp;
177 	ushort_t wk_flags;
178 #define	V_OPTIONAL	0x0000
179 #define	V_MUSTHAVE	0x0001
180 #define	V_MAPPED	0x0002
181 #define	V_MULTI		0x0003	/* optional, may be more than one */
182 } wkdevice[] = {
183 	{ "sbus", have_sbus, NULL, V_MULTI },
184 	{ "pci", have_pci, NULL, V_MULTI },
185 	{ "eeprom", have_eeprom, NULL, V_MULTI },
186 	{ "auxio", have_auxio, NULL, V_OPTIONAL },
187 	{ "rtc", have_rtc, NULL, V_OPTIONAL },
188 	{ "pmc", have_pmc, NULL, V_OPTIONAL },
189 	{ 0, },
190 };
191 
192 static void map_wellknown(dnode_t);
193 
194 void
195 map_wellknown_devices()
196 {
197 	struct wkdevice *wkp;
198 	phandle_t	ieeprom;
199 	dnode_t	root;
200 	uint_t	stick_freq;
201 
202 	/*
203 	 * if there is a chosen eeprom, note it (for have_eeprom())
204 	 */
205 	if (GETPROPLEN(prom_chosennode(), CHOSEN_EEPROM) ==
206 	    sizeof (phandle_t) &&
207 	    GETPROP(prom_chosennode(), CHOSEN_EEPROM, (caddr_t)&ieeprom) != -1)
208 		chosen_eeprom = (dnode_t)prom_decode_int(ieeprom);
209 
210 	root = prom_nextnode((dnode_t)0);
211 	/*
212 	 * Get System clock frequency from root node if it exists.
213 	 */
214 	if (GETPROP(root, "stick-frequency", (caddr_t)&stick_freq) != -1)
215 		system_clock_freq = stick_freq;
216 
217 	map_wellknown(NEXT((dnode_t)0));
218 
219 	/*
220 	 * See if it worked
221 	 */
222 	for (wkp = wkdevice; wkp->wk_namep; ++wkp) {
223 		if (wkp->wk_flags == V_MUSTHAVE) {
224 			cmn_err(CE_PANIC, "map_wellknown_devices: required "
225 			    "device %s not mapped", wkp->wk_namep);
226 		}
227 	}
228 
229 	/*
230 	 * all sun4u systems must have an IO bus, i.e. sbus or pcibus
231 	 */
232 	if (niobus == 0)
233 		cmn_err(CE_PANIC, "map_wellknown_devices: no i/o bus node");
234 
235 	check_cpus_ver();
236 	check_cpus_set();
237 }
238 
239 /*
240  * map_wellknown - map known devices & registers
241  */
242 static void
243 map_wellknown(dnode_t curnode)
244 {
245 	extern int status_okay(int, char *, int);
246 	char tmp_name[MAXSYSNAME];
247 	static void fill_address(dnode_t, char *);
248 	int sok;
249 
250 #ifdef VPRINTF
251 	VPRINTF("map_wellknown(%x)\n", curnode);
252 #endif /* VPRINTF */
253 
254 	for (curnode = CHILD(curnode); curnode; curnode = NEXT(curnode)) {
255 		/*
256 		 * prune subtree if status property indicating not okay
257 		 */
258 		sok = status_okay((int)curnode, (char *)NULL, 0);
259 		if (!sok) {
260 			char devtype_buf[OBP_MAXPROPNAME];
261 			int size;
262 
263 #ifdef VPRINTF
264 			VPRINTF("map_wellknown: !okay status property\n");
265 #endif /* VPRINTF */
266 			/*
267 			 * a status property indicating bad memory will be
268 			 * associated with a node which has a "device_type"
269 			 * property with a value of "memory-controller"
270 			 */
271 			if ((size = GETPROPLEN(curnode,
272 			    OBP_DEVICETYPE)) == -1)
273 				continue;
274 			if (size > OBP_MAXPROPNAME) {
275 				cmn_err(CE_CONT, "node %x '%s' prop too "
276 				    "big\n", curnode, OBP_DEVICETYPE);
277 				continue;
278 			}
279 			if (GETPROP(curnode, OBP_DEVICETYPE,
280 			    devtype_buf) == -1) {
281 				cmn_err(CE_CONT, "node %x '%s' get failed\n",
282 				    curnode, OBP_DEVICETYPE);
283 				continue;
284 			}
285 			if (strcmp(devtype_buf, "memory-controller") != 0)
286 				continue;
287 			/*
288 			 * ...else fall thru and process the node...
289 			 */
290 		}
291 		bzero(tmp_name, MAXSYSNAME);
292 		if (GETPROP(curnode, OBP_NAME, (caddr_t)tmp_name) != -1)
293 			fill_address(curnode, tmp_name);
294 		if (GETPROP(curnode, OBP_DEVICETYPE, tmp_name) != -1 &&
295 		    strcmp(tmp_name, "cpu") == 0) {
296 			fill_cpu(curnode);
297 		}
298 		if (strcmp(tmp_name, "tod") == 0)
299 			have_tod(curnode);
300 		if (sok && (strcmp(tmp_name, "memory-controller") == 0) &&
301 		    (&plat_fill_mc != NULL))
302 			plat_fill_mc(curnode);
303 		map_wellknown(curnode);
304 	}
305 }
306 
307 static void
308 fill_address(dnode_t curnode, char *namep)
309 {
310 	struct wkdevice *wkp;
311 	int size;
312 	uint32_t vaddr;
313 
314 	for (wkp = wkdevice; wkp->wk_namep; ++wkp) {
315 		if (strcmp(wkp->wk_namep, namep) != 0)
316 			continue;
317 		if (wkp->wk_flags == V_MAPPED)
318 			return;
319 		if (wkp->wk_vaddrp != NULL) {
320 			if ((size = GETPROPLEN(curnode, OBP_ADDRESS)) == -1) {
321 				cmn_err(CE_CONT, "device %s size %d\n",
322 				    namep, size);
323 				continue;
324 			}
325 			if (size != sizeof (vaddr)) {
326 				cmn_err(CE_CONT, "device %s address prop too "
327 				    "big\n", namep);
328 				continue;
329 			}
330 			if (GETPROP(curnode, OBP_ADDRESS,
331 			    (caddr_t)&vaddr) == -1) {
332 				cmn_err(CE_CONT, "device %s not mapped\n",
333 				    namep);
334 				continue;
335 			}
336 
337 			/* make into a native pointer */
338 			*wkp->wk_vaddrp = (caddr_t)(uintptr_t)vaddr;
339 #ifdef VPRINTF
340 			VPRINTF("fill_address: %s mapped to %p\n", namep,
341 			    *wkp->wk_vaddrp);
342 #endif /* VPRINTF */
343 		}
344 		if (wkp->wk_func != NULL)
345 			(*wkp->wk_func)(curnode);
346 		/*
347 		 * If this one is optional and there may be more than
348 		 * one, don't set V_MAPPED, which would cause us to skip it
349 		 * next time around
350 		 */
351 		if (wkp->wk_flags != V_MULTI)
352 			wkp->wk_flags = V_MAPPED;
353 	}
354 }
355 
356 int
357 get_portid(dnode_t node, dnode_t *cmpp)
358 {
359 	int portid;
360 	char dev_type[OBP_MAXPROPNAME];
361 
362 	if (cmpp != NULL)
363 		*cmpp = OBP_NONODE;
364 
365 	if (GETPROP(node, "portid", (caddr_t)&portid) != -1)
366 		return (portid);
367 	if (GETPROP(node, "upa-portid", (caddr_t)&portid) != -1)
368 		return (portid);
369 	if (GETPROP(node, "device_type", (caddr_t)&dev_type) == -1)
370 		return (-1);
371 
372 	/* On a CMP core, the "portid" is in the parent */
373 	if (strcmp(dev_type, "cpu") == 0) {
374 		node = prom_parentnode(node);
375 		if (GETPROP(node, "portid", (caddr_t)&portid) != -1) {
376 			if (cmpp != NULL)
377 				*cmpp = node;
378 
379 			return (portid);
380 		}
381 	}
382 
383 	return (-1);
384 }
385 
386 /*
387  * Adjust page coloring variables based on the physical ecache setsize of
388  * the configured cpus:
389  *
390  * Set ecache_setsize to max ecache set size to be used by
391  * page_coloring_init() to determine the page colors to configure.
392  * The adjustment is unlikely to be necessary... For cheetah+ systems,
393  * ecache_setsize should already be set in cpu_fiximp() to the maximum
394  * possible ecache setsize of any supported cheetah+ cpus. The adjustment
395  * is for the off chance that a non-cheetah+ system may have heterogenous
396  * cpus.
397  *
398  * Set cpu_setsize to the actual cpu setsize if the setsize is homogenous
399  * across all cpus otherwise set it to -1 if heterogenous.
400  *
401  * Set cpu_page_colors to -1 to signify heterogeneity of ecache setsizes
402  * to the page_get routines.
403  */
404 static void
405 adj_ecache_setsize(int ecsetsize)
406 {
407 	if (ecsetsize > ecache_setsize)
408 		ecache_setsize = ecsetsize;
409 
410 	switch (cpu_setsize) {
411 	case -1:
412 		break;
413 	case 0:
414 		cpu_setsize = ecsetsize;
415 		break;
416 	default:
417 		/* set to -1 if hetergenous cpus */
418 		if (cpu_setsize != ecsetsize) {
419 			if (do_pg_coloring)
420 				cpu_page_colors = -1;
421 			/*
422 			 * if page coloring disabled, cpu_page_colors should
423 			 * remain 0 to prevent page coloring processing.
424 			 */
425 			cpu_setsize = -1;
426 		}
427 		break;
428 	}
429 }
430 
431 void
432 fill_cpu(dnode_t node)
433 {
434 	extern int cpu_get_cpu_unum(int, char *, int, int *);
435 	struct cpu_node *cpunode;
436 	processorid_t cpuid;
437 	int portid;
438 	int tlbsize;
439 	int size;
440 	uint_t clk_freq;
441 	dnode_t cmpnode;
442 	char namebuf[OBP_MAXPROPNAME], unum[UNUM_NAMLEN];
443 	char *namebufp;
444 
445 	if ((portid = get_portid(node, &cmpnode)) == -1) {
446 		cmn_err(CE_PANIC, "portid not found");
447 	}
448 
449 	if (GETPROP(node, "cpuid", (caddr_t)&cpuid) == -1) {
450 		cpuid = portid;
451 	}
452 
453 	if (cpuid < 0 || cpuid >= NCPU) {
454 		cmn_err(CE_PANIC, "cpu node %x: cpuid %d out of range",
455 			node, cpuid);
456 		return;
457 	}
458 
459 	cpunode = &cpunodes[cpuid];
460 	cpunode->portid = portid;
461 
462 	if (cpu_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, &size) != 0) {
463 		cpunode->fru_fmri[0] = '\0';
464 	} else {
465 		(void) snprintf(cpunode->fru_fmri, sizeof (cpunode->fru_fmri),
466 		    "%s%s", CPU_FRU_FMRI, unum);
467 	}
468 
469 	(void) GETPROP(node, (cmpnode ? "compatible" : "name"), namebuf);
470 	namebufp = namebuf;
471 	if (strncmp(namebufp, "SUNW,", 5) == 0)
472 		namebufp += 5;
473 	(void) strcpy(cpunode->name, namebufp);
474 
475 	(void) GETPROP(node, "implementation#",
476 	    (caddr_t)&cpunode->implementation);
477 	(void) GETPROP(node, "mask#", (caddr_t)&cpunode->version);
478 
479 	if (IS_CHEETAH(cpunode->implementation)) {
480 		/* remap mask reg */
481 		cpunode->version = REMAP_CHEETAH_MASK(cpunode->version);
482 	}
483 	if (GETPROP(node, "clock-frequency", (caddr_t)&clk_freq) == -1) {
484 		/*
485 		 * If we didn't find it in the CPU node, look in the root node.
486 		 */
487 		dnode_t root = prom_nextnode((dnode_t)0);
488 		if (GETPROP(root, "clock-frequency", (caddr_t)&clk_freq) == -1)
489 			clk_freq = 0;
490 	}
491 	cpunode->clock_freq = clk_freq;
492 
493 	ASSERT(cpunode->clock_freq != 0);
494 	/*
495 	 * Compute scaling factor based on rate of %tick. This is used
496 	 * to convert from ticks derived from %tick to nanoseconds. See
497 	 * comment in sun4u/sys/clock.h for details.
498 	 */
499 	cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC <<
500 	    (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq);
501 
502 	(void) GETPROP(node, "#itlb-entries", (caddr_t)&tlbsize);
503 	ASSERT(tlbsize < USHRT_MAX); /* since we cast it */
504 	cpunode->itlb_size = (ushort_t)tlbsize;
505 
506 	(void) GETPROP(node, "#dtlb-entries", (caddr_t)&tlbsize);
507 	ASSERT(tlbsize < USHRT_MAX); /* since we cast it */
508 	cpunode->dtlb_size = (ushort_t)tlbsize;
509 
510 	cpunode->nodeid = node;
511 
512 	if (cmpnode != OBP_NONODE) {
513 		/*
514 		 * If the CPU has a level 3 cache, then it will be the
515 		 * external cache. Otherwise the level 2 cache is the
516 		 * external cache.
517 		 */
518 		size = 0;
519 		(void) GETPROP(node, "l3-cache-size", (caddr_t)&size);
520 		if (size <= 0)
521 			(void) GETPROP(node, "l2-cache-size", (caddr_t)&size);
522 		ASSERT(size != 0);
523 		cpunode->ecache_size = size;
524 
525 		size = 0;
526 		(void) GETPROP(node, "l3-cache-line-size", (caddr_t)&size);
527 		if (size <= 0)
528 			(void) GETPROP(node, "l2-cache-line-size",
529 			    (caddr_t)&size);
530 		ASSERT(size != 0);
531 		cpunode->ecache_linesize = size;
532 
533 		size = 0;
534 		(void) GETPROP(node, "l2-cache-associativity", (caddr_t)&size);
535 		ASSERT(size != 0);
536 		cpunode->ecache_associativity = size;
537 
538 		cmp_add_cpu(portid, cpuid);
539 	} else {
540 		size = 0;
541 		(void) GETPROP(node, "ecache-size", (caddr_t)&size);
542 		ASSERT(size != 0);
543 		cpunode->ecache_size = size;
544 
545 		size = 0;
546 		(void) GETPROP(node, "ecache-line-size", (caddr_t)&size);
547 		ASSERT(size != 0);
548 		cpunode->ecache_linesize = size;
549 
550 		size = 0;
551 		(void) GETPROP(node, "ecache-associativity", (caddr_t)&size);
552 		ASSERT(size != 0);
553 		cpunode->ecache_associativity = size;
554 	}
555 
556 	/* by default set msram to non-mirrored one */
557 	cpunode->msram = ECACHE_CPU_NON_MIRROR;
558 
559 	if (GETPROPLEN(node, "msram") != -1) {
560 		cpunode->msram = ECACHE_CPU_MIRROR;
561 	}
562 
563 	if (GETPROPLEN(node, "msram-observed") != -1) {
564 		cpunode->msram = ECACHE_CPU_MIRROR;
565 	}
566 
567 	if (ncpunode == 0) {
568 		cpu_fiximp(node);
569 	}
570 
571 	cpunode->ecache_setsize =
572 	    cpunode->ecache_size / cpunode->ecache_associativity;
573 
574 	adj_ecache_setsize(cpunode->ecache_setsize);
575 
576 	ncpunode++;
577 }
578 
579 int
580 get_portid_ddi(dev_info_t *dip, dev_info_t **cmpp)
581 {
582 	int portid;
583 	char dev_type[OBP_MAXPROPNAME];
584 	int len = OBP_MAXPROPNAME;
585 
586 	if (cmpp != NULL)
587 		*cmpp = NULL;
588 
589 	if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
590 		    DDI_PROP_DONTPASS, "portid", -1)) != -1)
591 		return (portid);
592 	if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
593 		    DDI_PROP_DONTPASS, "upa-portid", -1)) != -1)
594 		return (portid);
595 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
596 		DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type,
597 		&len) != 0)
598 		return (-1);
599 
600 	/* On a CMP core, the "portid" is in the parent */
601 	if (strcmp(dev_type, "cpu") == 0) {
602 		dip = ddi_get_parent(dip);
603 		if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
604 		    DDI_PROP_DONTPASS, "portid", -1)) != -1) {
605 			if (cmpp != NULL)
606 				*cmpp = dip;
607 
608 			return (portid);
609 		}
610 	}
611 
612 	return (-1);
613 }
614 
615 /*
616  * A hotplug version of fill_cpu().  (Doesn't assume that there's a node
617  * in the PROM device tree for this CPU.)  We still need the PROM version
618  * since it is called very early in the boot cycle before (before
619  * setup_ddi()).  Sigh...someday this will all be cleaned up.
620  */
621 
622 void
623 fill_cpu_ddi(dev_info_t *dip)
624 {
625 	extern int cpu_get_cpu_unum(int, char *, int, int *);
626 	struct cpu_node *cpunode;
627 	processorid_t cpuid;
628 	int portid;
629 	int len;
630 	int tlbsize;
631 	dev_info_t *cmpnode;
632 	char namebuf[OBP_MAXPROPNAME], unum[UNUM_NAMLEN];
633 	char *namebufp;
634 
635 	if ((portid = get_portid_ddi(dip, &cmpnode)) == -1) {
636 		cmn_err(CE_PANIC, "portid not found");
637 	}
638 
639 	if ((cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
640 	    DDI_PROP_DONTPASS, "cpuid", -1)) == -1) {
641 		cpuid = portid;
642 	}
643 
644 	if (cpuid < 0 || cpuid >= NCPU) {
645 		cmn_err(CE_PANIC, "cpu dip %p: cpuid %d out of range",
646 			(void *) dip, cpuid);
647 		return;
648 	}
649 
650 	cpunode = &cpunodes[cpuid];
651 	cpunode->portid = portid;
652 
653 	if (cpu_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, &len) != 0) {
654 		cpunode->fru_fmri[0] = '\0';
655 	} else {
656 		(void) snprintf(cpunode->fru_fmri, sizeof (cpunode->fru_fmri),
657 		    "%s%s", CPU_FRU_FMRI, unum);
658 	}
659 
660 	len = sizeof (namebuf);
661 	(void) ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
662 	    DDI_PROP_DONTPASS, (cmpnode ? "compatible" : "name"),
663 	    (caddr_t)namebuf, &len);
664 
665 	namebufp = namebuf;
666 	if (strncmp(namebufp, "SUNW,", 5) == 0)
667 		namebufp += 5;
668 	(void) strcpy(cpunode->name, namebufp);
669 
670 	cpunode->implementation = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
671 	    DDI_PROP_DONTPASS, "implementation#", 0);
672 
673 	cpunode->version = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
674 	    DDI_PROP_DONTPASS, "mask#", 0);
675 
676 	if (IS_CHEETAH(cpunode->implementation)) {
677 		/* remap mask reg */
678 		cpunode->version = REMAP_CHEETAH_MASK(cpunode->version);
679 	}
680 
681 	cpunode->clock_freq = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
682 	    DDI_PROP_DONTPASS, "clock-frequency", 0);
683 
684 	ASSERT(cpunode->clock_freq != 0);
685 	/*
686 	 * Compute scaling factor based on rate of %tick. This is used
687 	 * to convert from ticks derived from %tick to nanoseconds. See
688 	 * comment in sun4u/sys/clock.h for details.
689 	 */
690 	cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC <<
691 	    (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq);
692 
693 	tlbsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
694 	    DDI_PROP_DONTPASS, "#itlb-entries", 0);
695 	ASSERT(tlbsize < USHRT_MAX); /* since we cast it */
696 	cpunode->itlb_size = (ushort_t)tlbsize;
697 
698 	tlbsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
699 	    DDI_PROP_DONTPASS, "#dtlb-entries", 0);
700 	ASSERT(tlbsize < USHRT_MAX); /* since we cast it */
701 	cpunode->dtlb_size = (ushort_t)tlbsize;
702 
703 	cpunode->nodeid = ddi_get_nodeid(dip);
704 
705 	if (cmpnode != NULL) {
706 		/*
707 		 * If the CPU has a level 3 cache, then that is it's
708 		 * external cache. Otherwise the external cache must
709 		 * be the level 2 cache.
710 		 */
711 		cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY,
712 		    dip, DDI_PROP_DONTPASS, "l3-cache-size", 0);
713 		if (cpunode->ecache_size == 0)
714 			cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY,
715 			    dip, DDI_PROP_DONTPASS, "l2-cache-size", 0);
716 		ASSERT(cpunode->ecache_size != 0);
717 
718 		cpunode->ecache_linesize = ddi_prop_get_int(DDI_DEV_T_ANY,
719 		    dip, DDI_PROP_DONTPASS, "l3-cache-line-size", 0);
720 		if (cpunode->ecache_linesize == 0)
721 			cpunode->ecache_linesize =
722 			    ddi_prop_get_int(DDI_DEV_T_ANY, dip,
723 			    DDI_PROP_DONTPASS, "l2-cache-line-size", 0);
724 		ASSERT(cpunode->ecache_linesize != 0);
725 
726 		cpunode->ecache_associativity = ddi_prop_get_int(DDI_DEV_T_ANY,
727 		    dip, DDI_PROP_DONTPASS, "l2-cache-associativity", 0);
728 		ASSERT(cpunode->ecache_associativity != 0);
729 
730 		cmp_add_cpu(portid, cpuid);
731 	} else {
732 		cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY,
733 		    dip, DDI_PROP_DONTPASS, "ecache-size", 0);
734 		ASSERT(cpunode->ecache_size != 0);
735 
736 		cpunode->ecache_linesize = ddi_prop_get_int(DDI_DEV_T_ANY,
737 		    dip, DDI_PROP_DONTPASS, "ecache-line-size", 0);
738 		ASSERT(cpunode->ecache_linesize != 0);
739 
740 		cpunode->ecache_associativity = ddi_prop_get_int(DDI_DEV_T_ANY,
741 		    dip, DDI_PROP_DONTPASS, "ecache-associativity", 0);
742 		ASSERT(cpunode->ecache_associativity != 0);
743 	}
744 
745 	/* by default set msram to non-mirrored one */
746 	cpunode->msram = ECACHE_CPU_NON_MIRROR;
747 
748 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "msram")) {
749 			cpunode->msram = ECACHE_CPU_MIRROR;
750 	} else if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
751 			"msram-observed")) {
752 				cpunode->msram = ECACHE_CPU_MIRROR;
753 	}
754 
755 	ASSERT(ncpunode > 0);	/* fiximp not req'd */
756 
757 	cpunode->ecache_setsize =
758 	    cpunode->ecache_size / cpunode->ecache_associativity;
759 
760 	adj_ecache_setsize(cpunode->ecache_setsize);
761 
762 	ncpunode++;
763 }
764 
765 void
766 empty_cpu(int cpuid)
767 {
768 	bzero(&cpunodes[cpuid], sizeof (struct cpu_node));
769 	ncpunode--;
770 }
771 
772 #ifdef SF_ERRATA_30 /* call causes fp-disabled */
773 int spitfire_call_bug = 0;
774 #endif
775 #ifdef SF_V9_TABLE_28	/* fp over/underflow traps may cause wrong fsr.cexc */
776 int spitfire_bb_fsr_bug = 0;
777 #endif
778 
779 #ifdef JALAPENO_ERRATA_85
780 /*
781  * Set the values here assuming we're running 2.4 or later Jalapenos.  If
782  * not, they'll be reset below.  Either way, the default can be overridden
783  * when we read /etc/system later in boot.
784  */
785 int jp_errata_85_allow_slow_scrub = 1;
786 int jp_errata_85_enable = 0;
787 #endif	/* JALAPENO_ERRATA_85 */
788 
789 static void
790 check_cpus_ver(void)
791 {
792 	int i;
793 	int impl, cpuid = getprocessorid();
794 	int min_supported_rev;
795 
796 	ASSERT(cpunodes[cpuid].nodeid != 0);
797 
798 	impl = cpunodes[cpuid].implementation;
799 	switch (impl) {
800 	default:
801 		min_supported_rev = 0;
802 		break;
803 	case SPITFIRE_IMPL:
804 		min_supported_rev = SPITFIRE_MINREV_SUPPORTED;
805 		break;
806 	case CHEETAH_IMPL:
807 		min_supported_rev = CHEETAH_MINREV_SUPPORTED;
808 		break;
809 	}
810 
811 	for (i = 0; i < NCPU; i++) {
812 		if (cpunodes[i].nodeid == 0)
813 			continue;
814 
815 		if (IS_SPITFIRE(impl)) {
816 			if (cpunodes[i].version < min_supported_rev) {
817 				cmn_err(CE_PANIC,
818 				"UltraSPARC versions older than %d.%d"
819 				" are no longer supported (cpu #%d)",
820 				SPITFIRE_MAJOR_VERSION(min_supported_rev),
821 				SPITFIRE_MINOR_VERSION(min_supported_rev), i);
822 			}
823 
824 			/*
825 			 * Min supported rev is 2.1 but we've seen problems
826 			 * with that so we still want to warn if we see one.
827 			 */
828 			if (cpunodes[i].version < 0x22) {
829 				cmn_err(CE_WARN,
830 				"UltraSPARC versions older than "
831 				"2.2 are not supported (cpu #%d)", i);
832 #ifdef SF_ERRATA_30 /* call causes fp-disabled */
833 				spitfire_call_bug = 1;
834 #endif /* SF_ERRATA_30 */
835 			}
836 		}
837 
838 
839 #ifdef SF_V9_TABLE_28	/* fp over/underflow traps may cause wrong fsr.cexc */
840 		if (IS_SPITFIRE(impl) || IS_BLACKBIRD(impl))
841 			spitfire_bb_fsr_bug = 1;
842 #endif /* SF_V9_TABLE_28 */
843 
844 		if (IS_CHEETAH(impl)) {
845 			if (cpunodes[i].version < min_supported_rev) {
846 				cmn_err(CE_PANIC,
847 				"UltraSPARC-III versions older than %d.%d"
848 				" are no longer supported (cpu #%d)",
849 				CHEETAH_MAJOR_VERSION(min_supported_rev),
850 				CHEETAH_MINOR_VERSION(min_supported_rev), i);
851 			}
852 
853 		}
854 
855 #ifdef JALAPENO_ERRATA_85
856 		if (IS_JALAPENO(impl) && (cpunodes[i].version < 0x24)) {
857 			jp_errata_85_allow_slow_scrub = 0;
858 			jp_errata_85_enable = 1;
859 		}
860 #endif /* JALAPENO_ERRATA_85 */
861 	}
862 }
863 
864 /*
865  * Check for a legal set of CPUs.
866  */
867 static void
868 check_cpus_set(void)
869 {
870 	int i;
871 	int impl;
872 	int npanther = 0;
873 
874 	impl = cpunodes[getprocessorid()].implementation;
875 
876 	switch (impl) {
877 	case CHEETAH_PLUS_IMPL:
878 	case JAGUAR_IMPL:
879 	case PANTHER_IMPL:
880 		/*
881 		 * Check for a legal heterogeneous set of CPUs.
882 		 */
883 		for (i = 0; i < NCPU; i++) {
884 			if (cpunodes[i].nodeid == 0)
885 				continue;
886 
887 			if (IS_PANTHER(cpunodes[i].implementation)) {
888 				npanther += 1;
889 			}
890 
891 			if (!(IS_CHEETAH_PLUS(cpunodes[i].implementation) ||
892 			    IS_JAGUAR(cpunodes[i].implementation) ||
893 			    IS_PANTHER(cpunodes[i].implementation))) {
894 				use_mp = 0;
895 				break;
896 			}
897 		}
898 		break;
899 	default:
900 		/*
901 		 * Check for a homogeneous set of CPUs.
902 		 */
903 		for (i = 0; i < NCPU; i++) {
904 			if (cpunodes[i].nodeid == 0)
905 				continue;
906 
907 			if (cpunodes[i].implementation != impl) {
908 				use_mp = 0;
909 				break;
910 			}
911 		}
912 		break;
913 	}
914 
915 	/*
916 	 * Change from mmu_page_sizes from 4 to 6 for totally-Panther domains,
917 	 * where npanther == ncpunode. Also, set ecache_alignsize (and a few
918 	 * other globals) to the correct value for totally-Panther domains.
919 	 */
920 	if (&mmu_init_mmu_page_sizes) {
921 		(void) mmu_init_mmu_page_sizes(npanther);
922 	}
923 	if ((npanther == ncpunode) && (&cpu_fix_allpanther)) {
924 		cpu_fix_allpanther();
925 	}
926 
927 	/*
928 	 * Set max cpus we can have based on ncpunode and use_mp
929 	 */
930 	if (use_mp) {
931 		int (*set_max_ncpus)(void);
932 
933 		set_max_ncpus = (int (*)(void))
934 			kobj_getsymvalue("set_platform_max_ncpus", 0);
935 
936 		if (set_max_ncpus) {
937 			max_ncpus = set_max_ncpus();
938 			if (max_ncpus < ncpunode)
939 				max_ncpus = ncpunode;
940 			boot_max_ncpus = ncpunode;
941 		} else {
942 			max_ncpus = ncpunode;
943 		}
944 	} else {
945 		cmn_err(CE_NOTE, "MP not supported on mismatched modules,"
946 		    " booting UP only");
947 
948 		for (i = 0; i < NCPU; i++) {
949 			if (cpunodes[i].nodeid == 0)
950 				continue;
951 
952 			cmn_err(CE_NOTE, "cpu%d: %s version 0x%x", i,
953 			    cpunodes[i].name, cpunodes[i].version);
954 		}
955 
956 		max_ncpus = 1;
957 	}
958 }
959 
960 /*
961  * The first sysio must always programmed up for the system clock and error
962  * handling purposes, referenced by v_sysio_addr in machdep.c.
963  */
964 static void
965 have_sbus(dnode_t node)
966 {
967 	int size;
968 	uint_t portid;
969 
970 	size = GETPROPLEN(node, "upa-portid");
971 	if (size == -1 || size > sizeof (portid))
972 		cmn_err(CE_PANIC, "upa-portid size");
973 	if (GETPROP(node, "upa-portid", (caddr_t)&portid) == -1)
974 		cmn_err(CE_PANIC, "upa-portid");
975 
976 	niobus++;
977 
978 	/*
979 	 * need one physical TSB
980 	 */
981 	niommu_tsbs++;
982 }
983 
984 
985 #define	IOMMU_PER_SCHIZO	2
986 
987 /*
988  * The first psycho must always programmed up for the system clock and error
989  * handling purposes.
990  */
991 static void
992 have_pci(dnode_t node)
993 {
994 	int size;
995 	uint_t portid;
996 	char compatible[OBP_MAXDRVNAME];
997 
998 	size = GETPROPLEN(node, "portid");
999 	if (size == -1) size = GETPROPLEN(node, "upa-portid");
1000 	if (size == -1)
1001 		return;
1002 	if (size > sizeof (portid))
1003 		cmn_err(CE_PANIC, "portid size wrong");
1004 
1005 	if (GETPROP(node, "portid", (caddr_t)&portid) == -1)
1006 		if (GETPROP(node, "upa-portid", (caddr_t)&portid) == -1)
1007 			cmn_err(CE_PANIC, "portid not found");
1008 
1009 	niobus++;
1010 
1011 
1012 	/*
1013 	 * Need two physical TSBs for Schizo compatible nodes,
1014 	 * one otherwise.
1015 	 */
1016 	compatible[0] = '\0';
1017 	(void) prom_getprop(node, OBP_COMPATIBLE, compatible);
1018 	if (strcmp(compatible, "pci108e,8001") == 0)
1019 		niommu_tsbs += IOMMU_PER_SCHIZO;
1020 	else
1021 		niommu_tsbs++;
1022 }
1023 
1024 /*
1025  * The first eeprom is used as the TOD clock, referenced
1026  * by v_eeprom_addr in locore.s.
1027  */
1028 static void
1029 have_eeprom(dnode_t node)
1030 {
1031 	int size;
1032 	uint32_t eaddr;
1033 
1034 	/*
1035 	 * "todmostek" module will be selected based on finding a "model"
1036 	 * property value of "mk48t59" in the "eeprom" node.
1037 	 */
1038 	if (tod_module_name == NULL) {
1039 		char buf[MAXSYSNAME];
1040 
1041 		if ((GETPROP(node, "model", buf) != -1) &&
1042 		    (strcmp(buf, "mk48t59") == 0))
1043 			tod_module_name = "todmostek";
1044 	}
1045 
1046 	/*
1047 	 * If we have found two distinct eeprom's, then we're done.
1048 	 */
1049 	if (v_eeprom_addr && v_timecheck_addr != v_eeprom_addr)
1050 		return;
1051 
1052 	/*
1053 	 * multiple eeproms may exist but at least
1054 	 * one must have an "address" property
1055 	 */
1056 	if ((size = GETPROPLEN(node, OBP_ADDRESS)) == -1)
1057 		return;
1058 	if (size != sizeof (eaddr))
1059 		cmn_err(CE_PANIC, "eeprom addr size");
1060 	if (GETPROP(node, OBP_ADDRESS, (caddr_t)&eaddr) == -1)
1061 		cmn_err(CE_PANIC, "eeprom addr");
1062 
1063 	/*
1064 	 * If we have a chosen eeprom and it is not this node, keep looking.
1065 	 */
1066 	if (chosen_eeprom != NULL && chosen_eeprom != node) {
1067 		v_timecheck_addr = (caddr_t)(uintptr_t)eaddr;
1068 		return;
1069 	}
1070 
1071 	v_eeprom_addr = (caddr_t)(uintptr_t)eaddr;
1072 
1073 	/*
1074 	 * If we don't find an I/O board to use to check the clock,
1075 	 * we'll fall back on whichever TOD is available.
1076 	 */
1077 	if (v_timecheck_addr == NULL)
1078 		v_timecheck_addr = v_eeprom_addr;
1079 
1080 	/*
1081 	 * Does this eeprom have watchdog support?
1082 	 */
1083 	if (GETPROPLEN(node, WATCHDOG_ENABLE) != -1)
1084 		watchdog_available = 1;
1085 }
1086 
1087 static void
1088 have_rtc(dnode_t node)
1089 {
1090 	int size;
1091 	uint32_t eaddr;
1092 
1093 	/*
1094 	 * "ds1287" module will be selected based on finding a "model"
1095 	 * property value of "ds1287" in the "rtc" node.
1096 	 */
1097 	if (tod_module_name == NULL) {
1098 		char buf[MAXSYSNAME];
1099 
1100 		if (GETPROP(node, "model", buf) != -1) {
1101 			if ((strcmp(buf, "m5819p") == 0) ||
1102 			    (strcmp(buf, "m5823") == 0))
1103 			    tod_module_name = "todm5823";
1104 			else if (strcmp(buf, "ds1287") == 0)
1105 			    tod_module_name = "todds1287";
1106 		}
1107 	}
1108 
1109 	/*
1110 	 * XXX - drives on if address prop doesn't exist, later falls
1111 	 * over in tod module
1112 	 */
1113 	if ((size = GETPROPLEN(node, OBP_ADDRESS)) == -1)
1114 		return;
1115 	if (size != sizeof (eaddr))
1116 		cmn_err(CE_PANIC, "rtc addr size");
1117 	if (GETPROP(node, OBP_ADDRESS, (caddr_t)&eaddr) == -1)
1118 		cmn_err(CE_PANIC, "rtc addr");
1119 
1120 	v_rtc_addr_reg = (caddr_t)(uintptr_t)eaddr;
1121 	v_rtc_data_reg = (volatile unsigned char *)(uintptr_t)eaddr + 1;
1122 
1123 	/*
1124 	 * Does this rtc have watchdog support?
1125 	 */
1126 	if (GETPROPLEN(node, WATCHDOG_ENABLE) != -1)
1127 		watchdog_available = 1;
1128 }
1129 
1130 static void
1131 have_pmc(dnode_t node)
1132 {
1133 	uint32_t vaddr;
1134 	dnode_t root;
1135 
1136 	/*
1137 	 * Watchdog property is in the root node.
1138 	 */
1139 	root = prom_nextnode((dnode_t)0);
1140 	if (GETPROPLEN(root, WATCHDOG_ENABLE) != -1) {
1141 		/*
1142 		 * The hardware watchdog timer resides within logical
1143 		 * unit 8 of SuperI/O. The address property of the node
1144 		 * contains the virtual address that we use to program
1145 		 * the timer.
1146 		 */
1147 		if (GETPROP(node, OBP_ADDRESS, (caddr_t)&vaddr) == -1) {
1148 			watchdog_available = 0;
1149 			return;
1150 		}
1151 		v_pmc_addr_reg = (volatile uint8_t *)(uintptr_t)vaddr;
1152 		v_pmc_data_reg = (volatile uint8_t *)(uintptr_t)vaddr + 1;
1153 		watchdog_available = 1;
1154 	}
1155 }
1156 
1157 static void
1158 have_auxio(dnode_t node)
1159 {
1160 	size_t size, n;
1161 	uint32_t addr[5];
1162 
1163 	/*
1164 	 * Get the size of the auzio's address property.
1165 	 * On some platforms, the address property contains one
1166 	 * entry and on others it contains five entries.
1167 	 * In all cases, the first entries are compatible.
1168 	 *
1169 	 * This routine gets the address property for the auxio
1170 	 * node and stores the first entry in v_auxio_addr which
1171 	 * is used by the routine set_auxioreg in sun4u/ml/locore.s.
1172 	 */
1173 	if ((size = GETPROPLEN(node, OBP_ADDRESS)) == -1)
1174 		cmn_err(CE_PANIC, "no auxio address property");
1175 
1176 	switch (n = (size / sizeof (addr[0]))) {
1177 	case 1:
1178 		break;
1179 	case 5:
1180 		break;
1181 	default:
1182 		cmn_err(CE_PANIC, "auxio addr has %lu entries?", n);
1183 	}
1184 
1185 	if (GETPROP(node, OBP_ADDRESS, (caddr_t)addr) == -1)
1186 		cmn_err(CE_PANIC, "auxio addr");
1187 
1188 	v_auxio_addr = (caddr_t)(uintptr_t)(addr[0]); /* make into pointer */
1189 }
1190 
1191 static void
1192 have_tod(dnode_t node)
1193 {
1194 	static char tod_name[MAXSYSNAME];
1195 
1196 	if (GETPROP(node, OBP_NAME, (caddr_t)tod_name) == -1)
1197 		cmn_err(CE_PANIC, "tod name");
1198 	/*
1199 	 * This is a node with "device_type" property value of "tod".
1200 	 * Name of the tod module is the name from the node.
1201 	 */
1202 	tod_module_name = tod_name;
1203 }
1204