xref: /illumos-gate/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c (revision f6f4cb8ada400367a1921f6b93fb9e02f53ac5e6)
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 #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 	{ NULL }
88 };
89 
90 static const topo_method_t strands_retire_methods[] = {
91 	{ TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
92 	    TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
93 	    retire_strands },
94 	{ TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
95 	    TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
96 	    unretire_strands },
97 	{ TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
98 	    TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
99 	    service_state_strands },
100 	{ TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
101 	    TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
102 	    unusable_strands },
103 	{ NULL }
104 };
105 
106 int
107 _topo_init(topo_mod_t *mod)
108 {
109 	if (getenv("TOPOCHIPDBG"))
110 		topo_mod_setdebug(mod);
111 	topo_mod_dprintf(mod, "initializing chip enumerator\n");
112 
113 	if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
114 		whinge(mod, NULL, "failed to register hc: "
115 		    "%s\n", topo_mod_errmsg(mod));
116 		return (-1); /* mod errno set */
117 	}
118 
119 	return (0);
120 }
121 
122 void
123 _topo_fini(topo_mod_t *mod)
124 {
125 	topo_mod_unregister(mod);
126 }
127 
128 boolean_t
129 is_xpv(void)
130 {
131 	static int r = -1;
132 	char platform[MAXNAMELEN];
133 
134 	if (r != -1)
135 		return (r == 0);
136 
137 	(void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
138 	r = strcmp(platform, "i86xpv");
139 	return (r == 0);
140 }
141 
142 static tnode_t *
143 create_node(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, char *name,
144     topo_instance_t inst)
145 {
146 	nvlist_t *fmri;
147 	tnode_t *cnode;
148 
149 	if (mkrsrc(mod, pnode, name, inst, auth, &fmri) != 0) {
150 		whinge(mod, NULL, "create_node: mkrsrc failed\n");
151 		return (NULL);
152 	}
153 	cnode = topo_node_bind(mod, pnode, name, inst, fmri);
154 	nvlist_free(fmri);
155 	if (cnode == NULL)
156 		whinge(mod, NULL, "create_node: node bind failed for %s %d\n",
157 		    name, (int)inst);
158 
159 	return (cnode);
160 }
161 
162 static int
163 create_strand(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu, nvlist_t *auth)
164 {
165 	tnode_t *strand;
166 	int32_t strandid, cpuid;
167 	int err, nerr = 0;
168 	nvlist_t *fmri;
169 
170 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_STRAND_ID,
171 	    &strandid)) != 0) {
172 		whinge(mod, NULL, "create_strand: lookup strand_id failed: "
173 		    "%s\n", strerror(err));
174 		return (-1);
175 	}
176 
177 	if ((strand = topo_node_lookup(pnode, STRAND_NODE_NAME, strandid))
178 	    != NULL) {
179 		whinge(mod, NULL, "create_strand: duplicate tuple found\n");
180 		return (-1);
181 	}
182 
183 	if ((strand = create_node(mod, pnode, auth, STRAND_NODE_NAME,
184 	    strandid)) == NULL)
185 		return (-1);
186 
187 	/*
188 	 * Inherit FRU from core node, in native use cpu scheme ASRU,
189 	 * in xpv, use hc scheme ASRU.
190 	 */
191 	(void) topo_node_fru_set(strand, NULL, 0, &err);
192 	if (is_xpv()) {
193 		if (topo_node_resource(strand, &fmri, &err) == -1) {
194 			whinge(mod, &nerr, "create_strand: "
195 			    "topo_node_resource failed\n");
196 		} else {
197 			(void) topo_node_asru_set(strand, fmri, 0, &err);
198 			nvlist_free(fmri);
199 		}
200 	} else {
201 		if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
202 			whinge(mod, &nerr, "create_strand: lookup cpuid "
203 			    "failed\n");
204 		} else {
205 			if ((fmri = cpu_fmri_create(mod, cpuid, NULL, 0))
206 			    != NULL) {
207 				(void) topo_node_asru_set(strand, fmri,
208 				    0, &err);
209 				nvlist_free(fmri);
210 			} else {
211 				whinge(mod, &nerr, "create_strand: "
212 				    "cpu_fmri_create() failed\n");
213 			}
214 		}
215 	}
216 
217 	if (topo_method_register(mod, strand, strands_retire_methods) < 0)
218 		whinge(mod, &nerr, "create_strand: "
219 		    "topo_method_register failed\n");
220 
221 	(void) topo_pgroup_create(strand, &strand_pgroup, &err);
222 	nerr -= add_nvlist_longprops(mod, strand, cpu, PGNAME(STRAND), NULL,
223 	    STRAND_CHIP_ID, STRAND_CORE_ID, STRAND_CPU_ID, NULL);
224 
225 	return (err == 0 && nerr == 0 ? 0 : -1);
226 }
227 
228 static int
229 create_core(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu, nvlist_t *auth)
230 {
231 	tnode_t *core;
232 	int32_t coreid, cpuid;
233 	int err, nerr = 0;
234 	nvlist_t *fmri;
235 
236 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CORE_ID, &coreid))
237 	    != 0) {
238 		whinge(mod, NULL, "create_core: lookup core_id failed: %s\n",
239 		    strerror(err));
240 		return (-1);
241 	}
242 	if ((core = topo_node_lookup(pnode, CORE_NODE_NAME, coreid)) == NULL) {
243 		if ((core = create_node(mod, pnode, auth, CORE_NODE_NAME,
244 		    coreid)) == NULL)
245 			return (-1);
246 
247 		/*
248 		 * Inherit FRU from the chip node, for native, we use hc
249 		 * scheme ASRU for the core node.
250 		 */
251 		(void) topo_node_fru_set(core, NULL, 0, &err);
252 		if (is_xpv()) {
253 			if (topo_node_resource(core, &fmri, &err) == -1) {
254 				whinge(mod, &nerr, "create_core: "
255 				    "topo_node_resource failed\n");
256 			} else {
257 				(void) topo_node_asru_set(core, fmri, 0, &err);
258 				nvlist_free(fmri);
259 			}
260 		}
261 		if (topo_method_register(mod, core, strands_retire_methods) < 0)
262 			whinge(mod, &nerr, "create_core: "
263 			    "topo_method_register failed\n");
264 
265 		(void) topo_pgroup_create(core, &core_pgroup, &err);
266 		nerr -= add_nvlist_longprop(mod, core, cpu, PGNAME(CORE),
267 		    CORE_CHIP_ID, NULL);
268 
269 		if (topo_node_range_create(mod, core, STRAND_NODE_NAME,
270 		    0, 255) != 0)
271 			return (-1);
272 	}
273 
274 	if (! is_xpv()) {
275 		/*
276 		 * In native mode, we're in favor of cpu scheme ASRU for
277 		 * printing reason.  More work needs to be done to support
278 		 * multi-strand cpu: the ASRU will be a list of cpuid then.
279 		 */
280 		if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
281 			whinge(mod, &nerr, "create_core: lookup cpuid "
282 			    "failed\n");
283 		} else {
284 			if ((fmri = cpu_fmri_create(mod, cpuid, NULL, 0))
285 			    != NULL) {
286 				(void) topo_node_asru_set(core, fmri, 0, &err);
287 				nvlist_free(fmri);
288 			} else {
289 				whinge(mod, &nerr, "create_core: "
290 				    "cpu_fmri_create() failed\n");
291 			}
292 		}
293 	}
294 
295 	err = create_strand(mod, core, cpu, auth);
296 
297 	return (err == 0 && nerr == 0 ? 0 : -1);
298 }
299 
300 static int
301 create_chip(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
302     topo_instance_t max, nvlist_t *cpu, nvlist_t *auth,
303     int mc_offchip)
304 {
305 	tnode_t *chip;
306 	int32_t chipid;
307 	nvlist_t *fmri = NULL;
308 	int err, nerr = 0;
309 	int32_t fms[3];
310 	const char *vendor = NULL;
311 
312 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CHIP_ID, &chipid))
313 	    != 0) {
314 		whinge(mod, NULL, "create_chip: lookup chip_id failed: %s\n",
315 		    strerror(err));
316 		return (-1);
317 	}
318 
319 	if (chipid < min || chipid > max)
320 		return (-1);
321 
322 	if ((chip = topo_node_lookup(pnode, CHIP_NODE_NAME, chipid)) == NULL) {
323 		if ((chip = create_node(mod, pnode, auth, CHIP_NODE_NAME,
324 		    chipid)) == NULL)
325 			return (-1);
326 
327 		if (topo_method_register(mod, chip, chip_methods) < 0)
328 			whinge(mod, &nerr, "create_chip: "
329 			    "topo_method_register failed\n");
330 
331 		if (topo_node_resource(chip, &fmri, &err) == -1) {
332 			whinge(mod, &nerr, "create_chip: "
333 			    "topo_node_resource failed\n");
334 		} else {
335 			(void) topo_node_fru_set(chip, fmri, 0, &err);
336 			nvlist_free(fmri);
337 		}
338 
339 		(void) topo_pgroup_create(chip, &chip_pgroup, &err);
340 		nerr -= add_nvlist_strprop(mod, chip, cpu, PGNAME(CHIP),
341 		    CHIP_VENDOR_ID, &vendor);
342 		nerr -= add_nvlist_longprops(mod, chip, cpu, PGNAME(CHIP),
343 		    fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL);
344 
345 		if (topo_method_register(mod, chip, strands_retire_methods) < 0)
346 			whinge(mod, &nerr, "create_chip: "
347 			    "topo_method_register failed\n");
348 
349 		if (topo_node_range_create(mod, chip, CORE_NODE_NAME,
350 		    0, 255) != 0)
351 			return (-1);
352 	}
353 
354 	err = create_core(mod, chip, cpu, auth);
355 
356 	/*
357 	 * Create memory-controller node under a chip for architectures
358 	 * that may have on-chip memory-controller(s).
359 	 */
360 	if (vendor != NULL && strcmp(vendor, "AuthenticAMD") == 0)
361 		amd_mc_create(mod, chip, MCT_NODE_NAME, auth,
362 		    fms[0], fms[1], fms[2], &nerr);
363 	else if (!mc_offchip)
364 		onchip_mc_create(mod, chip, MCT_NODE_NAME, auth);
365 
366 	return (err == 0 && nerr == 0 ? 0 : -1);
367 }
368 
369 /*ARGSUSED*/
370 static int
371 create_chips(topo_mod_t *mod, tnode_t *pnode, const char *name,
372     topo_instance_t min, topo_instance_t max, void *arg, nvlist_t *auth,
373     int mc_offchip)
374 {
375 	fmd_agent_hdl_t *hdl;
376 	nvlist_t **cpus;
377 	int nerr = 0;
378 	uint_t i, ncpu;
379 
380 	if (strcmp(name, CHIP_NODE_NAME) != 0)
381 		return (0);
382 
383 	if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL)
384 		return (-1);
385 	if (fmd_agent_physcpu_info(hdl, &cpus, &ncpu) != 0) {
386 		whinge(mod, NULL, "create_chip: fmd_agent_physcpu_info "
387 		    "failed: %s\n", fmd_agent_errmsg(hdl));
388 		fmd_agent_close(hdl);
389 		return (-1);
390 	}
391 	fmd_agent_close(hdl);
392 
393 	for (i = 0; i < ncpu; i++) {
394 		nerr -= create_chip(mod, pnode, min, max, cpus[i], auth,
395 		    mc_offchip);
396 		nvlist_free(cpus[i]);
397 	}
398 	umem_free(cpus, sizeof (nvlist_t *) * ncpu);
399 
400 	if (nerr == 0) {
401 		return (0);
402 	} else {
403 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
404 		return (-1);
405 	}
406 }
407 
408 /*ARGSUSED*/
409 static int
410 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
411     topo_instance_t min, topo_instance_t max, void *arg, void *notused)
412 {
413 	int rv = 0;
414 	nvlist_t *auth = NULL;
415 	int offchip_mc;
416 	char buf[BUFSIZ];
417 	const char *dom0 = "control_d";
418 
419 	/*
420 	 * Create nothing if we're running in domU.
421 	 */
422 	if (sysinfo(SI_PLATFORM, buf, sizeof (buf)) == -1)
423 		return (-1);
424 
425 	if (strncmp(buf, "i86pc", sizeof (buf)) != 0 &&
426 	    strncmp(buf, "i86xpv", sizeof (buf)) != 0)
427 		return (0);
428 
429 	if (strncmp(buf, "i86xpv", sizeof (buf)) == 0) {
430 		int fd = open("/dev/xen/domcaps", O_RDONLY);
431 
432 		if (fd != -1) {
433 			if (read(fd, buf, sizeof (buf)) <= 0 ||
434 			    strncmp(buf, dom0, strlen(dom0)) != 0) {
435 				(void) close(fd);
436 				return (0);
437 			}
438 			(void) close(fd);
439 		}
440 	}
441 
442 	auth = topo_mod_auth(mod, pnode);
443 
444 	offchip_mc = mc_offchip_open();
445 	if (strcmp(name, CHIP_NODE_NAME) == 0)
446 		rv = create_chips(mod, pnode, name, min, max, NULL, auth,
447 		    offchip_mc);
448 
449 	if (offchip_mc)
450 		(void) mc_offchip_create(mod, pnode, "memory-controller", auth);
451 
452 	nvlist_free(auth);
453 
454 	return (rv);
455 }
456