17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
57aec1d6eScindi  * Common Development and Distribution License (the "License").
67aec1d6eScindi  * You may not use this file except in compliance with the License.
77aec1d6eScindi  *
87aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi  * See the License for the specific language governing permissions
117aec1d6eScindi  * and limitations under the License.
127aec1d6eScindi  *
137aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi  *
197aec1d6eScindi  * CDDL HEADER END
207aec1d6eScindi  */
217aec1d6eScindi 
227aec1d6eScindi /*
2310569901Sgavinm  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247aec1d6eScindi  * Use is subject to license terms.
257aec1d6eScindi  */
267aec1d6eScindi 
277aec1d6eScindi #include <unistd.h>
28*e4b86885SCheng Sean Ye #include <fcntl.h>
297aec1d6eScindi #include <stdio.h>
307aec1d6eScindi #include <stdlib.h>
318a40a695Sgavinm #include <stdarg.h>
327aec1d6eScindi #include <string.h>
337aec1d6eScindi #include <strings.h>
347aec1d6eScindi #include <limits.h>
357aec1d6eScindi #include <alloca.h>
367aec1d6eScindi #include <kstat.h>
377aec1d6eScindi #include <errno.h>
387aec1d6eScindi #include <libnvpair.h>
397aec1d6eScindi #include <sys/types.h>
407aec1d6eScindi #include <sys/bitmap.h>
417aec1d6eScindi #include <sys/processor.h>
427aec1d6eScindi #include <sys/param.h>
437aec1d6eScindi #include <sys/fm/protocol.h>
447aec1d6eScindi #include <sys/systeminfo.h>
457aec1d6eScindi #include <sys/mc.h>
468a40a695Sgavinm #include <sys/mc_amd.h>
4720c794b3Sgavinm #include <sys/mc_intel.h>
48*e4b86885SCheng Sean Ye #include <sys/devfm.h>
49*e4b86885SCheng Sean Ye #include <fm/fmd_agent.h>
507aec1d6eScindi #include <fm/topo_mod.h>
517aec1d6eScindi 
527aec1d6eScindi #include "chip.h"
537aec1d6eScindi 
54bac58072Sgavinm #define	MAX_DIMMNUM	7
55bac58072Sgavinm #define	MAX_CSNUM	7
56bac58072Sgavinm 
577aec1d6eScindi /*
587aec1d6eScindi  * Enumerates the processing chips, or sockets, (as distinct from cores) in a
597aec1d6eScindi  * system.  For each chip found, the necessary nodes (one or more cores, and
607aec1d6eScindi  * possibly a memory controller) are constructed underneath.
617aec1d6eScindi  */
627aec1d6eScindi 
6320c794b3Sgavinm static int chip_enum(topo_mod_t *, tnode_t *, const char *,
6420c794b3Sgavinm     topo_instance_t, topo_instance_t, void *, void *);
658a40a695Sgavinm 
660eb822a1Scindi static const topo_modops_t chip_ops =
670eb822a1Scindi 	{ chip_enum, NULL};
680eb822a1Scindi static const topo_modinfo_t chip_info =
699dd0f810Scindi 	{ CHIP_NODE_NAME, FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops };
700eb822a1Scindi 
710eb822a1Scindi static const topo_pgroup_info_t chip_pgroup =
729dd0f810Scindi 	{ PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
73*e4b86885SCheng Sean Ye 
74*e4b86885SCheng Sean Ye static const topo_pgroup_info_t core_pgroup =
75*e4b86885SCheng Sean Ye 	{ PGNAME(CORE), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
76*e4b86885SCheng Sean Ye 
77*e4b86885SCheng Sean Ye static const topo_pgroup_info_t strand_pgroup =
78*e4b86885SCheng Sean Ye 	{ PGNAME(STRAND), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
798a40a695Sgavinm 
8020c794b3Sgavinm static const topo_method_t chip_methods[] = {
814557a2a1Srobj 	{ SIMPLE_CHIP_LBL, "Property method", 0,
824557a2a1Srobj 	    TOPO_STABILITY_INTERNAL, simple_chip_label},
834557a2a1Srobj 	{ G4_CHIP_LBL, "Property method", 0,
844557a2a1Srobj 	    TOPO_STABILITY_INTERNAL, g4_chip_label},
852cb5535aSrobj 	{ A4FPLUS_CHIP_LBL, "Property method", 0,
862cb5535aSrobj 	    TOPO_STABILITY_INTERNAL, a4fplus_chip_label},
874557a2a1Srobj 	{ NULL }
884557a2a1Srobj };
894557a2a1Srobj 
90*e4b86885SCheng Sean Ye static const topo_method_t strands_retire_methods[] = {
91*e4b86885SCheng Sean Ye 	{ TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
92*e4b86885SCheng Sean Ye 	    TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
93*e4b86885SCheng Sean Ye 	    retire_strands },
94*e4b86885SCheng Sean Ye 	{ TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
95*e4b86885SCheng Sean Ye 	    TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
96*e4b86885SCheng Sean Ye 	    unretire_strands },
97*e4b86885SCheng Sean Ye 	{ TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
98*e4b86885SCheng Sean Ye 	    TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
99*e4b86885SCheng Sean Ye 	    service_state_strands },
100*e4b86885SCheng Sean Ye 	{ TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
101*e4b86885SCheng Sean Ye 	    TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
102*e4b86885SCheng Sean Ye 	    unusable_strands },
103*e4b86885SCheng Sean Ye 	{ NULL }
104*e4b86885SCheng Sean Ye };
105*e4b86885SCheng Sean Ye 
1067aec1d6eScindi int
1077aec1d6eScindi _topo_init(topo_mod_t *mod)
1087aec1d6eScindi {
1090eb822a1Scindi 	if (getenv("TOPOCHIPDBG"))
1100eb822a1Scindi 		topo_mod_setdebug(mod);
1117aec1d6eScindi 	topo_mod_dprintf(mod, "initializing chip enumerator\n");
1127aec1d6eScindi 
1130eb822a1Scindi 	if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
1148a40a695Sgavinm 		whinge(mod, NULL, "failed to register hc: "
1157aec1d6eScindi 		    "%s\n", topo_mod_errmsg(mod));
1167aec1d6eScindi 		return (-1); /* mod errno set */
1177aec1d6eScindi 	}
1187aec1d6eScindi 
1197aec1d6eScindi 	return (0);
1207aec1d6eScindi }
1217aec1d6eScindi 
1227aec1d6eScindi void
1237aec1d6eScindi _topo_fini(topo_mod_t *mod)
1247aec1d6eScindi {
1257aec1d6eScindi 	topo_mod_unregister(mod);
1267aec1d6eScindi }
1277aec1d6eScindi 
128*e4b86885SCheng Sean Ye boolean_t
129*e4b86885SCheng Sean Ye is_xpv(void)
130e3d60c9bSAdrian Frost {
131*e4b86885SCheng Sean Ye 	static int r = -1;
132*e4b86885SCheng Sean Ye 	char platform[MAXNAMELEN];
133e3d60c9bSAdrian Frost 
134*e4b86885SCheng Sean Ye 	if (r != -1)
135*e4b86885SCheng Sean Ye 		return (r == 0);
136e3d60c9bSAdrian Frost 
137*e4b86885SCheng Sean Ye 	(void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
138*e4b86885SCheng Sean Ye 	r = strcmp(platform, "i86xpv");
139*e4b86885SCheng Sean Ye 	return (r == 0);
140*e4b86885SCheng Sean Ye }
141e3d60c9bSAdrian Frost 
142*e4b86885SCheng Sean Ye static tnode_t *
143*e4b86885SCheng Sean Ye create_node(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, char *name,
144*e4b86885SCheng Sean Ye     topo_instance_t inst)
145*e4b86885SCheng Sean Ye {
146*e4b86885SCheng Sean Ye 	nvlist_t *fmri;
147*e4b86885SCheng Sean Ye 	tnode_t *cnode;
148e3d60c9bSAdrian Frost 
149*e4b86885SCheng Sean Ye 	if (mkrsrc(mod, pnode, name, inst, auth, &fmri) != 0) {
150*e4b86885SCheng Sean Ye 		whinge(mod, NULL, "create_node: mkrsrc failed\n");
151*e4b86885SCheng Sean Ye 		return (NULL);
152e3d60c9bSAdrian Frost 	}
153*e4b86885SCheng Sean Ye 	cnode = topo_node_bind(mod, pnode, name, inst, fmri);
154*e4b86885SCheng Sean Ye 	nvlist_free(fmri);
155*e4b86885SCheng Sean Ye 	if (cnode == NULL)
156*e4b86885SCheng Sean Ye 		whinge(mod, NULL, "create_node: node bind failed for %s %d\n",
157*e4b86885SCheng Sean Ye 		    name, (int)inst);
158e3d60c9bSAdrian Frost 
159*e4b86885SCheng Sean Ye 	return (cnode);
160e3d60c9bSAdrian Frost }
161e3d60c9bSAdrian Frost 
162e3d60c9bSAdrian Frost static int
163*e4b86885SCheng Sean Ye create_strand(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu, nvlist_t *auth)
164e3d60c9bSAdrian Frost {
165*e4b86885SCheng Sean Ye 	tnode_t *strand;
166*e4b86885SCheng Sean Ye 	int32_t strandid, cpuid;
167e3d60c9bSAdrian Frost 	int err, nerr = 0;
168*e4b86885SCheng Sean Ye 	nvlist_t *fmri;
169e3d60c9bSAdrian Frost 
170*e4b86885SCheng Sean Ye 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_STRAND_ID,
171*e4b86885SCheng Sean Ye 	    &strandid)) != 0) {
172*e4b86885SCheng Sean Ye 		whinge(mod, NULL, "create_strand: lookup strand_id failed: "
173*e4b86885SCheng Sean Ye 		    "%s\n", strerror(err));
174e3d60c9bSAdrian Frost 		return (-1);
175*e4b86885SCheng Sean Ye 	}
176e3d60c9bSAdrian Frost 
177*e4b86885SCheng Sean Ye 	if ((strand = topo_node_lookup(pnode, STRAND_NODE_NAME, strandid))
178*e4b86885SCheng Sean Ye 	    != NULL) {
179*e4b86885SCheng Sean Ye 		whinge(mod, NULL, "create_strand: duplicate tuple found\n");
180*e4b86885SCheng Sean Ye 		return (-1);
181*e4b86885SCheng Sean Ye 	}
182e3d60c9bSAdrian Frost 
183*e4b86885SCheng Sean Ye 	if ((strand = create_node(mod, pnode, auth, STRAND_NODE_NAME,
184*e4b86885SCheng Sean Ye 	    strandid)) == NULL)
185*e4b86885SCheng Sean Ye 		return (-1);
186e3d60c9bSAdrian Frost 
187*e4b86885SCheng Sean Ye 	/*
188*e4b86885SCheng Sean Ye 	 * Inherit FRU from core node, in native use cpu scheme ASRU,
189*e4b86885SCheng Sean Ye 	 * in xpv, use hc scheme ASRU.
190*e4b86885SCheng Sean Ye 	 */
191*e4b86885SCheng Sean Ye 	(void) topo_node_fru_set(strand, NULL, 0, &err);
192*e4b86885SCheng Sean Ye 	if (is_xpv()) {
193*e4b86885SCheng Sean Ye 		if (topo_node_resource(strand, &fmri, &err) == -1) {
194*e4b86885SCheng Sean Ye 			whinge(mod, &nerr, "create_strand: "
195*e4b86885SCheng Sean Ye 			    "topo_node_resource failed\n");
196*e4b86885SCheng Sean Ye 		} else {
197*e4b86885SCheng Sean Ye 			(void) topo_node_asru_set(strand, fmri, 0, &err);
198e3d60c9bSAdrian Frost 			nvlist_free(fmri);
199e3d60c9bSAdrian Frost 		}
200*e4b86885SCheng Sean Ye 	} else {
201*e4b86885SCheng Sean Ye 		if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
202*e4b86885SCheng Sean Ye 			whinge(mod, &nerr, "create_strand: lookup cpuid "
203*e4b86885SCheng Sean Ye 			    "failed\n");
204*e4b86885SCheng Sean Ye 		} else {
205*e4b86885SCheng Sean Ye 			if ((fmri = cpu_fmri_create(mod, cpuid, NULL, 0))
206*e4b86885SCheng Sean Ye 			    != NULL) {
207*e4b86885SCheng Sean Ye 				(void) topo_node_asru_set(strand, fmri,
208*e4b86885SCheng Sean Ye 				    0, &err);
209*e4b86885SCheng Sean Ye 				nvlist_free(fmri);
210*e4b86885SCheng Sean Ye 			} else {
211*e4b86885SCheng Sean Ye 				whinge(mod, &nerr, "create_strand: "
212*e4b86885SCheng Sean Ye 				    "cpu_fmri_create() failed\n");
213*e4b86885SCheng Sean Ye 			}
214*e4b86885SCheng Sean Ye 		}
215*e4b86885SCheng Sean Ye 	}
216e3d60c9bSAdrian Frost 
217*e4b86885SCheng Sean Ye 	if (topo_method_register(mod, strand, strands_retire_methods) < 0)
218*e4b86885SCheng Sean Ye 		whinge(mod, &nerr, "create_strand: "
219*e4b86885SCheng Sean Ye 		    "topo_method_register failed\n");
220e3d60c9bSAdrian Frost 
221*e4b86885SCheng Sean Ye 	(void) topo_pgroup_create(strand, &strand_pgroup, &err);
222*e4b86885SCheng Sean Ye 	nerr -= add_nvlist_longprops(mod, strand, cpu, PGNAME(STRAND), NULL,
223*e4b86885SCheng Sean Ye 	    STRAND_CHIP_ID, STRAND_CORE_ID, STRAND_CPU_ID, NULL);
224e3d60c9bSAdrian Frost 
225*e4b86885SCheng Sean Ye 	return (err == 0 && nerr == 0 ? 0 : -1);
226e3d60c9bSAdrian Frost }
227e3d60c9bSAdrian Frost 
2287aec1d6eScindi static int
229*e4b86885SCheng Sean Ye create_core(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu, nvlist_t *auth)
2307aec1d6eScindi {
231*e4b86885SCheng Sean Ye 	tnode_t *core;
232*e4b86885SCheng Sean Ye 	int32_t coreid, cpuid;
23335c358f7Sgavinm 	int err, nerr = 0;
234*e4b86885SCheng Sean Ye 	nvlist_t *fmri;
2357aec1d6eScindi 
236*e4b86885SCheng Sean Ye 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CORE_ID, &coreid))
237*e4b86885SCheng Sean Ye 	    != 0) {
238*e4b86885SCheng Sean Ye 		whinge(mod, NULL, "create_core: lookup core_id failed: %s\n",
239*e4b86885SCheng Sean Ye 		    strerror(err));
2407aec1d6eScindi 		return (-1);
241*e4b86885SCheng Sean Ye 	}
242*e4b86885SCheng Sean Ye 	if ((core = topo_node_lookup(pnode, CORE_NODE_NAME, coreid)) == NULL) {
243*e4b86885SCheng Sean Ye 		if ((core = create_node(mod, pnode, auth, CORE_NODE_NAME,
244*e4b86885SCheng Sean Ye 		    coreid)) == NULL)
245*e4b86885SCheng Sean Ye 			return (-1);
2467aec1d6eScindi 
2478a40a695Sgavinm 		/*
248*e4b86885SCheng Sean Ye 		 * Inherit FRU from the chip node, for native, we use hc
249*e4b86885SCheng Sean Ye 		 * scheme ASRU for the core node.
2508a40a695Sgavinm 		 */
251*e4b86885SCheng Sean Ye 		(void) topo_node_fru_set(core, NULL, 0, &err);
252*e4b86885SCheng Sean Ye 		if (is_xpv()) {
253*e4b86885SCheng Sean Ye 			if (topo_node_resource(core, &fmri, &err) == -1) {
254*e4b86885SCheng Sean Ye 				whinge(mod, &nerr, "create_core: "
255*e4b86885SCheng Sean Ye 				    "topo_node_resource failed\n");
256*e4b86885SCheng Sean Ye 			} else {
257*e4b86885SCheng Sean Ye 				(void) topo_node_asru_set(core, fmri, 0, &err);
258*e4b86885SCheng Sean Ye 				nvlist_free(fmri);
259*e4b86885SCheng Sean Ye 			}
2607aec1d6eScindi 		}
261*e4b86885SCheng Sean Ye 		if (topo_method_register(mod, core, strands_retire_methods) < 0)
262*e4b86885SCheng Sean Ye 			whinge(mod, &nerr, "create_core: "
263*e4b86885SCheng Sean Ye 			    "topo_method_register failed\n");
264*e4b86885SCheng Sean Ye 
265*e4b86885SCheng Sean Ye 		(void) topo_pgroup_create(core, &core_pgroup, &err);
266*e4b86885SCheng Sean Ye 		nerr -= add_nvlist_longprop(mod, core, cpu, PGNAME(CORE),
267*e4b86885SCheng Sean Ye 		    CORE_CHIP_ID, NULL);
2687aec1d6eScindi 
269*e4b86885SCheng Sean Ye 		if (topo_node_range_create(mod, core, STRAND_NODE_NAME,
270*e4b86885SCheng Sean Ye 		    0, 255) != 0)
271*e4b86885SCheng Sean Ye 			return (-1);
272*e4b86885SCheng Sean Ye 	}
2738a40a695Sgavinm 
274*e4b86885SCheng Sean Ye 	if (! is_xpv()) {
2758a40a695Sgavinm 		/*
276*e4b86885SCheng Sean Ye 		 * In native mode, we're in favor of cpu scheme ASRU for
277*e4b86885SCheng Sean Ye 		 * printing reason.  More work needs to be done to support
278*e4b86885SCheng Sean Ye 		 * multi-strand cpu: the ASRU will be a list of cpuid then.
2798a40a695Sgavinm 		 */
280*e4b86885SCheng Sean Ye 		if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
281*e4b86885SCheng Sean Ye 			whinge(mod, &nerr, "create_core: lookup cpuid "
2828a40a695Sgavinm 			    "failed\n");
283*e4b86885SCheng Sean Ye 		} else {
284*e4b86885SCheng Sean Ye 			if ((fmri = cpu_fmri_create(mod, cpuid, NULL, 0))
285*e4b86885SCheng Sean Ye 			    != NULL) {
286*e4b86885SCheng Sean Ye 				(void) topo_node_asru_set(core, fmri, 0, &err);
287*e4b86885SCheng Sean Ye 				nvlist_free(fmri);
288*e4b86885SCheng Sean Ye 			} else {
289*e4b86885SCheng Sean Ye 				whinge(mod, &nerr, "create_core: "
290*e4b86885SCheng Sean Ye 				    "cpu_fmri_create() failed\n");
291*e4b86885SCheng Sean Ye 			}
2927aec1d6eScindi 		}
2937aec1d6eScindi 	}
2947aec1d6eScindi 
295*e4b86885SCheng Sean Ye 	err = create_strand(mod, core, cpu, auth);
296*e4b86885SCheng Sean Ye 
297*e4b86885SCheng Sean Ye 	return (err == 0 && nerr == 0 ? 0 : -1);
2987aec1d6eScindi }
2997aec1d6eScindi 
3007aec1d6eScindi static int
301*e4b86885SCheng Sean Ye create_chip(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
302*e4b86885SCheng Sean Ye     topo_instance_t max, nvlist_t *cpu, nvlist_t *auth,
303e3d60c9bSAdrian Frost     int mc_offchip)
3047aec1d6eScindi {
305*e4b86885SCheng Sean Ye 	tnode_t *chip;
306*e4b86885SCheng Sean Ye 	int32_t chipid;
307*e4b86885SCheng Sean Ye 	nvlist_t *fmri = NULL;
308*e4b86885SCheng Sean Ye 	int err, nerr = 0;
309*e4b86885SCheng Sean Ye 	int32_t fms[3];
310*e4b86885SCheng Sean Ye 	const char *vendor = NULL;
3117aec1d6eScindi 
312*e4b86885SCheng Sean Ye 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CHIP_ID, &chipid))
313*e4b86885SCheng Sean Ye 	    != 0) {
314*e4b86885SCheng Sean Ye 		whinge(mod, NULL, "create_chip: lookup chip_id failed: %s\n",
315*e4b86885SCheng Sean Ye 		    strerror(err));
316*e4b86885SCheng Sean Ye 		return (-1);
3177aec1d6eScindi 	}
3187aec1d6eScindi 
319*e4b86885SCheng Sean Ye 	if (chipid < min || chipid > max)
320*e4b86885SCheng Sean Ye 		return (-1);
3217aec1d6eScindi 
322*e4b86885SCheng Sean Ye 	if ((chip = topo_node_lookup(pnode, CHIP_NODE_NAME, chipid)) == NULL) {
323*e4b86885SCheng Sean Ye 		if ((chip = create_node(mod, pnode, auth, CHIP_NODE_NAME,
324*e4b86885SCheng Sean Ye 		    chipid)) == NULL)
325*e4b86885SCheng Sean Ye 			return (-1);
3267aec1d6eScindi 
327*e4b86885SCheng Sean Ye 		if (topo_method_register(mod, chip, chip_methods) < 0)
328*e4b86885SCheng Sean Ye 			whinge(mod, &nerr, "create_chip: "
329*e4b86885SCheng Sean Ye 			    "topo_method_register failed\n");
3307aec1d6eScindi 
331*e4b86885SCheng Sean Ye 		if (topo_node_resource(chip, &fmri, &err) == -1) {
332*e4b86885SCheng Sean Ye 			whinge(mod, &nerr, "create_chip: "
333*e4b86885SCheng Sean Ye 			    "topo_node_resource failed\n");
334*e4b86885SCheng Sean Ye 		} else {
335*e4b86885SCheng Sean Ye 			(void) topo_node_fru_set(chip, fmri, 0, &err);
3367aec1d6eScindi 			nvlist_free(fmri);
3377aec1d6eScindi 		}
3387aec1d6eScindi 
339*e4b86885SCheng Sean Ye 		(void) topo_pgroup_create(chip, &chip_pgroup, &err);
340*e4b86885SCheng Sean Ye 		nerr -= add_nvlist_strprop(mod, chip, cpu, PGNAME(CHIP),
341*e4b86885SCheng Sean Ye 		    CHIP_VENDOR_ID, &vendor);
342*e4b86885SCheng Sean Ye 		nerr -= add_nvlist_longprops(mod, chip, cpu, PGNAME(CHIP),
343*e4b86885SCheng Sean Ye 		    fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL);
3444557a2a1Srobj 
345*e4b86885SCheng Sean Ye 		if (topo_method_register(mod, chip, strands_retire_methods) < 0)
346*e4b86885SCheng Sean Ye 			whinge(mod, &nerr, "create_chip: "
347*e4b86885SCheng Sean Ye 			    "topo_method_register failed\n");
3487aec1d6eScindi 
349*e4b86885SCheng Sean Ye 		if (topo_node_range_create(mod, chip, CORE_NODE_NAME,
350*e4b86885SCheng Sean Ye 		    0, 255) != 0)
351*e4b86885SCheng Sean Ye 			return (-1);
352*e4b86885SCheng Sean Ye 	}
3537aec1d6eScindi 
354*e4b86885SCheng Sean Ye 	err = create_core(mod, chip, cpu, auth);
3559dd0f810Scindi 
356*e4b86885SCheng Sean Ye 	/*
357*e4b86885SCheng Sean Ye 	 * Create memory-controller node under a chip for architectures
358*e4b86885SCheng Sean Ye 	 * that may have on-chip memory-controller(s).
359*e4b86885SCheng Sean Ye 	 */
360*e4b86885SCheng Sean Ye 	if (vendor != NULL && strcmp(vendor, "AuthenticAMD") == 0)
361*e4b86885SCheng Sean Ye 		amd_mc_create(mod, chip, MCT_NODE_NAME, auth,
362*e4b86885SCheng Sean Ye 		    fms[0], fms[1], fms[2], &nerr);
363*e4b86885SCheng Sean Ye 	else if (!mc_offchip)
364*e4b86885SCheng Sean Ye 		onchip_mc_create(mod, chip, MCT_NODE_NAME, auth);
3657aec1d6eScindi 
366*e4b86885SCheng Sean Ye 	return (err == 0 && nerr == 0 ? 0 : -1);
367*e4b86885SCheng Sean Ye }
368e3d60c9bSAdrian Frost 
369*e4b86885SCheng Sean Ye /*ARGSUSED*/
370*e4b86885SCheng Sean Ye static int
371*e4b86885SCheng Sean Ye create_chips(topo_mod_t *mod, tnode_t *pnode, const char *name,
372*e4b86885SCheng Sean Ye     topo_instance_t min, topo_instance_t max, void *arg, nvlist_t *auth,
373*e4b86885SCheng Sean Ye     int mc_offchip)
374*e4b86885SCheng Sean Ye {
375*e4b86885SCheng Sean Ye 	fmd_agent_hdl_t *hdl;
376*e4b86885SCheng Sean Ye 	nvlist_t **cpus;
377*e4b86885SCheng Sean Ye 	int nerr = 0;
378*e4b86885SCheng Sean Ye 	uint_t i, ncpu;
37920c794b3Sgavinm 
380*e4b86885SCheng Sean Ye 	if (strcmp(name, CHIP_NODE_NAME) != 0)
381*e4b86885SCheng Sean Ye 		return (0);
382*e4b86885SCheng Sean Ye 
383*e4b86885SCheng Sean Ye 	if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL)
384*e4b86885SCheng Sean Ye 		return (-1);
385*e4b86885SCheng Sean Ye 	if (fmd_agent_physcpu_info(hdl, &cpus, &ncpu) != 0) {
386*e4b86885SCheng Sean Ye 		whinge(mod, NULL, "create_chip: fmd_agent_physcpu_info "
387*e4b86885SCheng Sean Ye 		    "failed: %s\n", fmd_agent_errmsg(hdl));
388*e4b86885SCheng Sean Ye 		fmd_agent_close(hdl);
389*e4b86885SCheng Sean Ye 		return (-1);
3907aec1d6eScindi 	}
391*e4b86885SCheng Sean Ye 	fmd_agent_close(hdl);
3927aec1d6eScindi 
393*e4b86885SCheng Sean Ye 	for (i = 0; i < ncpu; i++) {
394*e4b86885SCheng Sean Ye 		nerr -= create_chip(mod, pnode, min, max, cpus[i], auth,
395*e4b86885SCheng Sean Ye 		    mc_offchip);
396*e4b86885SCheng Sean Ye 		nvlist_free(cpus[i]);
397*e4b86885SCheng Sean Ye 	}
398*e4b86885SCheng Sean Ye 	umem_free(cpus, sizeof (nvlist_t *) * ncpu);
3997aec1d6eScindi 
4008a40a695Sgavinm 	if (nerr == 0) {
4018a40a695Sgavinm 		return (0);
4028a40a695Sgavinm 	} else {
4037aec1d6eScindi 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
4048a40a695Sgavinm 		return (-1);
4058a40a695Sgavinm 	}
4067aec1d6eScindi }
4077aec1d6eScindi 
4080eb822a1Scindi /*ARGSUSED*/
4097aec1d6eScindi static int
4107aec1d6eScindi chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
4110eb822a1Scindi     topo_instance_t min, topo_instance_t max, void *arg, void *notused)
4127aec1d6eScindi {
4130eb822a1Scindi 	int rv = 0;
4140eb822a1Scindi 	nvlist_t *auth = NULL;
415e3d60c9bSAdrian Frost 	int offchip_mc;
416*e4b86885SCheng Sean Ye 	char buf[BUFSIZ];
417*e4b86885SCheng Sean Ye 	const char *dom0 = "control_d";
418*e4b86885SCheng Sean Ye 
419*e4b86885SCheng Sean Ye 	/*
420*e4b86885SCheng Sean Ye 	 * Create nothing if we're running in domU.
421*e4b86885SCheng Sean Ye 	 */
422*e4b86885SCheng Sean Ye 	if (sysinfo(SI_PLATFORM, buf, sizeof (buf)) == -1)
423*e4b86885SCheng Sean Ye 		return (-1);
424*e4b86885SCheng Sean Ye 
425*e4b86885SCheng Sean Ye 	if (strncmp(buf, "i86pc", sizeof (buf)) != 0 &&
426*e4b86885SCheng Sean Ye 	    strncmp(buf, "i86xpv", sizeof (buf)) != 0)
427*e4b86885SCheng Sean Ye 		return (0);
428*e4b86885SCheng Sean Ye 
429*e4b86885SCheng Sean Ye 	if (strncmp(buf, "i86xpv", sizeof (buf)) == 0) {
430*e4b86885SCheng Sean Ye 		int fd = open("/dev/xen/domcaps", O_RDONLY);
431*e4b86885SCheng Sean Ye 
432*e4b86885SCheng Sean Ye 		if (fd != -1) {
433*e4b86885SCheng Sean Ye 			if (read(fd, buf, sizeof (buf)) <= 0 ||
434*e4b86885SCheng Sean Ye 			    strncmp(buf, dom0, strlen(dom0)) != 0) {
435*e4b86885SCheng Sean Ye 				(void) close(fd);
436*e4b86885SCheng Sean Ye 				return (0);
437*e4b86885SCheng Sean Ye 			}
438*e4b86885SCheng Sean Ye 			(void) close(fd);
439*e4b86885SCheng Sean Ye 		}
440*e4b86885SCheng Sean Ye 	}
4410eb822a1Scindi 
4420eb822a1Scindi 	auth = topo_mod_auth(mod, pnode);
4437aec1d6eScindi 
444e3d60c9bSAdrian Frost 	offchip_mc = mc_offchip_open();
4459dd0f810Scindi 	if (strcmp(name, CHIP_NODE_NAME) == 0)
446*e4b86885SCheng Sean Ye 		rv = create_chips(mod, pnode, name, min, max, NULL, auth,
447e3d60c9bSAdrian Frost 		    offchip_mc);
4487aec1d6eScindi 
449e3d60c9bSAdrian Frost 	if (offchip_mc)
45020c794b3Sgavinm 		(void) mc_offchip_create(mod, pnode, "memory-controller", auth);
45120c794b3Sgavinm 
4520eb822a1Scindi 	nvlist_free(auth);
4530eb822a1Scindi 
4540eb822a1Scindi 	return (rv);
4557aec1d6eScindi }
456