xref: /illumos-gate/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c (revision 1a2d662a91cee3bf82f41cd47c7ae6f3825d9db2)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2019, Joyent, Inc.
26  * Copyright 2020 Oxide Computer Company
27  */
28 
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <limits.h>
37 #include <alloca.h>
38 #include <kstat.h>
39 #include <errno.h>
40 #include <libnvpair.h>
41 #include <sys/types.h>
42 #include <sys/bitmap.h>
43 #include <sys/processor.h>
44 #include <sys/param.h>
45 #include <sys/fm/protocol.h>
46 #include <sys/systeminfo.h>
47 #include <sys/mc.h>
48 #include <sys/mc_amd.h>
49 #include <sys/mc_intel.h>
50 #include <sys/devfm.h>
51 #include <fm/fmd_agent.h>
52 #include <fm/topo_mod.h>
53 
54 #include "chip.h"
55 
56 #define	MAX_DIMMNUM	7
57 #define	MAX_CSNUM	7
58 
59 /*
60  * Enumerates the processing chips, or sockets, (as distinct from cores) in a
61  * system.  For each chip found, the necessary nodes (one or more cores, and
62  * possibly a memory controller) are constructed underneath.
63  */
64 
65 static int chip_enum(topo_mod_t *, tnode_t *, const char *,
66     topo_instance_t, topo_instance_t, void *, void *);
67 
68 static const topo_modops_t chip_ops =
69 	{ chip_enum, NULL};
70 static const topo_modinfo_t chip_info =
71 	{ CHIP_NODE_NAME, FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops };
72 
73 static const topo_pgroup_info_t chip_pgroup =
74 	{ PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
75 
76 static const topo_pgroup_info_t core_pgroup =
77 	{ PGNAME(CORE), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
78 
79 static const topo_pgroup_info_t strand_pgroup =
80 	{ PGNAME(STRAND), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
81 
82 static const topo_method_t chip_methods[] = {
83 	{ SIMPLE_CHIP_LBL, "Property method", 0,
84 	    TOPO_STABILITY_INTERNAL, simple_chip_label},
85 	{ G4_CHIP_LBL, "Property method", 0,
86 	    TOPO_STABILITY_INTERNAL, g4_chip_label},
87 	{ A4FPLUS_CHIP_LBL, "Property method", 0,
88 	    TOPO_STABILITY_INTERNAL, a4fplus_chip_label},
89 	{ FSB2_CHIP_LBL, "Property method", 0,
90 	    TOPO_STABILITY_INTERNAL, fsb2_chip_label},
91 	{ TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC,
92 	    TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL,
93 	    chip_fmri_replaced },
94 	{ NULL }
95 };
96 
97 static const topo_method_t strands_retire_methods[] = {
98 	{ TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
99 	    TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
100 	    retire_strands },
101 	{ TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
102 	    TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
103 	    unretire_strands },
104 	{ TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
105 	    TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
106 	    service_state_strands },
107 	{ TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
108 	    TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
109 	    unusable_strands },
110 	{ NULL }
111 };
112 
113 int
114 _topo_init(topo_mod_t *mod)
115 {
116 	if (getenv("TOPOCHIPDBG"))
117 		topo_mod_setdebug(mod);
118 	topo_mod_dprintf(mod, "initializing chip enumerator\n");
119 
120 	if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
121 		whinge(mod, NULL, "failed to register hc: "
122 		    "%s\n", topo_mod_errmsg(mod));
123 		return (-1); /* mod errno set */
124 	}
125 
126 	return (0);
127 }
128 
129 void
130 _topo_fini(topo_mod_t *mod)
131 {
132 	topo_mod_unregister(mod);
133 }
134 
135 boolean_t
136 is_xpv(void)
137 {
138 	static int r = -1;
139 	char platform[MAXNAMELEN];
140 
141 	if (r != -1)
142 		return (r == 0);
143 
144 	(void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
145 	r = strcmp(platform, "i86xpv");
146 	return (r == 0);
147 }
148 
149 static tnode_t *
150 create_node(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, char *name,
151     topo_instance_t inst, nvlist_t *cpu, uint16_t smbios_id)
152 {
153 	nvlist_t *fmri;
154 	tnode_t *cnode;
155 
156 	if (mkrsrc(mod, pnode, name, inst, auth, &fmri) != 0) {
157 		whinge(mod, NULL, "create_node: mkrsrc failed\n");
158 		return (NULL);
159 	}
160 
161 	if (FM_AWARE_SMBIOS(mod)) {
162 		id_t phys_cpu_smbid;
163 		int perr = 0;
164 		const char *serial = NULL;
165 		const char *part = NULL;
166 		const char *rev = NULL;
167 
168 		phys_cpu_smbid = smbios_id;
169 		serial = chip_serial_smbios_get(mod, phys_cpu_smbid);
170 		part = chip_part_smbios_get(mod, phys_cpu_smbid);
171 		rev = chip_rev_smbios_get(mod, phys_cpu_smbid);
172 
173 		perr += nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID,
174 		    serial);
175 		perr += nvlist_add_string(fmri, FM_FMRI_HC_PART,
176 		    part);
177 		perr += nvlist_add_string(fmri, FM_FMRI_HC_REVISION,
178 		    rev);
179 
180 		if (perr != 0)
181 			whinge(mod, NULL,
182 			    "create_node: nvlist_add_string failed\n");
183 
184 		topo_mod_strfree(mod, (char *)serial);
185 		topo_mod_strfree(mod, (char *)part);
186 		topo_mod_strfree(mod, (char *)rev);
187 	} else {
188 		char *serial = NULL;
189 
190 		if (nvlist_lookup_string(cpu, FM_PHYSCPU_INFO_CHIP_IDENTSTR,
191 		    &serial) == 0) {
192 			if (nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID,
193 			    serial) != 0) {
194 				whinge(mod, NULL,
195 				    "create_node: nvlist_add_string failed\n");
196 			}
197 		}
198 	}
199 
200 	cnode = topo_node_bind(mod, pnode, name, inst, fmri);
201 
202 	nvlist_free(fmri);
203 	if (cnode == NULL) {
204 		whinge(mod, NULL, "create_node: node bind failed"
205 		    " for %s %d\n", name, (int)inst);
206 	}
207 
208 	return (cnode);
209 }
210 
211 static int
212 create_strand(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu,
213     nvlist_t *auth, uint16_t chip_smbiosid)
214 {
215 	tnode_t *strand;
216 	int32_t strandid, cpuid;
217 	int err, perr, nerr = 0;
218 	nvlist_t *fmri;
219 	char *serial = NULL;
220 	char *part = NULL;
221 	char *rev = NULL;
222 
223 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_STRAND_ID,
224 	    &strandid)) != 0) {
225 		whinge(mod, NULL, "create_strand: lookup strand_id failed: "
226 		    "%s\n", strerror(err));
227 		return (-1);
228 	}
229 
230 	if ((strand = topo_node_lookup(pnode, STRAND_NODE_NAME, strandid))
231 	    != NULL) {
232 		whinge(mod, NULL, "create_strand: duplicate tuple found\n");
233 		return (-1);
234 	}
235 
236 	if ((strand = create_node(mod, pnode, auth, STRAND_NODE_NAME,
237 	    strandid, cpu, chip_smbiosid)) == NULL)
238 		return (-1);
239 
240 	/*
241 	 * Inherit FRU from core node, in native use cpu scheme ASRU,
242 	 * in xpv, use hc scheme ASRU.
243 	 */
244 	(void) topo_node_fru_set(strand, NULL, 0, &perr);
245 	/*
246 	 * From the inherited FRU, extract the Serial
247 	 * number(if SMBIOS donates) and set it in the ASRU
248 	 */
249 	if (FM_AWARE_SMBIOS(mod)) {
250 		char *val = NULL;
251 
252 		if (topo_prop_get_fmri(strand, TOPO_PGROUP_PROTOCOL,
253 		    TOPO_PROP_RESOURCE, &fmri, &err) != 0)
254 			whinge(mod, NULL,
255 			    "create_strand: topo_prop_get_fmri failed\n");
256 		if (nvlist_lookup_string(fmri, FM_FMRI_HC_SERIAL_ID, &val) != 0)
257 			whinge(mod, NULL,
258 			    "create_strand: nvlist_lookup_string failed: \n");
259 		else
260 			serial = topo_mod_strdup(mod, val);
261 		nvlist_free(fmri);
262 	}
263 	if (is_xpv()) {
264 		if (topo_node_resource(strand, &fmri, &err) == -1) {
265 			whinge(mod, &nerr, "create_strand: "
266 			    "topo_node_resource failed\n");
267 		} else {
268 			if (FM_AWARE_SMBIOS(mod))
269 				(void) nvlist_add_string(fmri,
270 				    FM_FMRI_HC_SERIAL_ID, serial);
271 			(void) topo_node_asru_set(strand, fmri, 0, &err);
272 			nvlist_free(fmri);
273 		}
274 	} else {
275 		if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
276 			whinge(mod, &nerr, "create_strand: lookup cpuid "
277 			    "failed\n");
278 		} else {
279 			if ((fmri = cpu_fmri_create(mod, cpuid, serial, 0))
280 			    != NULL) {
281 				(void) topo_node_asru_set(strand, fmri,
282 				    0, &err);
283 				nvlist_free(fmri);
284 			} else {
285 				whinge(mod, &nerr, "create_strand: "
286 				    "cpu_fmri_create() failed\n");
287 			}
288 		}
289 	}
290 
291 	if (topo_method_register(mod, strand, strands_retire_methods) < 0)
292 		whinge(mod, &nerr, "create_strand: "
293 		    "topo_method_register failed\n");
294 
295 	(void) topo_pgroup_create(strand, &strand_pgroup, &err);
296 	nerr -= add_nvlist_longprops(mod, strand, cpu, PGNAME(STRAND), NULL,
297 	    STRAND_CHIP_ID, STRAND_PROCNODE_ID, STRAND_CORE_ID, STRAND_CPU_ID,
298 	    NULL);
299 
300 	if (FM_AWARE_SMBIOS(mod)) {
301 		(void) topo_node_label_set(strand, NULL, &perr);
302 
303 		if (topo_node_resource(strand, &fmri, &perr) != 0) {
304 			whinge(mod, &nerr, "create_strand: "
305 			    "topo_node_resource failed\n");
306 			perr = 0;
307 		}
308 
309 		perr += nvlist_lookup_string(fmri,
310 		    FM_FMRI_HC_PART, &part);
311 		perr += nvlist_lookup_string(fmri,
312 		    FM_FMRI_HC_REVISION, &rev);
313 
314 		if (perr != 0) {
315 			whinge(mod, NULL,
316 			    "create_strand: nvlist_lookup_string failed\n");
317 			perr = 0;
318 		}
319 
320 		perr += topo_prop_set_string(strand, PGNAME(STRAND),
321 		    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, serial, &perr);
322 		perr += topo_prop_set_string(strand, PGNAME(STRAND),
323 		    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, part, &perr);
324 		perr += topo_prop_set_string(strand, PGNAME(STRAND),
325 		    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, rev, &perr);
326 
327 		if (perr != 0)
328 			whinge(mod, NULL, "create_strand: topo_prop_set_string"
329 			    "failed\n");
330 
331 		nvlist_free(fmri);
332 		topo_mod_strfree(mod, serial);
333 	}
334 
335 	return (err == 0 && nerr == 0 ? 0 : -1);
336 }
337 
338 static int
339 create_core(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu,
340     nvlist_t *auth, uint16_t chip_smbiosid)
341 {
342 	tnode_t *core;
343 	int32_t coreid, cpuid;
344 	int err, perr, nerr = 0;
345 	nvlist_t *fmri;
346 	char *serial = NULL;
347 	char *part = NULL;
348 	char *rev = NULL;
349 
350 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CORE_ID, &coreid))
351 	    != 0) {
352 		whinge(mod, NULL, "create_core: lookup core_id failed: %s\n",
353 		    strerror(err));
354 		return (-1);
355 	}
356 	if ((core = topo_node_lookup(pnode, CORE_NODE_NAME, coreid)) == NULL) {
357 		if ((core = create_node(mod, pnode, auth, CORE_NODE_NAME,
358 		    coreid, cpu, chip_smbiosid)) == NULL)
359 			return (-1);
360 
361 		/*
362 		 * Inherit FRU from the chip node, for native, we use hc
363 		 * scheme ASRU for the core node.
364 		 */
365 		(void) topo_node_fru_set(core, NULL, 0, &perr);
366 		/*
367 		 * From the inherited FRU, extract the Serial
368 		 * number if SMBIOS donates and set it in the ASRU
369 		 */
370 		if (FM_AWARE_SMBIOS(mod)) {
371 			char *val = NULL;
372 
373 			if (topo_node_resource(core, &fmri, &err) != 0)
374 				whinge(mod, NULL,
375 				    "create_core: topo_prop_get_fmri failed\n");
376 			if (nvlist_lookup_string(fmri, FM_FMRI_HC_SERIAL_ID,
377 			    &val) != 0)
378 				whinge(mod, NULL, "create_core:"
379 				    "nvlist_lookup_string failed\n");
380 			else
381 				serial = topo_mod_strdup(mod, val);
382 			nvlist_free(fmri);
383 		}
384 		if (is_xpv()) {
385 			if (topo_node_resource(core, &fmri, &err) == -1) {
386 				whinge(mod, &nerr, "create_core: "
387 				    "topo_node_resource failed\n");
388 			} else {
389 				if (FM_AWARE_SMBIOS(mod))
390 					(void) nvlist_add_string(fmri,
391 					    FM_FMRI_HC_SERIAL_ID, serial);
392 				(void) topo_node_asru_set(core, fmri, 0, &err);
393 				nvlist_free(fmri);
394 			}
395 		}
396 		if (topo_method_register(mod, core, strands_retire_methods) < 0)
397 			whinge(mod, &nerr, "create_core: "
398 			    "topo_method_register failed\n");
399 
400 		(void) topo_pgroup_create(core, &core_pgroup, &err);
401 		nerr -= add_nvlist_longprops(mod, core, cpu, PGNAME(CORE), NULL,
402 		    CORE_CHIP_ID, CORE_PROCNODE_ID, NULL);
403 
404 		if (topo_node_range_create(mod, core, STRAND_NODE_NAME,
405 		    0, 255) != 0)
406 			return (-1);
407 
408 		/*
409 		 * Creating a temperature sensor may fail because the sensor
410 		 * doesn't exist or due to internal reasons. At the moment, we
411 		 * swallow any such errors that occur.
412 		 */
413 		(void) chip_create_core_temp_sensor(mod, core);
414 	}
415 
416 	if (!is_xpv()) {
417 		/*
418 		 * In native mode, we're in favor of cpu scheme ASRU for
419 		 * printing reason.  More work needs to be done to support
420 		 * multi-strand cpu: the ASRU will be a list of cpuid then.
421 		 */
422 		if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
423 			whinge(mod, &nerr, "create_core: lookup cpuid "
424 			    "failed\n");
425 		} else {
426 			if ((fmri = cpu_fmri_create(mod, cpuid, serial, 0))
427 			    != NULL) {
428 				(void) topo_node_asru_set(core, fmri, 0, &err);
429 				nvlist_free(fmri);
430 			} else {
431 				whinge(mod, &nerr, "create_core: "
432 				    "cpu_fmri_create() failed\n");
433 			}
434 		}
435 	}
436 
437 	if (FM_AWARE_SMBIOS(mod)) {
438 		(void) topo_node_label_set(core, NULL, &perr);
439 
440 		if (topo_node_resource(core, &fmri, &perr) != 0) {
441 			whinge(mod, &nerr, "create_core: "
442 			    "topo_node_resource failed\n");
443 			perr = 0;
444 		}
445 
446 		perr += nvlist_lookup_string(fmri,
447 		    FM_FMRI_HC_PART, &part);
448 		perr += nvlist_lookup_string(fmri,
449 		    FM_FMRI_HC_REVISION, &rev);
450 
451 		if (perr != 0) {
452 			whinge(mod, NULL,
453 			    "create_core: nvlist_lookup_string failed\n");
454 			perr = 0;
455 		}
456 
457 		perr += topo_prop_set_string(core, PGNAME(CORE),
458 		    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, serial, &perr);
459 		perr += topo_prop_set_string(core, PGNAME(CORE),
460 		    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, part, &perr);
461 		perr += topo_prop_set_string(core, PGNAME(CORE),
462 		    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, rev, &perr);
463 
464 		if (perr != 0)
465 			whinge(mod, NULL, "create_core: topo_prop_set_string"
466 			    "failed\n");
467 
468 		nvlist_free(fmri);
469 		topo_mod_strfree(mod, serial);
470 	}
471 
472 	err = create_strand(mod, core, cpu, auth, chip_smbiosid);
473 
474 	return (err == 0 && nerr == 0 ? 0 : -1);
475 }
476 
477 static int
478 create_chip(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
479     topo_instance_t max, nvlist_t *cpu, nvlist_t *auth,
480     int mc_offchip, kstat_ctl_t *kc)
481 {
482 	tnode_t *chip;
483 	nvlist_t *fmri = NULL;
484 	int err, perr, nerr = 0;
485 	int32_t chipid, procnodeid, procnodes_per_pkg;
486 	const char *vendor;
487 	char *brand, *socket;
488 	int32_t family, model;
489 	boolean_t create_mc = B_FALSE;
490 	uint16_t smbios_id;
491 
492 	/*
493 	 * /dev/fm will export the chipid based on SMBIOS' ordering
494 	 * of Type-4 structures, if SMBIOS meets FMA needs
495 	 */
496 	err = nvlist_lookup_pairs(cpu, 0,
497 	    FM_PHYSCPU_INFO_CHIP_ID, DATA_TYPE_INT32, &chipid,
498 	    FM_PHYSCPU_INFO_NPROCNODES, DATA_TYPE_INT32, &procnodes_per_pkg,
499 	    FM_PHYSCPU_INFO_PROCNODE_ID, DATA_TYPE_INT32, &procnodeid,
500 	    FM_PHYSCPU_INFO_VENDOR_ID, DATA_TYPE_STRING, &vendor,
501 	    FM_PHYSCPU_INFO_FAMILY, DATA_TYPE_INT32, &family,
502 	    FM_PHYSCPU_INFO_MODEL, DATA_TYPE_INT32, &model,
503 	    NULL);
504 
505 	if (err) {
506 		whinge(mod, NULL, "create_chip: lookup failed: %s\n",
507 		    strerror(err));
508 		return (-1);
509 	}
510 
511 	if (chipid < min || chipid > max)
512 		return (-1);
513 
514 	if (FM_AWARE_SMBIOS(mod)) {
515 		if ((err = nvlist_lookup_uint16(cpu,
516 		    FM_PHYSCPU_INFO_SMBIOS_ID, &smbios_id)) != 0) {
517 			whinge(mod, NULL,
518 			    "create_chip: lookup smbios_id failed"
519 			    ": enumerating x86pi & chip topology, but"
520 			    " no Chip properties from SMBIOS"
521 			    " - err msg : %s\n", strerror(err));
522 			/*
523 			 * Lets reset the module specific
524 			 * data to NULL, overriding any
525 			 * SMBIOS capability encoded earlier.
526 			 * This will fail all subsequent
527 			 * FM_AWARE_SMBIOS checks.
528 			 */
529 			topo_mod_setspecific(mod, NULL);
530 		}
531 	}
532 
533 	if ((chip = topo_node_lookup(pnode, CHIP_NODE_NAME, chipid)) == NULL) {
534 		if ((chip = create_node(mod, pnode, auth, CHIP_NODE_NAME,
535 		    chipid, cpu, smbios_id)) == NULL)
536 			return (-1);
537 		/*
538 		 * Do not register XML map methods if SMBIOS can provide
539 		 * serial, part, revision & label
540 		 */
541 		if (!FM_AWARE_SMBIOS(mod)) {
542 			if (topo_method_register(mod, chip, chip_methods) < 0)
543 				whinge(mod, &nerr, "create_chip: "
544 				    "topo_method_register failed\n");
545 		}
546 
547 		(void) topo_pgroup_create(chip, &chip_pgroup, &err);
548 		nerr -= add_nvlist_strprop(mod, chip, cpu, PGNAME(CHIP),
549 		    CHIP_VENDOR_ID, NULL);
550 		nerr -= add_nvlist_longprops(mod, chip, cpu, PGNAME(CHIP),
551 		    NULL, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL);
552 
553 		/*
554 		 * Attempt to lookup the processor brand and socket string in
555 		 * kstats and add it as a prop, if found.
556 		 */
557 		brand = socket = NULL;
558 		get_chip_kstat_strs(mod, kc, chipid, &brand, &socket);
559 		if (brand != NULL && topo_prop_set_string(chip, PGNAME(CHIP),
560 		    CHIP_BRAND, TOPO_PROP_IMMUTABLE, brand, &perr) != 0) {
561 			whinge(mod, &nerr, "failed to set prop %s/%s",
562 			    PGNAME(CHIP), CHIP_BRAND);
563 		}
564 		topo_mod_strfree(mod, brand);
565 
566 		if (socket != NULL && topo_prop_set_string(chip, PGNAME(CHIP),
567 		    CHIP_SOCKET, TOPO_PROP_IMMUTABLE, socket, &perr) != 0) {
568 			whinge(mod, &nerr, "failed to set prop %s/%s",
569 			    PGNAME(CHIP), CHIP_SOCKET);
570 		}
571 		topo_mod_strfree(mod, socket);
572 
573 		if (FM_AWARE_SMBIOS(mod)) {
574 			int fru = 0;
575 			char *serial = NULL;
576 			char *part = NULL;
577 			char *rev = NULL;
578 			char *label;
579 
580 			fru = chip_fru_smbios_get(mod, smbios_id);
581 			/*
582 			 * Chip is not a FRU, set the FRU fmri of parent node
583 			 */
584 			if (topo_node_resource(chip, &fmri, &perr) != 0)
585 				whinge(mod, &nerr, "create_chip: "
586 				    "topo_node_resource failed\n");
587 			if (!fru) {
588 				(void) topo_node_fru_set(chip, NULL, 0, &perr);
589 				label = NULL;
590 			} else {
591 				label = (char *)chip_label_smbios_get(mod,
592 				    pnode, smbios_id, NULL);
593 
594 				if (topo_node_fru_set(chip, fmri, 0, &perr)
595 				    != 0) {
596 					whinge(mod, NULL, "create_chip: "
597 					    "topo_node_fru_set failed\n");
598 					perr = 0;
599 				}
600 			}
601 
602 			perr += nvlist_lookup_string(fmri,
603 			    FM_FMRI_HC_SERIAL_ID, &serial);
604 			perr += nvlist_lookup_string(fmri,
605 			    FM_FMRI_HC_PART, &part);
606 			perr += nvlist_lookup_string(fmri,
607 			    FM_FMRI_HC_REVISION, &rev);
608 
609 			if (perr != 0) {
610 				whinge(mod, NULL,
611 				    "create_chip: nvlist_lookup_string"
612 				    "failed\n");
613 				perr = 0;
614 			}
615 
616 			perr += topo_prop_set_string(chip, PGNAME(CHIP),
617 			    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE,
618 			    serial, &perr);
619 			perr += topo_prop_set_string(chip, PGNAME(CHIP),
620 			    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE,
621 			    part, &perr);
622 			perr += topo_prop_set_string(chip, PGNAME(CHIP),
623 			    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE,
624 			    rev, &perr);
625 
626 			if (perr != 0)
627 				whinge(mod, NULL,
628 				    "create_chip: topo_prop_set_string"
629 				    "failed\n");
630 
631 			nvlist_free(fmri);
632 
633 			if (topo_node_label_set(chip, label, &perr)
634 			    == -1) {
635 				whinge(mod, NULL, "create_chip: "
636 				    "topo_node_label_set failed\n");
637 			}
638 			topo_mod_strfree(mod, label);
639 
640 		} else {
641 			if (topo_node_resource(chip, &fmri, &err) == -1) {
642 				whinge(mod, &nerr, "create_chip: "
643 				    "topo_node_resource failed\n");
644 			} else {
645 				(void) topo_node_fru_set(chip, fmri, 0, &perr);
646 				nvlist_free(fmri);
647 			}
648 		}
649 
650 		if (topo_method_register(mod, chip, strands_retire_methods) < 0)
651 			whinge(mod, &nerr, "create_chip: "
652 			    "topo_method_register failed\n");
653 
654 		if (topo_node_range_create(mod, chip, CORE_NODE_NAME, 0, 255))
655 			return (-1);
656 
657 		if (strcmp(vendor, "AuthenticAMD") == 0) {
658 			if (topo_node_range_create(mod, chip, MCT_NODE_NAME,
659 			    0, 255))
660 				return (-1);
661 		}
662 
663 		create_mc = B_TRUE;
664 
665 		/*
666 		 * Creating a temperature sensor may fail because the sensor
667 		 * doesn't exist or due to internal reasons. At the moment, we
668 		 * swallow any such errors that occur.
669 		 */
670 		(void) chip_create_chip_temp_sensor(mod, chip);
671 	}
672 
673 	if (FM_AWARE_SMBIOS(mod)) {
674 		int status = 0;
675 		/*
676 		 * STATUS
677 		 * CPU Socket Populated
678 		 * CPU Socket Unpopulated
679 		 * Populated : Enabled
680 		 * Populated : Disabled by BIOS (Setup)
681 		 * Populated : Disabled by BIOS (Error)
682 		 * Populated : Idle
683 		 *
684 		 * Enumerate core & strand only for Populated : Enabled
685 		 * Enumerate Off-Chip Memory Controller only for
686 		 * Populated : Enabled
687 		 */
688 
689 		status = chip_status_smbios_get(mod, (id_t)smbios_id);
690 		if (!status) {
691 			whinge(mod, NULL, "create_chip: "
692 			    "CPU Socket is not populated or is disabled\n");
693 			return (0);
694 		}
695 	}
696 
697 	err = create_core(mod, chip, cpu, auth, smbios_id);
698 
699 	/*
700 	 * Create memory-controller node under a chip for architectures
701 	 * that may have on-chip memory-controller(s).
702 	 * If SMBIOS meets FMA needs, when Multi-Chip-Module is
703 	 * addressed, mc instances should be derived from SMBIOS
704 	 */
705 	if (strcmp(vendor, "AuthenticAMD") == 0) {
706 		amd_mc_create(mod, smbios_id, chip, MCT_NODE_NAME, auth,
707 		    procnodeid, procnodes_per_pkg, family, model, &nerr);
708 	} else if (create_mc && !mc_offchip)
709 		onchip_mc_create(mod, smbios_id, chip, MCT_NODE_NAME, auth);
710 
711 	return (err == 0 && nerr == 0 ? 0 : -1);
712 }
713 
714 /*ARGSUSED*/
715 static int
716 create_chips(topo_mod_t *mod, tnode_t *pnode, const char *name,
717     topo_instance_t min, topo_instance_t max, void *arg, nvlist_t *auth,
718     int mc_offchip)
719 {
720 	fmd_agent_hdl_t *hdl;
721 	nvlist_t **cpus;
722 	int nerr = 0;
723 	uint_t i, ncpu;
724 	kstat_ctl_t *kc;
725 
726 	if (strcmp(name, CHIP_NODE_NAME) != 0)
727 		return (0);
728 
729 	if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL)
730 		return (-1);
731 	if (fmd_agent_physcpu_info(hdl, &cpus, &ncpu) != 0) {
732 		whinge(mod, NULL, "create_chip: fmd_agent_physcpu_info "
733 		    "failed: %s\n", fmd_agent_errmsg(hdl));
734 		fmd_agent_close(hdl);
735 		return (-1);
736 	}
737 	fmd_agent_close(hdl);
738 
739 	if ((kc = kstat_open()) == NULL) {
740 		whinge(mod, NULL, "kstat_open() failed");
741 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
742 	}
743 
744 	for (i = 0; i < ncpu; i++) {
745 		nerr -= create_chip(mod, pnode, min, max, cpus[i], auth,
746 		    mc_offchip, kc);
747 		nvlist_free(cpus[i]);
748 	}
749 	(void) kstat_close(kc);
750 	umem_free(cpus, sizeof (nvlist_t *) * ncpu);
751 
752 	if (nerr == 0) {
753 		return (0);
754 	} else {
755 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
756 		return (-1);
757 	}
758 }
759 
760 /*ARGSUSED*/
761 static int
762 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
763     topo_instance_t min, topo_instance_t max, void *arg, void *smbios_enabled)
764 {
765 	int rv = 0;
766 	nvlist_t *auth = NULL;
767 	int offchip_mc;
768 	char buf[BUFSIZ];
769 	const char *dom0 = "control_d";
770 
771 	/*
772 	 * Create nothing if we're running in domU.
773 	 */
774 	if (sysinfo(SI_PLATFORM, buf, sizeof (buf)) == -1)
775 		return (-1);
776 
777 	if (strncmp(buf, "i86pc", sizeof (buf)) != 0 &&
778 	    strncmp(buf, "i86xpv", sizeof (buf)) != 0)
779 		return (0);
780 
781 	if (strncmp(buf, "i86xpv", sizeof (buf)) == 0) {
782 		int fd = open("/dev/xen/domcaps", O_RDONLY);
783 
784 		if (fd != -1) {
785 			if (read(fd, buf, sizeof (buf)) <= 0 ||
786 			    strncmp(buf, dom0, strlen(dom0)) != 0) {
787 				(void) close(fd);
788 				return (0);
789 			}
790 			(void) close(fd);
791 		}
792 	}
793 
794 	/*
795 	 * Set Chip Enumerator Module's private data with the value passed by
796 	 * x86pi Enumerator, defining SMBIOS capabilities
797 	 */
798 	topo_mod_setspecific(mod, smbios_enabled);
799 
800 	if (FM_AWARE_SMBIOS(mod))
801 		if (init_chip_smbios(mod) != 0) {
802 			whinge(mod, NULL,
803 			    "init_chip_smbios() failed, "
804 			    " enumerating x86pi & chip topology, but no"
805 			    " CPU & Memory properties will be"
806 			    " derived from SMBIOS\n");
807 			/*
808 			 * Lets reset the module specific
809 			 * data to NULL, overriding any
810 			 * SMBIOS capability encoded earlier.
811 			 * This will fail all subsequent
812 			 * FM_AWARE_SMBIOS checks.
813 			 */
814 			topo_mod_setspecific(mod, NULL);
815 		}
816 
817 	auth = topo_mod_auth(mod, pnode);
818 
819 	offchip_mc = mc_offchip_open();
820 	if (strcmp(name, CHIP_NODE_NAME) == 0)
821 		rv = create_chips(mod, pnode, name, min, max, NULL, auth,
822 		    offchip_mc);
823 
824 	if (offchip_mc)
825 		(void) mc_offchip_create(mod, pnode, "memory-controller", auth);
826 
827 	nvlist_free(auth);
828 
829 	return (rv);
830 }
831