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