gptwo_cpu.c revision 4135:69588295f961
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
54int gptwo_cpu_debug = 0;
55
56static 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 */
78struct 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
87static dev_info_t *gptwocfg_create_cpu_node(dev_info_t *, spcd_t *,
88    uint_t, uint_t, uint_t, uint_t);
89static dev_info_t *gptwocfg_create_mc_node(dev_info_t *, spcd_t *, uint_t);
90static dev_info_t *gptwocfg_create_cmp_node(dev_info_t *, spcd_t *, uint_t);
91static int gptwocfg_create_core_node(dev_info_t *, spcd_t *, uint_t, uint_t);
92static int set_mc_props(dev_info_t *new_child, void *arg, uint_t flags);
93static int set_cmp_props(dev_info_t *new_child, void *arg, uint_t flags);
94static int set_cpu_props(dev_info_t *new_child, void *arg, uint_t flags);
95static int set_cpu_common_props(dev_info_t *new_child, struct bca *bcp);
96static int set_cpu_us3_props(dev_info_t *new_child, struct bca *bcp);
97static int set_cpu_us4_props(dev_info_t *new_child, struct bca *bcp);
98static 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
105extern struct mod_ops mod_miscops;
106
107static struct modlmisc modlmisc = {
108	&mod_miscops, /* Type of module */
109	"gptwo->cpu configurator %I%",
110};
111
112static struct modlinkage modlinkage = {
113	MODREV_1, (void *)&modlmisc, NULL
114};
115
116int
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
135int
136_fini(void)
137{
138	/* cleanup/freeup structs with configurator */
139	gptwocfg_unregister_ops(SAFPTYPE_CPU);
140	return (mod_remove(&modlinkage));
141}
142
143int
144_info(struct modinfo *modinfop)
145{
146	return (mod_info(&modlinkage, modinfop));
147}
148
149gptwo_new_nodes_t *
150gptwocfg_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
233static dev_info_t *
234gptwocfg_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*/
257static int
258set_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
301static dev_info_t *
302gptwocfg_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*/
327static int
328set_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 */
367static int
368set_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 */
463static int
464set_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 */
648static int
649set_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
878static dev_info_t *
879gptwocfg_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*/
901static int
902set_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*/
1007static void
1008get_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
1017static void
1018debug(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