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 #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 	{ A4FPLUS_CHIP_LBL, "Property method", 0,
81 	    TOPO_STABILITY_INTERNAL, a4fplus_chip_label},
82 	{ NULL }
83 };
84 
85 int
86 _topo_init(topo_mod_t *mod)
87 {
88 	chip_t *chip;
89 
90 	if (getenv("TOPOCHIPDBG"))
91 		topo_mod_setdebug(mod);
92 	topo_mod_dprintf(mod, "initializing chip enumerator\n");
93 
94 	if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL)
95 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
96 
97 	if ((chip->chip_kc = kstat_open()) == NULL) {
98 		whinge(mod, NULL, "kstat_open failed: %s\n",
99 		    strerror(errno));
100 		topo_mod_free(mod, chip, sizeof (chip_t));
101 		return (topo_mod_seterrno(mod, errno));
102 	}
103 
104 	chip->chip_ncpustats = sysconf(_SC_CPUID_MAX);
105 	if ((chip->chip_cpustats = topo_mod_zalloc(mod, (
106 	    chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) {
107 		(void) kstat_close(chip->chip_kc);
108 		topo_mod_free(mod, chip, sizeof (chip_t));
109 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
110 	}
111 
112 	if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
113 		whinge(mod, NULL, "failed to register hc: "
114 		    "%s\n", topo_mod_errmsg(mod));
115 		topo_mod_free(mod, chip->chip_cpustats,
116 		    (chip->chip_ncpustats + 1) * sizeof (kstat_t *));
117 		(void) kstat_close(chip->chip_kc);
118 		topo_mod_free(mod, chip, sizeof (chip_t));
119 		return (-1); /* mod errno set */
120 	}
121 	topo_mod_setspecific(mod, (void *)chip);
122 
123 	return (0);
124 }
125 
126 void
127 _topo_fini(topo_mod_t *mod)
128 {
129 	chip_t *chip = topo_mod_getspecific(mod);
130 
131 	if (chip->chip_cpustats != NULL)
132 		topo_mod_free(mod, chip->chip_cpustats,
133 		    (chip->chip_ncpustats + 1) * sizeof (kstat_t *));
134 
135 	(void) kstat_close(chip->chip_kc);
136 	topo_mod_free(mod, chip, sizeof (chip_t));
137 
138 	topo_mod_unregister(mod);
139 }
140 
141 static int
142 cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid,
143     chip_t *chip, nvlist_t *auth)
144 {
145 	kstat_named_t *k;
146 	nvlist_t *fmri, *asru;
147 	tnode_t *cnode;
148 	int err, nerr = 0;
149 	int clogid, cpuid;
150 
151 	if (topo_node_range_create(mod, pnode, name, 0,
152 	    chip->chip_ncpustats) < 0)
153 		return (-1);
154 
155 	for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) {
156 		if (chip->chip_cpustats[cpuid] == NULL)
157 			continue;
158 
159 		/*
160 		 * The chip_id in the cpu_info kstat numbers the individual
161 		 * chips from 0 to #chips - 1.
162 		 */
163 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
164 		    "chip_id")) == NULL) {
165 			whinge(mod, &nerr, "cpu_create: chip_id lookup via "
166 			    "kstats failed\n");
167 			continue;
168 		}
169 
170 		if (k->value.l != chipid)
171 			continue;	/* not an error */
172 
173 		/*
174 		 * The clog_id in the cpu_info kstat numbers the virtual
175 		 * processors of a single chip;  these may be separate
176 		 * processor cores, or they may be hardware threads/strands
177 		 * of individual cores.
178 		 *
179 		 * The core_id in the cpu_info kstat tells us which cpus
180 		 * share the same core - i.e., are hardware strands of the
181 		 * same core.  The core ids do not reset to zero for each
182 		 * distinct chip - they number across all cores of all chips.
183 		 * This enumerator does not distinguish stranded
184 		 * cores so core_id is unused.
185 		 */
186 		if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
187 		    "clog_id")) == NULL) {
188 			whinge(mod, &nerr, "cpu_create: clog_id lookup via "
189 			    "kstats failed\n");
190 			continue;
191 		}
192 		clogid = k->value.l;
193 
194 		if (mkrsrc(mod, pnode, name, clogid, auth, &fmri) != 0) {
195 			whinge(mod, &nerr, "cpu_create: mkrsrc failed\n");
196 			continue;
197 		}
198 
199 		if ((cnode = topo_node_bind(mod, pnode, name, clogid, fmri))
200 		    == NULL) {
201 			whinge(mod, &nerr, "cpu_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_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_pgroup, &err);
217 
218 		(void) topo_prop_set_uint32(cnode, PGNAME(CPU), "cpuid",
219 		    TOPO_PROP_IMMUTABLE, cpuid, &err);
220 
221 		if (add_kstat_longprops(mod, cnode, chip->chip_cpustats[cpuid],
222 		    PGNAME(CPU), NULL, CPU_CHIP_ID, CPU_CORE_ID, CPU_CLOG_ID,
223 		    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 chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
232     topo_instance_t min, topo_instance_t max, chip_t *chip, nvlist_t *auth)
233 {
234 	int i, nerr = 0;
235 	kstat_t *ksp;
236 	ulong_t *chipmap;
237 	tnode_t *cnode;
238 	nvlist_t *fmri;
239 
240 	if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(max) *
241 	    sizeof (ulong_t))) == NULL)
242 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
243 
244 	/*
245 	 * Read in all cpu_info kstats, for all chip ids.  The ks_instance
246 	 * argument to kstat_lookup is the logical cpu_id - we will use this
247 	 * in cpu_create.
248 	 */
249 	for (i = 0; i <= chip->chip_ncpustats; i++) {
250 		if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) ==
251 		    NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0)
252 			continue;
253 
254 		chip->chip_cpustats[i] = ksp;
255 	}
256 
257 	for (i = 0; i <= chip->chip_ncpustats; i++) {
258 		const char *vendor;
259 		int32_t fms[3];
260 		kstat_named_t *k;
261 		int err, chipid;
262 
263 		if ((ksp = chip->chip_cpustats[i]) == NULL)
264 			continue;
265 
266 		if ((k = kstat_data_lookup(ksp, "chip_id")) == NULL) {
267 			whinge(mod, &nerr, "chip_create: chip_id lookup "
268 			    "via kstats failed\n");
269 			continue;
270 		}
271 
272 		chipid = k->value.l;
273 		if (BT_TEST(chipmap, chipid))
274 			continue;
275 
276 		if (chipid < min || chipid > max)
277 			continue;
278 
279 		if (mkrsrc(mod, pnode, name, chipid, auth, &fmri) != 0) {
280 			whinge(mod, &nerr, "chip_create: mkrsrc failed\n");
281 			continue;
282 		}
283 
284 		if ((cnode = topo_node_bind(mod, pnode, name, chipid, fmri))
285 		    == NULL) {
286 			nvlist_free(fmri);
287 			whinge(mod, &nerr, "chip_create: node bind "
288 			    "failed for chipid %d\n", chipid);
289 			continue;
290 		}
291 		BT_SET(chipmap, chipid);
292 
293 		if (topo_method_register(mod, cnode, chip_methods) < 0)
294 			whinge(mod, &nerr, "chip_create: "
295 			    "topo_method_register failed");
296 
297 		(void) topo_node_fru_set(cnode, fmri, 0, &err);
298 
299 		nvlist_free(fmri);
300 
301 		(void) topo_pgroup_create(cnode, &chip_pgroup, &err);
302 		if (add_kstat_strprop(mod, cnode, ksp, PGNAME(CHIP),
303 		    CHIP_VENDOR_ID, &vendor) != 0)
304 			nerr++;		/* have whinged elsewhere */
305 
306 		if (add_kstat_longprops(mod, cnode, ksp, PGNAME(CHIP),
307 		    fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL) != 0)
308 			nerr++;		/* have whinged elsewhere */
309 
310 		if (cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip, auth)
311 		    != 0)
312 			nerr++;		/* have whinged elsewhere */
313 
314 		/*
315 		 * Create memory-controller node under a chip for architectures
316 		 * that may have on-chip memory-controller(s).
317 		 */
318 		if (strcmp(vendor, "AuthenticAMD") == 0)
319 			amd_mc_create(mod, cnode, MCT_NODE_NAME, auth,
320 			    fms[0], fms[1], fms[2], &nerr);
321 	}
322 
323 	topo_mod_free(mod, chipmap, BT_BITOUL(max) * sizeof (ulong_t));
324 
325 	if (nerr == 0) {
326 		return (0);
327 	} else {
328 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
329 		return (-1);
330 	}
331 }
332 
333 /*ARGSUSED*/
334 static int
335 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
336     topo_instance_t min, topo_instance_t max, void *arg, void *notused)
337 {
338 	int rv = 0;
339 	chip_t *chip = (chip_t *)arg;
340 	nvlist_t *auth = NULL;
341 	int intel_mc;
342 
343 	auth = topo_mod_auth(mod, pnode);
344 
345 	intel_mc = mc_offchip_open();
346 	if (strcmp(name, CHIP_NODE_NAME) == 0)
347 		rv = chip_create(mod, pnode, name, min, max, chip, auth);
348 
349 	if (intel_mc)
350 		(void) mc_offchip_create(mod, pnode, "memory-controller", auth);
351 
352 	nvlist_free(auth);
353 
354 	return (rv);
355 }
356