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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <limits.h>
34 #include <alloca.h>
35 #include <kstat.h>
36 #include <errno.h>
37 #include <libnvpair.h>
38 #include <sys/types.h>
39 #include <sys/bitmap.h>
40 #include <sys/processor.h>
41 #include <sys/param.h>
42 #include <sys/fm/protocol.h>
43 #include <sys/systeminfo.h>
44 #include <sys/mc.h>
45 #include <sys/mc_amd.h>
46 #include <sys/mc_intel.h>
47 #include <fm/topo_mod.h>
48 
49 #include "chip.h"
50 
51 #define	MAX_DIMMNUM	7
52 #define	MAX_CSNUM	7
53 
54 /*
55  * Enumerates the processing chips, or sockets, (as distinct from cores) in a
56  * system.  For each chip found, the necessary nodes (one or more cores, and
57  * possibly a memory controller) are constructed underneath.
58  */
59 
60 static int chip_enum(topo_mod_t *, tnode_t *, const char *,
61     topo_instance_t, topo_instance_t, void *, void *);
62 
63 static const topo_modops_t chip_ops =
64 	{ chip_enum, NULL};
65 static const topo_modinfo_t chip_info =
66 	{ CHIP_NODE_NAME, FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops };
67 
68 static const topo_pgroup_info_t chip_pgroup =
69 	{ PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
70 static const topo_pgroup_info_t cpu_pgroup =
71 	{ PGNAME(CPU), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
72 static const topo_pgroup_info_t cpu_core_pgroup =
73 	{ PGNAME(CPU_CORE), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
74 static const topo_pgroup_info_t cpu_strand_pgroup =
75 	{ PGNAME(CPU_STRAND), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE,
76 	    1 };
77 
78 static const topo_method_t chip_methods[] = {
79 	{ SIMPLE_CHIP_LBL, "Property method", 0,
80 	    TOPO_STABILITY_INTERNAL, simple_chip_label},
81 	{ G4_CHIP_LBL, "Property method", 0,
82 	    TOPO_STABILITY_INTERNAL, g4_chip_label},
83 	{ A4FPLUS_CHIP_LBL, "Property method", 0,
84 	    TOPO_STABILITY_INTERNAL, a4fplus_chip_label},
85 	{ NULL }
86 };
87 
88 int
89 _topo_init(topo_mod_t *mod)
90 {
91 	chip_t *chip;
92 
93 	if (getenv("TOPOCHIPDBG"))
94 		topo_mod_setdebug(mod);
95 	topo_mod_dprintf(mod, "initializing chip enumerator\n");
96 
97 	if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL)
98 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
99 
100 	if ((chip->chip_kc = kstat_open()) == NULL) {
101 		whinge(mod, NULL, "kstat_open failed: %s\n",
102 		    strerror(errno));
103 		topo_mod_free(mod, chip, sizeof (chip_t));
104 		return (topo_mod_seterrno(mod, errno));
105 	}
106 
107 	chip->chip_ncpustats = sysconf(_SC_CPUID_MAX);
108 	if ((chip->chip_cpustats = topo_mod_zalloc(mod, (
109 	    chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) {
110 		(void) kstat_close(chip->chip_kc);
111 		topo_mod_free(mod, chip, sizeof (chip_t));
112 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
113 	}
114 
115 	if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
116 		whinge(mod, NULL, "failed to register hc: "
117 		    "%s\n", topo_mod_errmsg(mod));
118 		topo_mod_free(mod, chip->chip_cpustats,
119 		    (chip->chip_ncpustats + 1) * sizeof (kstat_t *));
120 		(void) kstat_close(chip->chip_kc);
121 		topo_mod_free(mod, chip, sizeof (chip_t));
122 		return (-1); /* mod errno set */
123 	}
124 	topo_mod_setspecific(mod, (void *)chip);
125 
126 	return (0);
127 }
128 
129 void
130 _topo_fini(topo_mod_t *mod)
131 {
132 	chip_t *chip = topo_mod_getspecific(mod);
133 
134 	if (chip->chip_cpustats != NULL)
135 		topo_mod_free(mod, chip->chip_cpustats,
136 		    (chip->chip_ncpustats + 1) * sizeof (kstat_t *));
137 
138 	(void) kstat_close(chip->chip_kc);
139 	topo_mod_free(mod, chip, sizeof (chip_t));
140 
141 	topo_mod_unregister(mod);
142 }
143 
144 static int
145 cpu_strand_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid,
146     int coreid, chip_t *chip, int nstrand, nvlist_t *auth)
147 {
148 	kstat_named_t *k;
149 	nvlist_t *fmri, *asru;
150 	tnode_t *cnode;
151 	int err, nerr = 0;
152 	int cpuid, clogid, tcoreid, strandid;
153 
154 	if (topo_node_range_create(mod, pnode, name, 0,
155 	    nstrand) < 0)
156 		return (-1);
157 
158 	for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) {
159 		if (chip->chip_cpustats[cpuid] == NULL)
160 			continue;
161 
162 		/*
163 		 * The chip_id in the cpu_info kstat numbers the individual
164 		 * chips from 0 to #chips - 1.
165 		 */
166 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
167 		    "chip_id")) == NULL) {
168 			whinge(mod, &nerr,
169 			    "cpu_strand_create: chip_id lookup via "
170 			    "kstats failed\n");
171 			continue;
172 		}
173 
174 		if (k->value.l != chipid)
175 			continue;	/* not an error */
176 
177 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
178 		    "clog_id")) == NULL) {
179 			whinge(mod, &nerr,
180 			    "cpu_strand_create: clog_id lookup via "
181 			    "kstats failed\n");
182 			continue;
183 		}
184 		clogid = k->value.l;
185 		tcoreid = clogid / nstrand;
186 
187 		if (coreid != tcoreid)
188 			continue;
189 
190 		strandid = clogid % nstrand;
191 
192 		if (mkrsrc(mod, pnode, name, strandid, auth, &fmri) != 0) {
193 			whinge(mod, &nerr,
194 			    "cpu_strand_create: mkrsrc failed\n");
195 			continue;
196 		}
197 
198 		if ((cnode = topo_node_bind(mod, pnode, name, strandid, fmri))
199 		    == NULL) {
200 			whinge(mod, &nerr,
201 			    "cpu_strand_create: node bind failed\n");
202 			nvlist_free(fmri);
203 			continue;
204 		}
205 		nvlist_free(fmri);
206 
207 		if ((asru = cpu_fmri_create(mod, cpuid, NULL, 0)) != NULL) {
208 			(void) topo_node_asru_set(cnode, asru, 0, &err);
209 			nvlist_free(asru);
210 		} else {
211 			whinge(mod, &nerr, "cpu_strand_create: cpu_fmri_create "
212 			    "failed\n");
213 		}
214 		(void) topo_node_fru_set(cnode, NULL, 0, &err);
215 
216 		(void) topo_pgroup_create(cnode, &cpu_strand_pgroup, &err);
217 
218 		(void) topo_prop_set_uint32(cnode, PGNAME(CPU_STRAND), "cpuid",
219 		    TOPO_PROP_IMMUTABLE, cpuid, &err);
220 
221 		if (add_kstat_longprops(mod, cnode, chip->chip_cpustats[cpuid],
222 		    PGNAME(CPU_STRAND), NULL, CPU_CHIP_ID, CPU_CORE_ID,
223 		    CPU_CLOG_ID, CPU_PKG_CORE_ID, NULL) != 0)
224 			nerr++;		/* have whinged elsewhere */
225 	}
226 
227 	return (nerr == 0 ? 0 : -1);
228 }
229 
230 static int
231 cpu_core_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid,
232     chip_t *chip, int ncore, int ncpu, nvlist_t *auth)
233 {
234 	kstat_named_t *k;
235 	nvlist_t *fmri;
236 	tnode_t *cnode;
237 	int clogid, cpuid, coreid;
238 	int nstrand;
239 	int err, nerr = 0;
240 
241 	if (topo_node_range_create(mod, pnode, name, 0,
242 	    ncore) < 0)
243 		return (-1);
244 
245 	nstrand = ncpu / ncore;
246 	for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) {
247 		if (chip->chip_cpustats[cpuid] == NULL)
248 			continue;
249 
250 		/*
251 		 * The chip_id in the cpu_info kstat numbers the individual
252 		 * chips from 0 to #chips - 1.
253 		 */
254 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
255 		    "chip_id")) == NULL) {
256 			whinge(mod, &nerr,
257 			    "cpu_core_create: chip_id lookup via "
258 			    "kstats failed\n");
259 			continue;
260 		}
261 
262 		if (k->value.l != chipid)
263 			continue;	/* not an error */
264 
265 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
266 		    "clog_id")) == NULL) {
267 			whinge(mod, &nerr,
268 			    "cpu_core_create: clog_id lookup via "
269 			    "kstats failed\n");
270 			continue;
271 		}
272 		clogid = k->value.l;
273 		coreid = clogid / nstrand;
274 
275 		if (mkrsrc(mod, pnode, name, coreid, auth, &fmri) != 0) {
276 			whinge(mod, &nerr, "cpu_core_create: mkrsrc failed\n");
277 			continue;
278 		}
279 
280 		if ((cnode = topo_node_bind(mod, pnode, name, coreid, fmri))
281 		    == NULL) {
282 			whinge(mod, &nerr,
283 			    "cpu_core_create: node bind failed\n");
284 			nvlist_free(fmri);
285 			continue;
286 		}
287 		nvlist_free(fmri);
288 
289 		(void) topo_node_fru_set(cnode, NULL, 0, &err);
290 
291 		(void) topo_pgroup_create(cnode, &cpu_core_pgroup, &err);
292 
293 		if (cpu_strand_create(mod, cnode, CPU_STRAND_NODE_NAME, chipid,
294 		    coreid, chip, nstrand, auth) != 0)
295 			nerr++;		/* have whinged elsewhere */
296 	}
297 
298 	return (nerr == 0 ? 0 : -1);
299 }
300 
301 static int
302 cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid,
303     chip_t *chip, nvlist_t *auth)
304 {
305 	kstat_named_t *k;
306 	nvlist_t *fmri, *asru;
307 	tnode_t *cnode;
308 	int err, nerr = 0;
309 	int clogid, cpuid;
310 
311 	if (topo_node_range_create(mod, pnode, name, 0,
312 	    chip->chip_ncpustats) < 0)
313 		return (-1);
314 
315 	for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) {
316 		if (chip->chip_cpustats[cpuid] == NULL)
317 			continue;
318 
319 		/*
320 		 * The chip_id in the cpu_info kstat numbers the individual
321 		 * chips from 0 to #chips - 1.
322 		 */
323 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
324 		    "chip_id")) == NULL) {
325 			whinge(mod, &nerr, "cpu_create: chip_id lookup via "
326 			    "kstats failed\n");
327 			continue;
328 		}
329 
330 		if (k->value.l != chipid)
331 			continue;	/* not an error */
332 
333 		/*
334 		 * The clog_id in the cpu_info kstat numbers the virtual
335 		 * processors of a single chip;  these may be separate
336 		 * processor cores, or they may be hardware threads/strands
337 		 * of individual cores.
338 		 *
339 		 * The core_id in the cpu_info kstat tells us which cpus
340 		 * share the same core - i.e., are hardware strands of the
341 		 * same core.  The core ids do not reset to zero for each
342 		 * distinct chip - they number across all cores of all chips.
343 		 * This enumerator does not distinguish stranded
344 		 * cores so core_id is unused.
345 		 */
346 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
347 		    "clog_id")) == NULL) {
348 			whinge(mod, &nerr, "cpu_create: clog_id lookup via "
349 			    "kstats failed\n");
350 			continue;
351 		}
352 		clogid = k->value.l;
353 
354 		if (mkrsrc(mod, pnode, name, clogid, auth, &fmri) != 0) {
355 			whinge(mod, &nerr, "cpu_create: mkrsrc failed\n");
356 			continue;
357 		}
358 
359 		if ((cnode = topo_node_bind(mod, pnode, name, clogid, fmri))
360 		    == NULL) {
361 			whinge(mod, &nerr, "cpu_create: node bind failed\n");
362 			nvlist_free(fmri);
363 			continue;
364 		}
365 		nvlist_free(fmri);
366 
367 		if ((asru = cpu_fmri_create(mod, cpuid, NULL, 0)) != NULL) {
368 			(void) topo_node_asru_set(cnode, asru, 0, &err);
369 			nvlist_free(asru);
370 		} else {
371 			whinge(mod, &nerr, "cpu_create: cpu_fmri_create "
372 			    "failed\n");
373 		}
374 		(void) topo_node_fru_set(cnode, NULL, 0, &err);
375 
376 		(void) topo_pgroup_create(cnode, &cpu_pgroup, &err);
377 
378 		(void) topo_prop_set_uint32(cnode, PGNAME(CPU), "cpuid",
379 		    TOPO_PROP_IMMUTABLE, cpuid, &err);
380 
381 		if (add_kstat_longprops(mod, cnode, chip->chip_cpustats[cpuid],
382 		    PGNAME(CPU), NULL, CPU_CHIP_ID, CPU_CORE_ID, CPU_CLOG_ID,
383 		    CPU_PKG_CORE_ID, NULL) != 0)
384 			nerr++;		/* have whinged elsewhere */
385 	}
386 
387 	return (nerr == 0 ? 0 : -1);
388 }
389 
390 static int
391 chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
392     topo_instance_t min, topo_instance_t max, chip_t *chip, nvlist_t *auth,
393     int mc_offchip)
394 {
395 	int i, nerr = 0;
396 	kstat_t *ksp;
397 	ulong_t *chipmap;
398 	tnode_t *cnode;
399 	nvlist_t *fmri;
400 	int ncore, ncpu;
401 
402 	if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(max) *
403 	    sizeof (ulong_t))) == NULL)
404 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
405 
406 	/*
407 	 * Read in all cpu_info kstats, for all chip ids.  The ks_instance
408 	 * argument to kstat_lookup is the logical cpu_id - we will use this
409 	 * in cpu_create.
410 	 */
411 	for (i = 0; i <= chip->chip_ncpustats; i++) {
412 		if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) ==
413 		    NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0)
414 			continue;
415 
416 		chip->chip_cpustats[i] = ksp;
417 	}
418 
419 	for (i = 0; i <= chip->chip_ncpustats; i++) {
420 		const char *vendor;
421 		int32_t fms[3];
422 		kstat_named_t *k;
423 		int err, chipid;
424 
425 		if ((ksp = chip->chip_cpustats[i]) == NULL)
426 			continue;
427 
428 		if ((k = kstat_data_lookup(ksp, "chip_id")) == NULL) {
429 			whinge(mod, &nerr, "chip_create: chip_id lookup "
430 			    "via kstats failed\n");
431 			continue;
432 		}
433 
434 		chipid = k->value.l;
435 		if (BT_TEST(chipmap, chipid))
436 			continue;
437 
438 		if (chipid < min || chipid > max)
439 			continue;
440 
441 		if (mkrsrc(mod, pnode, name, chipid, auth, &fmri) != 0) {
442 			whinge(mod, &nerr, "chip_create: mkrsrc failed\n");
443 			continue;
444 		}
445 
446 		if ((cnode = topo_node_bind(mod, pnode, name, chipid, fmri))
447 		    == NULL) {
448 			nvlist_free(fmri);
449 			whinge(mod, &nerr, "chip_create: node bind "
450 			    "failed for chipid %d\n", chipid);
451 			continue;
452 		}
453 		BT_SET(chipmap, chipid);
454 
455 		if (topo_method_register(mod, cnode, chip_methods) < 0)
456 			whinge(mod, &nerr, "chip_create: "
457 			    "topo_method_register failed");
458 
459 		(void) topo_node_fru_set(cnode, fmri, 0, &err);
460 
461 		nvlist_free(fmri);
462 
463 		(void) topo_pgroup_create(cnode, &chip_pgroup, &err);
464 		if (add_kstat_strprop(mod, cnode, ksp, PGNAME(CHIP),
465 		    CHIP_VENDOR_ID, &vendor) != 0)
466 			nerr++;		/* have whinged elsewhere */
467 
468 		if (add_kstat_longprops(mod, cnode, ksp, PGNAME(CHIP),
469 		    fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL) != 0)
470 			nerr++;		/* have whinged elsewhere */
471 
472 		if ((k = kstat_data_lookup(ksp, "ncore_per_chip")) == NULL) {
473 			whinge(mod, &nerr, "chip_create: ncore_per_chip lookup "
474 			    "via kstats failed\n");
475 			ncore = 0;
476 			ncpu = 0;
477 		} else {
478 			ncore = k->value.l;
479 
480 			if ((k = kstat_data_lookup(ksp,
481 			    "ncpu_per_chip")) == NULL) {
482 				whinge(mod, &nerr,
483 				    "chip_create: ncpu_per_chip lookup "
484 				    "via kstats failed\n");
485 				ncore = 0;
486 				ncpu = 0;
487 			} else {
488 				ncpu = k->value.l;
489 			}
490 		}
491 
492 		if (ncore < ncpu) {
493 			if (cpu_core_create(mod, cnode, CPU_CORE_NODE_NAME,
494 			    chipid, chip, ncore, ncpu, auth) != 0)
495 				nerr++;	/* have whinged elsewhere */
496 		} else if (cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip,
497 		    auth) != 0)
498 			nerr++;		/* have whinged elsewhere */
499 
500 		/*
501 		 * Create memory-controller node under a chip for architectures
502 		 * that may have on-chip memory-controller(s).
503 		 */
504 		if (strcmp(vendor, "AuthenticAMD") == 0)
505 			amd_mc_create(mod, cnode, MCT_NODE_NAME, auth,
506 			    fms[0], fms[1], fms[2], &nerr);
507 		else if (!mc_offchip)
508 			onchip_mc_create(mod, cnode, MCT_NODE_NAME, auth);
509 	}
510 
511 	topo_mod_free(mod, chipmap, BT_BITOUL(max) * sizeof (ulong_t));
512 
513 	if (nerr == 0) {
514 		return (0);
515 	} else {
516 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
517 		return (-1);
518 	}
519 }
520 
521 /*ARGSUSED*/
522 static int
523 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
524     topo_instance_t min, topo_instance_t max, void *arg, void *notused)
525 {
526 	int rv = 0;
527 	chip_t *chip = (chip_t *)arg;
528 	nvlist_t *auth = NULL;
529 	int offchip_mc;
530 
531 	auth = topo_mod_auth(mod, pnode);
532 
533 	offchip_mc = mc_offchip_open();
534 	if (strcmp(name, CHIP_NODE_NAME) == 0)
535 		rv = chip_create(mod, pnode, name, min, max, chip, auth,
536 		    offchip_mc);
537 
538 	if (offchip_mc)
539 		(void) mc_offchip_create(mod, pnode, "memory-controller", auth);
540 
541 	nvlist_free(auth);
542 
543 	return (rv);
544 }
545