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