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
52int gptwo_cpu_debug = 0;
53
54static 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 */
76struct 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
85static dev_info_t *gptwocfg_create_cpu_node(dev_info_t *, spcd_t *,
86    uint_t, uint_t, uint_t, uint_t);
87static dev_info_t *gptwocfg_create_mc_node(dev_info_t *, spcd_t *, uint_t);
88static dev_info_t *gptwocfg_create_cmp_node(dev_info_t *, spcd_t *, uint_t);
89static int gptwocfg_create_core_node(dev_info_t *, spcd_t *, uint_t, uint_t);
90static int set_mc_props(dev_info_t *new_child, void *arg, uint_t flags);
91static int set_cmp_props(dev_info_t *new_child, void *arg, uint_t flags);
92static int set_cpu_props(dev_info_t *new_child, void *arg, uint_t flags);
93static int set_cpu_common_props(dev_info_t *new_child, struct bca *bcp);
94static int set_cpu_us3_props(dev_info_t *new_child, struct bca *bcp);
95static int set_cpu_us4_props(dev_info_t *new_child, struct bca *bcp);
96static 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
103extern struct mod_ops mod_miscops;
104
105static struct modlmisc modlmisc = {
106	&mod_miscops, /* Type of module */
107	"gptwo->cpu configurator",
108};
109
110static struct modlinkage modlinkage = {
111	MODREV_1, (void *)&modlmisc, NULL
112};
113
114int
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
133int
134_fini(void)
135{
136	/* cleanup/freeup structs with configurator */
137	gptwocfg_unregister_ops(SAFPTYPE_CPU);
138	return (mod_remove(&modlinkage));
139}
140
141int
142_info(struct modinfo *modinfop)
143{
144	return (mod_info(&modlinkage, modinfop));
145}
146
147gptwo_new_nodes_t *
148gptwocfg_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
231static dev_info_t *
232gptwocfg_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*/
255static int
256set_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
299static dev_info_t *
300gptwocfg_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*/
325static int
326set_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 */
365static int
366set_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 */
461static int
462set_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 */
646static int
647set_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
876static dev_info_t *
877gptwocfg_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*/
899static int
900set_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*/
1005static void
1006get_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
1015static void
1016debug(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