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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <limits.h>
36 #include <alloca.h>
37 #include <kstat.h>
38 #include <errno.h>
39 #include <libnvpair.h>
40 #include <sys/types.h>
41 #include <sys/bitmap.h>
42 #include <sys/processor.h>
43 #include <sys/param.h>
44 #include <sys/fm/protocol.h>
45 #include <sys/systeminfo.h>
46 #include <sys/mc.h>
47 #include <sys/mc_amd.h>
48 #include <sys/mc_intel.h>
49 #include <fm/topo_mod.h>
50 
51 #include "chip.h"
52 
53 #define	MAX_DIMMNUM	7
54 #define	MAX_CSNUM	7
55 
56 /*
57  * Enumerates the processing chips, or sockets, (as distinct from cores) in a
58  * system.  For each chip found, the necessary nodes (one or more cores, and
59  * possibly a memory controller) are constructed underneath.
60  */
61 
62 static int chip_enum(topo_mod_t *, tnode_t *, const char *,
63     topo_instance_t, topo_instance_t, void *, void *);
64 
65 static const topo_modops_t chip_ops =
66 	{ chip_enum, NULL};
67 static const topo_modinfo_t chip_info =
68 	{ CHIP_NODE_NAME, FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops };
69 
70 static const topo_pgroup_info_t chip_pgroup =
71 	{ PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
72 static const topo_pgroup_info_t cpu_pgroup =
73 	{ PGNAME(CPU), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
74 
75 static const topo_method_t chip_methods[] = {
76 	{ SIMPLE_CHIP_LBL, "Property method", 0,
77 	    TOPO_STABILITY_INTERNAL, simple_chip_label},
78 	{ G4_CHIP_LBL, "Property method", 0,
79 	    TOPO_STABILITY_INTERNAL, g4_chip_label},
80 	{ NULL }
81 };
82 
83 int
84 _topo_init(topo_mod_t *mod)
85 {
86 	chip_t *chip;
87 
88 	if (getenv("TOPOCHIPDBG"))
89 		topo_mod_setdebug(mod);
90 	topo_mod_dprintf(mod, "initializing chip enumerator\n");
91 
92 	if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL)
93 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
94 
95 	if ((chip->chip_kc = kstat_open()) == NULL) {
96 		whinge(mod, NULL, "kstat_open failed: %s\n",
97 		    strerror(errno));
98 		topo_mod_free(mod, chip, sizeof (chip_t));
99 		return (topo_mod_seterrno(mod, errno));
100 	}
101 
102 	chip->chip_ncpustats = sysconf(_SC_CPUID_MAX);
103 	if ((chip->chip_cpustats = topo_mod_zalloc(mod, (
104 	    chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) {
105 		(void) kstat_close(chip->chip_kc);
106 		topo_mod_free(mod, chip, sizeof (chip_t));
107 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
108 	}
109 
110 	if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
111 		whinge(mod, NULL, "failed to register hc: "
112 		    "%s\n", topo_mod_errmsg(mod));
113 		topo_mod_free(mod, chip->chip_cpustats,
114 		    (chip->chip_ncpustats + 1) * sizeof (kstat_t *));
115 		(void) kstat_close(chip->chip_kc);
116 		topo_mod_free(mod, chip, sizeof (chip_t));
117 		return (-1); /* mod errno set */
118 	}
119 	topo_mod_setspecific(mod, (void *)chip);
120 
121 	return (0);
122 }
123 
124 void
125 _topo_fini(topo_mod_t *mod)
126 {
127 	chip_t *chip = topo_mod_getspecific(mod);
128 
129 	if (chip->chip_cpustats != NULL)
130 		topo_mod_free(mod, chip->chip_cpustats,
131 		    (chip->chip_ncpustats + 1) * sizeof (kstat_t *));
132 
133 	(void) kstat_close(chip->chip_kc);
134 	topo_mod_free(mod, chip, sizeof (chip_t));
135 
136 	topo_mod_unregister(mod);
137 }
138 
139 static int
140 cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid,
141     chip_t *chip, nvlist_t *auth)
142 {
143 	kstat_named_t *k;
144 	nvlist_t *fmri, *asru;
145 	tnode_t *cnode;
146 	int err, nerr = 0;
147 	int clogid, cpuid;
148 
149 	if (topo_node_range_create(mod, pnode, name, 0,
150 	    chip->chip_ncpustats) < 0)
151 		return (-1);
152 
153 	for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) {
154 		if (chip->chip_cpustats[cpuid] == NULL)
155 			continue;
156 
157 		/*
158 		 * The chip_id in the cpu_info kstat numbers the individual
159 		 * chips from 0 to #chips - 1.
160 		 */
161 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
162 		    "chip_id")) == NULL) {
163 			whinge(mod, &nerr, "cpu_create: chip_id lookup via "
164 			    "kstats failed\n");
165 			continue;
166 		}
167 
168 		if (k->value.l != chipid)
169 			continue;	/* not an error */
170 
171 		/*
172 		 * The clog_id in the cpu_info kstat numbers the virtual
173 		 * processors of a single chip;  these may be separate
174 		 * processor cores, or they may be hardware threads/strands
175 		 * of individual cores.
176 		 *
177 		 * The core_id in the cpu_info kstat tells us which cpus
178 		 * share the same core - i.e., are hardware strands of the
179 		 * same core.  The core ids do not reset to zero for each
180 		 * distinct chip - they number across all cores of all chips.
181 		 * This enumerator does not distinguish stranded
182 		 * cores so core_id is unused.
183 		 */
184 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
185 		    "clog_id")) == NULL) {
186 			whinge(mod, &nerr, "cpu_create: clog_id lookup via "
187 			    "kstats failed\n");
188 			continue;
189 		}
190 		clogid = k->value.l;
191 
192 		if (mkrsrc(mod, pnode, name, clogid, auth, &fmri) != 0) {
193 			whinge(mod, &nerr, "cpu_create: mkrsrc failed\n");
194 			continue;
195 		}
196 
197 		if ((cnode = topo_node_bind(mod, pnode, name, clogid, fmri))
198 		    == NULL) {
199 			whinge(mod, &nerr, "cpu_create: node bind failed\n");
200 			nvlist_free(fmri);
201 			continue;
202 		}
203 		nvlist_free(fmri);
204 
205 		if ((asru = cpu_fmri_create(mod, cpuid, NULL, 0)) != NULL) {
206 			(void) topo_node_asru_set(cnode, asru, 0, &err);
207 			nvlist_free(asru);
208 		} else {
209 			whinge(mod, &nerr, "cpu_create: cpu_fmri_create "
210 			    "failed\n");
211 		}
212 		(void) topo_node_fru_set(cnode, NULL, 0, &err);
213 
214 		(void) topo_pgroup_create(cnode, &cpu_pgroup, &err);
215 
216 		(void) topo_prop_set_uint32(cnode, PGNAME(CPU), "cpuid",
217 		    TOPO_PROP_IMMUTABLE, cpuid, &err);
218 
219 		if (add_kstat_longprops(mod, cnode, chip->chip_cpustats[cpuid],
220 		    PGNAME(CPU), NULL, CPU_CHIP_ID, CPU_CORE_ID, CPU_CLOG_ID,
221 		    NULL) != 0)
222 			nerr++;		/* have whinged elsewhere */
223 	}
224 
225 	return (nerr == 0 ? 0 : -1);
226 }
227 
228 static int
229 chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
230     topo_instance_t min, topo_instance_t max, chip_t *chip, nvlist_t *auth)
231 {
232 	int i, nerr = 0;
233 	kstat_t *ksp;
234 	ulong_t *chipmap;
235 	tnode_t *cnode;
236 	nvlist_t *fmri;
237 
238 	if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(max) *
239 	    sizeof (ulong_t))) == NULL)
240 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
241 
242 	/*
243 	 * Read in all cpu_info kstats, for all chip ids.  The ks_instance
244 	 * argument to kstat_lookup is the logical cpu_id - we will use this
245 	 * in cpu_create.
246 	 */
247 	for (i = 0; i <= chip->chip_ncpustats; i++) {
248 		if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) ==
249 		    NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0)
250 			continue;
251 
252 		chip->chip_cpustats[i] = ksp;
253 	}
254 
255 	for (i = 0; i <= chip->chip_ncpustats; i++) {
256 		const char *vendor;
257 		int32_t fms[3];
258 		kstat_named_t *k;
259 		int err, chipid;
260 
261 		if ((ksp = chip->chip_cpustats[i]) == NULL)
262 			continue;
263 
264 		if ((k = kstat_data_lookup(ksp, "chip_id")) == NULL) {
265 			whinge(mod, &nerr, "chip_create: chip_id lookup "
266 			    "via kstats failed\n");
267 			continue;
268 		}
269 
270 		chipid = k->value.l;
271 		if (BT_TEST(chipmap, chipid))
272 			continue;
273 
274 		if (chipid < min || chipid > max)
275 			continue;
276 
277 		if (mkrsrc(mod, pnode, name, chipid, auth, &fmri) != 0) {
278 			whinge(mod, &nerr, "chip_create: mkrsrc failed\n");
279 			continue;
280 		}
281 
282 		if ((cnode = topo_node_bind(mod, pnode, name, chipid, fmri))
283 		    == NULL) {
284 			nvlist_free(fmri);
285 			whinge(mod, &nerr, "chip_create: node bind "
286 			    "failed for chipid %d\n", chipid);
287 			continue;
288 		}
289 		BT_SET(chipmap, chipid);
290 
291 		if (topo_method_register(mod, cnode, chip_methods) < 0)
292 			whinge(mod, &nerr, "chip_create: "
293 			    "topo_method_register failed");
294 
295 		(void) topo_node_fru_set(cnode, fmri, 0, &err);
296 
297 		nvlist_free(fmri);
298 
299 		(void) topo_pgroup_create(cnode, &chip_pgroup, &err);
300 		if (add_kstat_strprop(mod, cnode, ksp, PGNAME(CHIP),
301 		    CHIP_VENDOR_ID, &vendor) != 0)
302 			nerr++;		/* have whinged elsewhere */
303 
304 		if (add_kstat_longprops(mod, cnode, ksp, PGNAME(CHIP),
305 		    fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL) != 0)
306 			nerr++;		/* have whinged elsewhere */
307 
308 		if (cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip, auth)
309 		    != 0)
310 			nerr++;		/* have whinged elsewhere */
311 
312 		/*
313 		 * Create memory-controller node under a chip for architectures
314 		 * that may have on-chip memory-controller(s).
315 		 */
316 		if (strcmp(vendor, "AuthenticAMD") == 0)
317 			amd_mc_create(mod, cnode, MCT_NODE_NAME, auth,
318 			    fms[0], fms[1], fms[2], &nerr);
319 	}
320 
321 	topo_mod_free(mod, chipmap, BT_BITOUL(max) * sizeof (ulong_t));
322 
323 	if (nerr == 0) {
324 		return (0);
325 	} else {
326 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
327 		return (-1);
328 	}
329 }
330 
331 /*ARGSUSED*/
332 static int
333 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
334     topo_instance_t min, topo_instance_t max, void *arg, void *notused)
335 {
336 	int rv = 0;
337 	chip_t *chip = (chip_t *)arg;
338 	nvlist_t *auth = NULL;
339 	int intel_mc;
340 
341 	auth = topo_mod_auth(mod, pnode);
342 
343 	intel_mc = mc_offchip_open();
344 	if (strcmp(name, CHIP_NODE_NAME) == 0)
345 		rv = chip_create(mod, pnode, name, min, max, chip, auth);
346 
347 	if (intel_mc)
348 		(void) mc_offchip_create(mod, pnode, "memory-controller", auth);
349 
350 	nvlist_free(auth);
351 
352 	return (rv);
353 }
354