xref: /illumos-gate/usr/src/uts/sun4u/io/gptwo_cpu.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * CPU functions to the Safari Configurator  (gptwo_cpu)
28  */
29 
30 #include <sys/types.h>
31 #include <sys/cred.h>
32 #include <sys/mman.h>
33 #include <sys/kmem.h>
34 #include <sys/conf.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/sunndi.h>
38 #include <sys/modctl.h>
39 #include <sys/stat.h>
40 #include <sys/param.h>
41 #include <sys/autoconf.h>
42 #include <sys/ksynch.h>
43 #include <sys/promif.h>
44 #include <sys/ndi_impldefs.h>
45 #include <sys/ddi_impldefs.h>
46 #include <sys/machsystm.h>
47 #include <sys/gp2cfg.h>
48 #include <sys/gptwo_cpu.h>
49 #include <sys/cheetahregs.h>
50 
51 #ifdef DEBUG
52 int gptwo_cpu_debug = 0;
53 
54 static void debug(char *, uintptr_t, uintptr_t,
55     uintptr_t, uintptr_t, uintptr_t);
56 
57 #define	GPTWO_DEBUG0(level, flag, s) if (gptwo_cpu_debug >= level) \
58     cmn_err(flag, s)
59 #define	GPTWO_DEBUG1(level, flag, fmt, a1) if (gptwo_cpu_debug >= level) \
60     debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
61 #define	GPTWO_DEBUG2(level, flag, fmt, a1, a2) if (gptwo_cpu_debug >= level) \
62     debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
63 #define	GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3) \
64     if (gptwo_cpu_debug >= level) \
65     debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
66 #else
67 #define	GPTWO_DEBUG0(level, flag, s)
68 #define	GPTWO_DEBUG1(level, flag, fmt, a1)
69 #define	GPTWO_DEBUG2(level, flag, fmt, a1, a2)
70 #define	GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3)
71 #endif
72 
73 /*
74  * Devinfo branch create arg
75  */
76 struct bca {
77 	spcd_t *pcd;
78 	uint_t portid;
79 	uint_t cpuid;
80 	uint_t coreid;
81 	uint_t impl;
82 	dev_info_t *new_child;
83 };
84 
85 static dev_info_t *gptwocfg_create_cpu_node(dev_info_t *, spcd_t *,
86     uint_t, uint_t, uint_t, uint_t);
87 static dev_info_t *gptwocfg_create_mc_node(dev_info_t *, spcd_t *, uint_t);
88 static dev_info_t *gptwocfg_create_cmp_node(dev_info_t *, spcd_t *, uint_t);
89 static int gptwocfg_create_core_node(dev_info_t *, spcd_t *, uint_t, uint_t);
90 static int set_mc_props(dev_info_t *new_child, void *arg, uint_t flags);
91 static int set_cmp_props(dev_info_t *new_child, void *arg, uint_t flags);
92 static int set_cpu_props(dev_info_t *new_child, void *arg, uint_t flags);
93 static int set_cpu_common_props(dev_info_t *new_child, struct bca *bcp);
94 static int set_cpu_us3_props(dev_info_t *new_child, struct bca *bcp);
95 static int set_cpu_us4_props(dev_info_t *new_child, struct bca *bcp);
96 static void get_new_child(dev_info_t *rdip, void *arg, uint_t flags);
97 
98 
99 /*
100  * Module linkage information for the kernel.
101  */
102 
103 extern struct mod_ops mod_miscops;
104 
105 static struct modlmisc modlmisc = {
106 	&mod_miscops, /* Type of module */
107 	"gptwo->cpu configurator",
108 };
109 
110 static struct modlinkage modlinkage = {
111 	MODREV_1, (void *)&modlmisc, NULL
112 };
113 
114 int
115 _init(void)
116 {
117 	int err = 0;
118 
119 	/* register device with the configurator */
120 	gptwocfg_register_ops(SAFPTYPE_CPU, gptwocfg_configure_cpu, NULL);
121 
122 	if ((err = mod_install(&modlinkage)) != 0) {
123 		GPTWO_DEBUG1(1, CE_WARN, "gptwo_cpu (CPU/MC Functions) "
124 		"failed to load, error=%d\n", err);
125 		gptwocfg_unregister_ops(SAFPTYPE_CPU);
126 	} else {
127 		GPTWO_DEBUG0(1, CE_WARN, "gptwo_cpu (CPU/MC Functions) "
128 		"has been loaded.\n");
129 	}
130 	return (err);
131 }
132 
133 int
134 _fini(void)
135 {
136 	/* cleanup/freeup structs with configurator */
137 	gptwocfg_unregister_ops(SAFPTYPE_CPU);
138 	return (mod_remove(&modlinkage));
139 }
140 
141 int
142 _info(struct modinfo *modinfop)
143 {
144 	return (mod_info(&modlinkage, modinfop));
145 }
146 
147 gptwo_new_nodes_t *
148 gptwocfg_configure_cpu(dev_info_t *ap, spcd_t *pcd, uint_t portid)
149 {
150 	dev_info_t *cpu_node[AGENTS_PER_PORT], *mc_node[AGENTS_PER_PORT];
151 	dev_info_t *cmp_node = NULL;
152 	gptwo_new_nodes_t *new_nodes;
153 	int nodes = 0;
154 	int i, j = 0;
155 	uint_t implementation;
156 
157 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_configure_cpu: portid=%x pcd=%lx\n",
158 	    portid, pcd);
159 
160 	for (i = 0; i < AGENTS_PER_PORT; i++) {
161 		cpu_node[i] = NULL;
162 		mc_node[i] = NULL;
163 	}
164 
165 	implementation = (pcd->spcd_ver_reg >> 32) & 0x000000000000ffff;
166 
167 	switch (implementation) {
168 	case CHEETAH_IMPL:
169 	case CHEETAH_PLUS_IMPL:
170 	case JAGUAR_IMPL:
171 	case PANTHER_IMPL:
172 		break;
173 	default:
174 		cmn_err(CE_WARN, "Unsupported cpu implementation=0x%x : "
175 		    "skipping configure of portid=0x%x", implementation,
176 		    portid);
177 		ASSERT(0);
178 		return (NULL);
179 	}
180 
181 	if (CPU_IMPL_IS_CMP(implementation)) {
182 		if (cmp_node = gptwocfg_create_cmp_node(ap, pcd, portid))
183 			nodes++;
184 		else
185 			return (NULL);
186 	}
187 
188 	for (i = 0; i < AGENTS_PER_PORT; i++) {
189 		if (pcd->spcd_agent[i] != SPCD_RSV_PASS)
190 			continue;
191 
192 		if (cpu_node[i] = gptwocfg_create_cpu_node(cmp_node ?
193 		    cmp_node : ap, pcd, portid, pcd->spcd_cpuid[i], i,
194 		    implementation)) {
195 			/*
196 			 * If the CPU is a CMP, the entire branch is
197 			 * manipulated using just the top node. Thus,
198 			 * the dips of the individual cores do not need
199 			 * to be held or stored in the new node list.
200 			 */
201 			if (cmp_node) {
202 				e_ddi_branch_rele(cpu_node[i]);
203 			} else {
204 				nodes++;
205 			}
206 		}
207 	}
208 
209 	/* current implementations have 1 MC node per Safari port */
210 	if (pcd->spcd_prsv == SPCD_RSV_PASS &&
211 	    (mc_node[0] = gptwocfg_create_mc_node(ap, pcd, portid)))
212 		nodes++;
213 
214 	new_nodes = gptwocfg_allocate_node_list(nodes);
215 
216 	j = 0;
217 	for (i = 0; i < AGENTS_PER_PORT; i++) {
218 		if ((cpu_node[i] != NULL) && (!CPU_IMPL_IS_CMP(implementation)))
219 			new_nodes->gptwo_nodes[j++] = cpu_node[i];
220 		if (mc_node[i] != NULL)
221 			new_nodes->gptwo_nodes[j++] = mc_node[i];
222 	}
223 
224 	if (cmp_node)
225 		new_nodes->gptwo_nodes[j++] = cmp_node;
226 
227 	return (new_nodes);
228 }
229 
230 
231 static dev_info_t *
232 gptwocfg_create_cmp_node(dev_info_t *ap, spcd_t *pcd, uint_t portid)
233 {
234 	struct bca arg;
235 	devi_branch_t b;
236 
237 	arg.pcd = pcd;
238 	arg.portid = portid;
239 	arg.cpuid = 0;
240 	arg.coreid = 0;
241 	arg.new_child = NULL;
242 
243 	b.arg = &arg;
244 	b.type = DEVI_BRANCH_SID;
245 	b.create.sid_branch_create = set_cmp_props;
246 	b.devi_branch_callback = get_new_child;
247 
248 	if (e_ddi_branch_create(ap, &b, NULL, 0))
249 		return (NULL);
250 
251 	return (arg.new_child);
252 }
253 
254 /*ARGSUSED*/
255 static int
256 set_cmp_props(dev_info_t *new_child, void *arg, uint_t flags)
257 {
258 	struct bca *bap = (struct bca *)arg;
259 	gptwo_regspec_t	reg;
260 	spcd_t *pcd;
261 	uint_t portid;
262 
263 	pcd = bap->pcd;
264 	portid = bap->portid;
265 
266 	GPTWO_DEBUG2(1, CE_CONT, "set_cmp_props: portid=%x pcd=%lx\n",
267 	    portid, pcd);
268 
269 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
270 	    "name", "cmp") != DDI_SUCCESS) {
271 		GPTWO_DEBUG0(1, CE_CONT, "set_cmp_props: failed to "
272 		    "create name property\n");
273 		return (DDI_WALK_ERROR);
274 	}
275 
276 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
277 	    "portid", portid) != DDI_SUCCESS) {
278 		GPTWO_DEBUG0(1, CE_CONT, "set_cmp_props: failed to "
279 		    "create portid property\n");
280 		return (DDI_WALK_ERROR);
281 	}
282 
283 	reg.gptwo_phys_hi = 0x400 | (portid >> 9);
284 	reg.gptwo_phys_low = (portid << 23);
285 	reg.gptwo_size_hi = 0;
286 	reg.gptwo_size_low = 0x10000;
287 
288 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
289 	    new_child, "reg", (int *)&reg,
290 	    sizeof (gptwo_regspec_t) / sizeof (int)) != DDI_SUCCESS) {
291 		GPTWO_DEBUG0(1, CE_CONT, "set_cmp_props: failed to "
292 		    "create reg property\n");
293 		return (DDI_WALK_ERROR);
294 	}
295 
296 	return (DDI_WALK_TERMINATE);
297 }
298 
299 static dev_info_t *
300 gptwocfg_create_cpu_node(dev_info_t *ap, spcd_t *pcd, uint_t portid,
301     uint_t cpuid, uint_t coreid, uint_t impl)
302 {
303 	struct bca arg;
304 	devi_branch_t b = {0};
305 
306 	arg.pcd = pcd;
307 	arg.portid = portid;
308 	arg.cpuid = cpuid;
309 	arg.coreid = coreid;
310 	arg.impl = impl;
311 	arg.new_child = NULL;
312 
313 	b.arg = &arg;
314 	b.type = DEVI_BRANCH_SID;
315 	b.create.sid_branch_create = set_cpu_props;
316 	b.devi_branch_callback = get_new_child;
317 
318 	if (e_ddi_branch_create(ap, &b, NULL, 0))
319 		return (NULL);
320 
321 	return (arg.new_child);
322 }
323 
324 /*ARGSUSED*/
325 static int
326 set_cpu_props(dev_info_t *new_child, void *arg, uint_t flags)
327 {
328 	struct bca *bcp = arg;
329 	uint_t impl = bcp->impl;
330 	int rc;
331 
332 	if (set_cpu_common_props(new_child, bcp) != DDI_WALK_CONTINUE)
333 		return (DDI_WALK_ERROR);
334 
335 	switch (impl) {
336 	case CHEETAH_IMPL:
337 	case CHEETAH_PLUS_IMPL:
338 		rc = set_cpu_us3_props(new_child, bcp);
339 		break;
340 	case JAGUAR_IMPL:
341 	case PANTHER_IMPL:
342 		rc = set_cpu_us4_props(new_child, bcp);
343 		break;
344 	default:
345 		ASSERT(0);
346 		return (DDI_WALK_ERROR);
347 	}
348 
349 	return (rc);
350 }
351 
352 /*
353  * Set properties common to cpu (non-CMP) and core (CMP) nodes.
354  *
355  *	cpuid
356  * 	device_type
357  *	manufacturer#
358  * 	implementation#
359  *	mask#
360  *	sparc-version
361  * 	clock-frequency
362  *	#dtlb-entries
363  *	#itlb-entries
364  */
365 static int
366 set_cpu_common_props(dev_info_t *new_child, struct bca *bcp)
367 {
368 	uint_t	cpuid, impl;
369 	spcd_t	*pcd;
370 	int	mask, manufacturer;
371 
372 	cpuid = bcp->cpuid;
373 	pcd = bcp->pcd;
374 	impl = bcp->impl;
375 
376 	mask = (pcd->spcd_ver_reg >> 24) & 0x00000000000000ff;
377 	manufacturer = (pcd->spcd_ver_reg >> 48) & 0x000000000000ffff;
378 
379 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
380 	    "cpuid", cpuid) != DDI_SUCCESS) {
381 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
382 		    "to create cpuid property\n");
383 		return (DDI_WALK_ERROR);
384 	}
385 
386 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
387 	    "device_type", "cpu") != DDI_SUCCESS) {
388 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
389 		    "to create device_type property\n");
390 		return (DDI_WALK_ERROR);
391 	}
392 
393 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child, "manufacturer#",
394 	    manufacturer) != DDI_SUCCESS) {
395 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
396 		    "to create manufacturer# property\n");
397 		return (DDI_WALK_ERROR);
398 	}
399 
400 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child, "implementation#",
401 	    impl) != DDI_SUCCESS) {
402 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
403 		    "to create implementation# property\n");
404 		return (DDI_WALK_ERROR);
405 	}
406 
407 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child, "mask#",
408 	    mask) != DDI_SUCCESS) {
409 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
410 		    "to create mask# property\n");
411 		return (DDI_WALK_ERROR);
412 	}
413 
414 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
415 	    "sparc-version", 9) != DDI_SUCCESS) {
416 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
417 		    "to create sparc-version property\n");
418 		return (DDI_WALK_ERROR);
419 	}
420 
421 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
422 	    "clock-frequency", (pcd->spcd_afreq * 1000000)) != DDI_SUCCESS) {
423 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
424 		    "to create clock-frequency property\n");
425 		return (DDI_WALK_ERROR);
426 	}
427 
428 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
429 	    "#dtlb-entries", 0x10) != DDI_SUCCESS) {
430 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
431 		    "to create #dtlb-entries property\n");
432 		return (DDI_WALK_ERROR);
433 	}
434 
435 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
436 	    "#itlb-entries", 0x10) != DDI_SUCCESS) {
437 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
438 		    "to create #itlb-entries property\n");
439 		return (DDI_WALK_ERROR);
440 	}
441 
442 	return (DDI_WALK_CONTINUE);
443 }
444 
445 /*
446  * Set cpu node properties for Cheetah and Cheetah+.
447  *
448  *	name
449  * 	portid
450  * 	reg
451  * 	icache-size
452  * 	icache-line-size
453  *	icache-associativity
454  *	dcache-size
455  *	dcache-line-size
456  *	dcache-associativity
457  *	ecache-size
458  *	ecache-line-size
459  *	ecache-associativity
460  */
461 static int
462 set_cpu_us3_props(dev_info_t *new_child, struct bca *bcp)
463 {
464 	char *node_name;
465 	gptwo_regspec_t	reg;
466 	int ecache_size, ecache_line_size;
467 	int dimms, ecache_assoc;
468 	spcd_t *pcd;
469 	uint_t portid, impl;
470 
471 	pcd = bcp->pcd;
472 	portid = bcp->portid;
473 	impl = bcp->impl;
474 
475 	ASSERT(IS_CHEETAH(impl) || IS_CHEETAH_PLUS(impl));
476 
477 	switch (impl) {
478 	case CHEETAH_IMPL:
479 		ecache_assoc = CH_ECACHE_NWAY;
480 		node_name = "SUNW,UltraSPARC-III";
481 		break;
482 	case CHEETAH_PLUS_IMPL:
483 		/*
484 		 * Hard coding the ecache-associativity to 2 for Cheetah+.
485 		 * We probably should add this to the PCD.
486 		 */
487 		ecache_assoc = CHP_ECACHE_NWAY;
488 		node_name = "SUNW,UltraSPARC-III+";
489 		break;
490 	default:
491 		GPTWO_DEBUG1(1, CE_CONT, "set_cpu_us3_props: invalid "
492 		    "implementation=0x%x\n", impl);
493 		return (DDI_WALK_ERROR);
494 	}
495 
496 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
497 	    "name", node_name) != DDI_SUCCESS) {
498 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
499 		    "to create name property\n");
500 		return (DDI_WALK_ERROR);
501 	}
502 
503 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
504 	    "portid", portid) != DDI_SUCCESS) {
505 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
506 		    "to create portid property\n");
507 		return (DDI_WALK_ERROR);
508 	}
509 
510 	reg.gptwo_phys_hi = 0x400 | (portid >> 9);
511 	reg.gptwo_phys_low = (portid << 23);
512 	reg.gptwo_size_hi = 0;
513 	reg.gptwo_size_low = 0x10000;
514 
515 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
516 	    new_child, "reg", (int *)&reg,
517 	    sizeof (gptwo_regspec_t) / sizeof (int)) != DDI_SUCCESS) {
518 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
519 		    "to create reg property\n");
520 		return (DDI_WALK_ERROR);
521 	}
522 
523 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
524 	    "icache-size", CH_ICACHE_SIZE) != DDI_SUCCESS) {
525 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
526 		    "to create icache-size property\n");
527 		return (DDI_WALK_ERROR);
528 	}
529 
530 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
531 	    "icache-line-size", CH_ICACHE_LSIZE) != DDI_SUCCESS) {
532 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
533 		    "to create icache-line-size property\n");
534 		return (DDI_WALK_ERROR);
535 	}
536 
537 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
538 	    "icache-associativity", CH_ICACHE_NWAY) != DDI_SUCCESS) {
539 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
540 		    "to create icache-associativity property\n");
541 		return (DDI_WALK_ERROR);
542 	}
543 
544 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
545 	    "dcache-size", CH_DCACHE_SIZE) != DDI_SUCCESS) {
546 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
547 		    "to create dcache-size property\n");
548 		return (DDI_WALK_ERROR);
549 	}
550 
551 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
552 	    "dcache-line-size", CH_DCACHE_LSIZE) != DDI_SUCCESS) {
553 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
554 		    "to create dcache-line-size property\n");
555 		return (DDI_WALK_ERROR);
556 	}
557 
558 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
559 	    "dcache-associativity", CH_DCACHE_NWAY) != DDI_SUCCESS) {
560 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
561 		    "to create dcache-associativity property\n");
562 		return (DDI_WALK_ERROR);
563 	}
564 
565 	/*
566 	 * Get the External Cache Size from the Common PCD.
567 	 */
568 	ecache_size = pcd->spcd_cache * 0x100000;
569 
570 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
571 	    "ecache-size", ecache_size) != DDI_SUCCESS) {
572 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
573 		    "to create ecache-line-size property\n");
574 		return (DDI_WALK_ERROR);
575 	}
576 
577 	switch (ecache_size) {
578 	case CH_ECACHE_1M_SIZE:
579 		ecache_line_size = 64;
580 		break;
581 	case CH_ECACHE_4M_SIZE:
582 		ecache_line_size = 256;
583 		break;
584 	case CH_ECACHE_8M_SIZE:
585 		ecache_line_size = 512;
586 		break;
587 	default:
588 		GPTWO_DEBUG1(1, CE_CONT, "set_cpu_us3_props: invalid "
589 		    "ecache-size 0x%x\b", ecache_size);
590 		return (DDI_WALK_ERROR);
591 	}
592 
593 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
594 	    "ecache-line-size", ecache_line_size) != DDI_SUCCESS) {
595 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
596 		    "to create ecache-line-size property\n");
597 		return (DDI_WALK_ERROR);
598 	}
599 
600 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
601 	    "ecache-associativity", ecache_assoc) != DDI_SUCCESS) {
602 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
603 		    "to create ecache-associativity property\n");
604 		return (DDI_WALK_ERROR);
605 	}
606 
607 	/*
608 	 * Create the ecache-dimm-label property.
609 	 */
610 	dimms = 0;
611 
612 	while ((pcd->sprd_ecache_dimm_label[dimms] != NULL) &&
613 	    (dimms < MAX_DIMMS_PER_PORT))
614 		dimms++;
615 
616 	if (dimms) {
617 		(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, new_child,
618 		    "ecache-dimm-label", (char **)pcd->sprd_ecache_dimm_label,
619 		    dimms);
620 	}
621 
622 	return (DDI_WALK_TERMINATE);
623 }
624 
625 /*
626  * Set cmp core node properties for Jaguar and Panther.
627  *
628  * 	name
629  * 	compatible
630  * 	reg
631  *	l1-icache-size
632  *	l1-icache-line-size
633  *	l1-icache-associativity
634  *	l1-dcache-size
635  *	l1-dcache-line-size
636  *	l1-dcache-associativity
637  *	l2-cache-size
638  *	l2-cache-line-size
639  *	l2-cache-associativity
640  *	l2-cache-sharing
641  *	l3-cache-size
642  *	l3-cache-line-size
643  *	l3-cache-associativity
644  *	l3-cache-sharing
645  */
646 static int
647 set_cpu_us4_props(dev_info_t *new_child, struct bca *bcp)
648 {
649 	uint_t l1_icache_size, l1_icache_line_size;
650 	uint_t l2_cache_size, l2_cache_line_size, l2_cache_assoc;
651 	uint_t l2_cache_share;
652 	uint_t pcd_cache_size;
653 	uint_t coreid, impl;
654 	spcd_t *pcd;
655 	char *compatible;
656 	int dimms;
657 	int i;
658 
659 	pcd = bcp->pcd;
660 	coreid = bcp->coreid;
661 	impl = bcp->impl;
662 
663 	ASSERT(IS_JAGUAR(impl) || IS_PANTHER(impl));
664 
665 	/*
666 	 * Get the External Cache Size from the Common PCD.
667 	 */
668 	pcd_cache_size = pcd->spcd_cache * 0x100000;
669 
670 	switch (impl) {
671 	case JAGUAR_IMPL:
672 		compatible = "SUNW,UltraSPARC-IV";
673 		l1_icache_size = CH_ICACHE_SIZE;
674 		l1_icache_line_size = CH_ICACHE_LSIZE;
675 		l2_cache_assoc = CHP_ECACHE_NWAY;
676 
677 		/*
678 		 * Jaguar has no logical sharing of L2 cache, so the sharing
679 		 * bit-map will represent this core only.
680 		 */
681 		l2_cache_share = coreid ? 0x2 : 0x1;
682 
683 		/*
684 		 * Jaguar has a split ecache, so the total ecache must be
685 		 * divided in half to get the ecache for the individual core.
686 		 */
687 		l2_cache_size = pcd_cache_size / 2;
688 
689 		switch (l2_cache_size) {
690 		case JG_ECACHE_4M_SIZE:
691 			l2_cache_line_size = 64;
692 			break;
693 		case JG_ECACHE_8M_SIZE:
694 			l2_cache_line_size = 128;
695 			break;
696 		default:
697 			GPTWO_DEBUG1(1, CE_CONT, "set_cpu_us4_props: "
698 			    "invalid l2_cache-size 0x%x\n", l2_cache_size);
699 			return (DDI_WALK_ERROR);
700 		}
701 		break;
702 	case PANTHER_IMPL:
703 		ASSERT(pcd_cache_size == PN_L3_SIZE);
704 		compatible = "SUNW,UltraSPARC-IV+";
705 		l1_icache_size = PN_ICACHE_SIZE;
706 		l1_icache_line_size = PN_ICACHE_LSIZE;
707 		l2_cache_size = PN_L2_SIZE;
708 		l2_cache_line_size = PN_L2_LINESIZE;
709 		l2_cache_assoc = PN_ECACHE_NWAY;
710 
711 		/*
712 		 * For Panther, the L2 and L3 caches are logically shared by
713 		 * all enabled cores, so the sharing bit-map will represent
714 		 * all enabled cores.  Panther split-mode is still considered
715 		 * shared.
716 		 *
717 		 * Check the PCD status to determine enabled cores.
718 		 */
719 		ASSERT(pcd->spcd_ptype == SAFPTYPE_CPU);
720 		l2_cache_share = 0;
721 		for (i = 0; i < AGENTS_PER_PORT; i++) {
722 			if (pcd->spcd_agent[i] == SPCD_RSV_PASS) {
723 				l2_cache_share |= (1 << i);
724 			}
725 		}
726 
727 		break;
728 	default:
729 		GPTWO_DEBUG1(1, CE_CONT, "set_cpu_us4_props: invalid "
730 		    "implementation=0x%x\n", impl);
731 		return (DDI_WALK_ERROR);
732 	}
733 
734 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
735 	    "name", "cpu") != DDI_SUCCESS) {
736 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
737 		    "to create name property\n");
738 		return (DDI_WALK_ERROR);
739 	}
740 
741 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
742 	    "compatible", compatible) != DDI_SUCCESS) {
743 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
744 		    "to create compatible property\n");
745 		return (DDI_WALK_ERROR);
746 	}
747 
748 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
749 	    "reg", coreid) != DDI_SUCCESS) {
750 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
751 		    "to create reg property\n");
752 		return (DDI_WALK_ERROR);
753 	}
754 
755 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
756 	    "l1-icache-size", l1_icache_size) != DDI_SUCCESS) {
757 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
758 		    "to create l1-icache-size property\n");
759 		return (DDI_WALK_ERROR);
760 	}
761 
762 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
763 	    "l1-icache-line-size", l1_icache_line_size) != DDI_SUCCESS) {
764 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
765 		    "to create icache-line-size property\n");
766 		return (DDI_WALK_ERROR);
767 	}
768 
769 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
770 	    "l1-icache-associativity", CH_ICACHE_NWAY) != DDI_SUCCESS) {
771 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
772 		    "to create l1-icache-associativity property\n");
773 		return (DDI_WALK_ERROR);
774 	}
775 
776 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
777 	    "l1-dcache-size", CH_DCACHE_SIZE) != DDI_SUCCESS) {
778 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
779 		    "to create l1-dcache-size property\n");
780 		return (DDI_WALK_ERROR);
781 	}
782 
783 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
784 	    "l1-dcache-line-size", CH_DCACHE_LSIZE) != DDI_SUCCESS) {
785 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
786 		    "to create dcache-line-size property\n");
787 		return (DDI_WALK_ERROR);
788 	}
789 
790 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
791 	    "l1-dcache-associativity", CH_DCACHE_NWAY) != DDI_SUCCESS) {
792 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
793 		    "to create l1-dcache-associativity property\n");
794 		return (DDI_WALK_ERROR);
795 	}
796 
797 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
798 	    "l2-cache-size", l2_cache_size) != DDI_SUCCESS) {
799 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
800 		    "to create l2-cache-size property\n");
801 		return (DDI_WALK_ERROR);
802 	}
803 
804 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
805 	    "l2-cache-line-size", l2_cache_line_size) != DDI_SUCCESS) {
806 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
807 		    "to create l2_cache-line-size property\n");
808 		return (DDI_WALK_ERROR);
809 	}
810 
811 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
812 	    "l2-cache-associativity", l2_cache_assoc) != DDI_SUCCESS) {
813 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
814 		    "to create l2-cache-associativity property\n");
815 		return (DDI_WALK_ERROR);
816 	}
817 
818 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
819 	    "l2-cache-sharing", l2_cache_share) != DDI_SUCCESS) {
820 		GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
821 		    "to create l2-cache-sharing property\n");
822 		return (DDI_WALK_ERROR);
823 	}
824 
825 	/*
826 	 * Create the ecache-dimm-label property.
827 	 */
828 	dimms = 0;
829 
830 	while ((pcd->sprd_ecache_dimm_label[dimms] != NULL) &&
831 	    (dimms < MAX_DIMMS_PER_PORT))
832 		dimms++;
833 
834 	if (dimms) {
835 		(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, new_child,
836 		    "ecache-dimm-label", (char **)pcd->sprd_ecache_dimm_label,
837 		    dimms);
838 	}
839 
840 	if (IS_PANTHER(impl)) {
841 		int l3_cache_share = l2_cache_share;
842 
843 		if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
844 		    "l3-cache-size", PN_L3_SIZE) != DDI_SUCCESS) {
845 			GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: "
846 			    "failed to create l3-cache-size property\n");
847 			return (DDI_WALK_ERROR);
848 		}
849 
850 		if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
851 		    "l3-cache-line-size", PN_L3_LINESIZE) != DDI_SUCCESS) {
852 			GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: "
853 			    "failed to create l3-cache-line-size property\n");
854 			return (DDI_WALK_ERROR);
855 		}
856 
857 		if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
858 		    "l3-cache-associativity", PN_ECACHE_NWAY) != DDI_SUCCESS) {
859 			GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: "
860 			    "failed to create l3-cache-associativity "
861 			    "property\n");
862 			return (DDI_WALK_ERROR);
863 		}
864 
865 		if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
866 		    "l3-cache-sharing", l3_cache_share) != DDI_SUCCESS) {
867 			GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: "
868 			    "failed to create l3-cache-sharing property\n");
869 			return (DDI_WALK_ERROR);
870 		}
871 	}
872 
873 	return (DDI_WALK_TERMINATE);
874 }
875 
876 static dev_info_t *
877 gptwocfg_create_mc_node(dev_info_t *ap, spcd_t *pcd, uint_t portid)
878 {
879 	struct bca arg;
880 	devi_branch_t b = {0};
881 
882 	arg.pcd = pcd;
883 	arg.portid = portid;
884 	arg.cpuid = portid;
885 	arg.new_child = NULL;
886 
887 	b.arg = &arg;
888 	b.type = DEVI_BRANCH_SID;
889 	b.create.sid_branch_create = set_mc_props;
890 	b.devi_branch_callback = get_new_child;
891 
892 	if (e_ddi_branch_create(ap, &b, NULL, 0))
893 		return (NULL);
894 
895 	return (arg.new_child);
896 }
897 
898 /*ARGSUSED*/
899 static int
900 set_mc_props(dev_info_t *new_child, void *arg, uint_t flags)
901 {
902 	struct bca *bcp = arg;
903 	gptwo_regspec_t	reg;
904 	int banks, dimms;
905 	spcd_t *pcd = bcp->pcd;
906 	uint_t portid = bcp->portid;
907 	uint_t cpuid = bcp->cpuid;
908 
909 	GPTWO_DEBUG3(1, CE_CONT, "set_mc_props: ap=0x%lx portid=0x%x "
910 	    "cpuid=0x%x\n", ddi_get_parent(new_child), portid, cpuid);
911 
912 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
913 	    "name", "memory-controller") != DDI_SUCCESS) {
914 		GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
915 		    "to create name property\n");
916 		return (DDI_WALK_ERROR);
917 	}
918 
919 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
920 	    "compatible", "SUNW,UltraSPARC-III,mc") != DDI_SUCCESS) {
921 		GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
922 		    "to create compatible property\n");
923 		return (DDI_WALK_ERROR);
924 	}
925 
926 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
927 	    "device_type", "memory-controller") != DDI_SUCCESS) {
928 		GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
929 		    "to create device_type property\n");
930 		return (DDI_WALK_ERROR);
931 	}
932 
933 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
934 	    "portid", portid) != DDI_SUCCESS) {
935 		GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
936 		    "to create portid property\n");
937 		return (DDI_WALK_ERROR);
938 	}
939 
940 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
941 	    "cpuid", cpuid) != DDI_SUCCESS) {
942 		GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
943 		    "to create cpuid property\n");
944 		return (DDI_WALK_ERROR);
945 	}
946 
947 	reg.gptwo_phys_hi = 0x400 | (portid >> 9);
948 	reg.gptwo_phys_low = (portid << 23) | 0x400000;
949 	reg.gptwo_size_hi = 0;
950 	reg.gptwo_size_low = 0x48;
951 
952 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
953 	    new_child, "reg", (int *)&reg,
954 	    sizeof (gptwo_regspec_t) / sizeof (int)) != DDI_SUCCESS) {
955 		GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
956 		    "to create reg property\n");
957 		return (DDI_WALK_ERROR);
958 	}
959 
960 	if (pcd->memory_layout) {
961 		if (ndi_prop_update_byte_array(DDI_DEV_T_NONE,
962 		    new_child, "memory-layout", (uchar_t *)pcd->memory_layout,
963 		    pcd->memory_layout_size) != DDI_SUCCESS) {
964 
965 			GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
966 			    "to create memory-layout property\n");
967 
968 			return (DDI_WALK_ERROR);
969 		}
970 	}
971 
972 	/*
973 	 * Create the bank-status property.
974 	 */
975 	banks = 0;
976 
977 	while ((pcd->sprd_bank_rsv[banks] != NULL) &&
978 	    (banks < MAX_BANKS_PER_PORT))
979 		banks++;
980 
981 	if (banks) {
982 		(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, new_child,
983 		    "bank-status", (char **)pcd->sprd_bank_rsv, banks);
984 	}
985 
986 	/*
987 	 * Create the dimm-status property.
988 	 */
989 	dimms = 0;
990 
991 	while ((pcd->sprd_dimm[dimms] != NULL) &&
992 	    (dimms < MAX_DIMMS_PER_PORT))
993 		dimms++;
994 
995 	if (dimms) {
996 		(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, new_child,
997 		    "dimm-status", (char **)pcd->sprd_dimm, dimms);
998 	}
999 
1000 
1001 	return (DDI_WALK_TERMINATE);
1002 }
1003 
1004 /*ARGSUSED*/
1005 static void
1006 get_new_child(dev_info_t *rdip, void *arg, uint_t flags)
1007 {
1008 	struct bca *bcp = arg;
1009 
1010 	bcp->new_child = rdip;
1011 
1012 }
1013 
1014 #ifdef DEBUG
1015 static void
1016 debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
1017 	uintptr_t a4, uintptr_t a5)
1018 {
1019 	cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
1020 }
1021 #endif
1022