xref: /onnv-gate/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu.c (revision 3670:6338278a5e69)
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 <stdio.h>
30 #include <strings.h>
31 #include <umem.h>
32 #include <sys/types.h>
33 #include <sys/mdesc.h>
34 #include <sys/fm/ldom.h>
35 #include <fm/topo_mod.h>
36 #include <sys/fm/protocol.h>
37 
38 /*
39  * Enumerates the cpu strands in a system. For each strand found, the
40  * necessary cpu-schemed nodes are constructed underneath.
41  */
42 
43 #define	PLATFORM_CPU_NAME	"platform-cpu"
44 #define	PLATFORM_CPU_VERSION	TOPO_VERSION
45 #define	CPU_NODE_NAME		"cpu"
46 
47 #define	MD_STR_CPU		"cpu"
48 #define	MD_STR_COMPONENT	"component"
49 #define	MD_STR_TYPE		"type"
50 #define	MD_STR_PROCESSOR	"processor"
51 #define	MD_STR_STRAND		"strand"
52 #define	MD_STR_SERIAL		"serial_number"
53 
54 typedef struct md_cpumap {
55 	uint32_t cpumap_id;		/* virtual cpuid */
56 	uint32_t cpumap_pid;		/* physical cpuid */
57 	uint64_t cpumap_serialno;	/* cpu serial number */
58 } md_cpumap_t;
59 
60 typedef struct chip {
61 	md_cpumap_t *chip_cpus;		/* List of cpu maps */
62 	uint32_t chip_ncpus;		/* size */
63 } chip_t;
64 
65 
66 /* Forward declaration */
67 static int cpu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
68     topo_instance_t, void *, void *);
69 static void cpu_release(topo_mod_t *, tnode_t *);
70 static int cpu_mdesc_init(topo_mod_t *mod, chip_t *chip);
71 
72 
73 static const topo_modops_t cpu_ops =
74 	{ cpu_enum, cpu_release };
75 static const topo_modinfo_t cpu_info =
76 	{ PLATFORM_CPU_NAME, FM_FMRI_SCHEME_CPU, PLATFORM_CPU_VERSION,
77 		&cpu_ops };
78 
79 
80 static void *
81 cpu_alloc(size_t size)
82 {
83 	return (umem_alloc(size, UMEM_DEFAULT));
84 }
85 
86 static void
87 cpu_free(void *data, size_t size)
88 {
89 	umem_free(data, size);
90 }
91 
92 int
93 _topo_init(topo_mod_t *mod)
94 {
95 	chip_t *chip;
96 
97 	if (getenv("TOPOPLATFORMCPUDBG"))
98 		topo_mod_setdebug(mod);
99 	topo_mod_dprintf(mod, "initializing %s enumerator\n",
100 			PLATFORM_CPU_NAME);
101 
102 	if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL)
103 		return (-1);
104 
105 	if (cpu_mdesc_init(mod, chip) != 0) {
106 		topo_mod_dprintf(mod, "failed to get cpus from the PRI/MD\n");
107 		topo_mod_free(mod, chip, sizeof (chip_t));
108 		return (-1);
109 	}
110 
111 	if (topo_mod_register(mod, &cpu_info, TOPO_VERSION) != 0) {
112 		topo_mod_dprintf(mod, "failed to register hc: "
113 		    "%s\n", topo_mod_errmsg(mod));
114 		topo_mod_free(mod, chip, sizeof (chip_t));
115 		return (-1);
116 	}
117 	topo_mod_setspecific(mod, (void *)chip);
118 
119 	topo_mod_dprintf(mod, "%s enumerator inited\n", PLATFORM_CPU_NAME);
120 
121 	return (0);
122 }
123 
124 void
125 _topo_fini(topo_mod_t *mod)
126 {
127 	chip_t *chip;
128 
129 	chip = (chip_t *)topo_mod_getspecific(mod);
130 
131 	if (chip->chip_cpus != NULL)
132 		topo_mod_free(mod, chip->chip_cpus,
133 			chip->chip_ncpus * sizeof (md_cpumap_t));
134 
135 	topo_mod_free(mod, chip, sizeof (chip_t));
136 
137 	topo_mod_unregister(mod);
138 
139 }
140 
141 static int
142 cpu_n1_mdesc_init(topo_mod_t *mod, md_t *mdp, chip_t *chip)
143 {
144 	mde_cookie_t *listp;
145 	md_cpumap_t *mcmp;
146 	int num_nodes, idx;
147 
148 	num_nodes = md_node_count(mdp);
149 	listp = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * num_nodes);
150 
151 	chip->chip_ncpus = md_scan_dag(mdp,
152 					MDE_INVAL_ELEM_COOKIE,
153 					md_find_name(mdp, "cpu"),
154 					md_find_name(mdp, "fwd"),
155 					listp);
156 	topo_mod_dprintf(mod, "Found %d cpus\n", chip->chip_ncpus);
157 
158 	chip->chip_cpus = topo_mod_zalloc(mod, chip->chip_ncpus *
159 	    sizeof (md_cpumap_t));
160 
161 	for (idx = 0, mcmp = chip->chip_cpus;
162 	    idx < chip->chip_ncpus;
163 	    idx++, mcmp++) {
164 		uint64_t tl;
165 
166 		if (md_get_prop_val(mdp, listp[idx], "id", &tl) < 0)
167 			tl = (uint64_t)-1; /* invalid value */
168 		mcmp->cpumap_id = tl;
169 
170 		if (md_get_prop_val(mdp, listp[idx], "pid", &tl) < 0)
171 			tl = mcmp->cpumap_id;
172 		mcmp->cpumap_pid = tl;
173 
174 		if (md_get_prop_val(mdp, listp[idx], "serial#",
175 		    &mcmp->cpumap_serialno) < 0)
176 			mcmp->cpumap_serialno = 0;
177 	}
178 
179 	topo_mod_free(mod, listp, sizeof (mde_cookie_t) * num_nodes);
180 
181 	return (0);
182 }
183 
184 static int
185 cpu_n2_mdesc_init(topo_mod_t *mod, md_t *mdp, chip_t *chip)
186 {
187 	mde_cookie_t *list1p, *list2p;
188 	md_cpumap_t *mcmp;
189 	int i, j;
190 	int nnode, ncomp, nproc, ncpu;
191 	char *str = NULL;
192 	uint64_t sn;
193 
194 	nnode = md_node_count(mdp);
195 	list1p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * nnode);
196 
197 	/* Count the number of strands */
198 	ncomp = md_scan_dag(mdp,
199 			MDE_INVAL_ELEM_COOKIE,
200 			md_find_name(mdp, MD_STR_COMPONENT),
201 			md_find_name(mdp, "fwd"),
202 			list1p);
203 	if (ncomp <= 0) {
204 		topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode);
205 		return (-1);
206 	}
207 	for (i = 0, ncpu = 0; i < ncomp; i++) {
208 		if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 &&
209 		    str && strcmp(str, MD_STR_STRAND) == 0) {
210 			ncpu++;
211 		}
212 	}
213 	topo_mod_dprintf(mod, "Found %d strands\n", ncpu);
214 	if (ncpu == 0) {
215 		topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode);
216 		return (-1);
217 	}
218 
219 	/* Alloc strand entries */
220 	list2p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * 2 * ncpu);
221 	chip->chip_ncpus = ncpu;
222 	chip->chip_cpus = topo_mod_zalloc(mod, ncpu * sizeof (md_cpumap_t));
223 
224 	/* Visit each processor node */
225 	mcmp = chip->chip_cpus;
226 	for (i = 0, nproc = 0; i < ncomp; i++) {
227 		if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) < 0 ||
228 		    str == NULL || strcmp(str, MD_STR_PROCESSOR))
229 			continue;
230 		if (md_get_prop_val(mdp, list1p[i], MD_STR_SERIAL, &sn) < 0) {
231 			topo_mod_dprintf(mod,
232 				"Failed to get the serial number of proc[%d]\n",
233 				nproc);
234 			continue;
235 		}
236 		nproc++;
237 
238 		/* Get all the strands below this proc */
239 		ncpu = md_scan_dag(mdp,
240 				list1p[i],
241 				md_find_name(mdp, MD_STR_COMPONENT),
242 				md_find_name(mdp, "fwd"),
243 				list2p);
244 		topo_mod_dprintf(mod, "proc[%llx]: Found %d components\n",
245 				sn, ncpu);
246 		if (ncpu <= 0) {
247 			continue;
248 		}
249 		for (j = 0; j < ncpu; j++) {
250 			uint64_t tl;
251 
252 			/* Consider only the strand nodes */
253 			if (md_get_prop_str(mdp, list2p[j], MD_STR_TYPE, &str)
254 			    < 0 || str == NULL || strcmp(str, MD_STR_STRAND))
255 				continue;
256 
257 			if (md_get_prop_val(mdp, list2p[j], "id", &tl) < 0)
258 				tl = (uint64_t)-1; /* invalid value */
259 			mcmp->cpumap_id = tl;
260 
261 			if (md_get_prop_val(mdp, list2p[j], "pid", &tl) < 0)
262 				tl = mcmp->cpumap_id;
263 			mcmp->cpumap_pid = tl;
264 
265 			mcmp->cpumap_serialno = sn;
266 			mcmp++;
267 		}
268 	}
269 
270 	topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode);
271 	topo_mod_free(mod, list2p, sizeof (mde_cookie_t) * 2*chip->chip_ncpus);
272 
273 	return (0);
274 }
275 
276 static int
277 cpu_mdesc_init(topo_mod_t *mod, chip_t *chip)
278 {
279 	int rc = -1;
280 	md_t *mdp;
281 	ssize_t bufsiz = 0;
282 	uint64_t *bufp;
283 	ldom_hdl_t *lhp;
284 
285 	/* get the PRI/MD */
286 	lhp = ldom_init(cpu_alloc, cpu_free);
287 	if ((lhp == NULL) || (bufsiz = ldom_get_core_md(lhp, &bufp)) <= 0) {
288 		topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
289 		return (-1);
290 	}
291 
292 	if ((mdp = md_init_intern(bufp, cpu_alloc, cpu_free)) == NULL ||
293 	    md_node_count(mdp) <= 0) {
294 		cpu_free(bufp, (size_t)bufsiz);
295 		ldom_fini(lhp);
296 		return (-1);
297 	}
298 
299 	/*
300 	 * N1 MD contains cpu nodes while N2 MD contains component nodes.
301 	 */
302 	if (md_find_name(mdp, MD_STR_COMPONENT) != MDE_INVAL_STR_COOKIE) {
303 		rc = cpu_n2_mdesc_init(mod, mdp, chip);
304 	} else if (md_find_name(mdp, MD_STR_CPU) != MDE_INVAL_STR_COOKIE) {
305 		rc =  cpu_n1_mdesc_init(mod, mdp, chip);
306 	} else {
307 		topo_mod_dprintf(mod, "Unsupported PRI/MD\n");
308 		rc = -1;
309 	}
310 
311 	cpu_free(bufp, (size_t)bufsiz);
312 	(void) md_fini(mdp);
313 	ldom_fini(lhp);
314 
315 	return (rc);
316 }
317 
318 static nvlist_t *
319 cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *serial, uint8_t cpumask)
320 {
321 	int err;
322 	nvlist_t *fmri;
323 
324 	if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
325 		return (NULL);
326 	err = nvlist_add_uint8(fmri, FM_VERSION, FM_CPU_SCHEME_VERSION);
327 	err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
328 	err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpuid);
329 	err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, cpumask);
330 	if (serial != NULL)
331 		err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, serial);
332 	if (err != 0) {
333 		nvlist_free(fmri);
334 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
335 		return (NULL);
336 	}
337 
338 	return (fmri);
339 }
340 
341 static tnode_t *
342 cpu_tnode_create(topo_mod_t *mod, tnode_t *parent,
343     const char *name, topo_instance_t i, char *serial, void *priv)
344 {
345 	int cpu_mask = 0;
346 	nvlist_t *fmri;
347 	tnode_t *ntn;
348 
349 	fmri = cpu_fmri_create(mod, i, serial, cpu_mask);
350 	if (fmri == NULL) {
351 		topo_mod_dprintf(mod,
352 		    "Unable to make nvlist for %s bind: %s.\n",
353 		    name, topo_mod_errmsg(mod));
354 		return (NULL);
355 	}
356 
357 	ntn = topo_node_bind(mod, parent, name, i, fmri);
358 	if (ntn == NULL) {
359 		topo_mod_dprintf(mod,
360 		    "topo_node_bind (%s%d/%s%d) failed: %s\n",
361 		    topo_node_name(parent), topo_node_instance(parent),
362 		    name, i,
363 		    topo_strerror(topo_mod_errno(mod)));
364 		nvlist_free(fmri);
365 		return (NULL);
366 	}
367 	nvlist_free(fmri);
368 	topo_node_setspecific(ntn, priv);
369 
370 	return (ntn);
371 }
372 
373 /*ARGSUSED*/
374 static int
375 cpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name, chip_t *chip)
376 {
377 	int i;
378 	int min = -1;
379 	int max = -1;
380 	int nerr = 0;
381 	int pid;
382 	char sbuf[32];
383 	tnode_t *cnode;
384 
385 	topo_mod_dprintf(mod, "enumerating cpus\n");
386 
387 	/*
388 	 * find the min/max id of cpus per this cmp and create a cpu range
389 	 */
390 	for (i = 0; i < chip->chip_ncpus; i++) {
391 		if ((min < 0) || (chip->chip_cpus[i].cpumap_pid < min))
392 			min = chip->chip_cpus[i].cpumap_pid;
393 		if ((max < 0) || (chip->chip_cpus[i].cpumap_pid > max))
394 			max = chip->chip_cpus[i].cpumap_pid;
395 	}
396 	if (min < 0 || max < 0)
397 		return (-1);
398 	topo_node_range_destroy(rnode, name);
399 	if (topo_node_range_create(mod, rnode, name, 0, max+1) < 0) {
400 		topo_mod_dprintf(mod, "failed to create cpu range[0,%d]: %s\n",
401 					max, topo_mod_errmsg(mod));
402 		return (-1);
403 	}
404 
405 	/*
406 	 * Create the cpu nodes
407 	 */
408 	for (i = 0; i < chip->chip_ncpus; i++) {
409 
410 		(void) snprintf(sbuf, sizeof (sbuf), "%llx",
411 			chip->chip_cpus[i].cpumap_serialno);
412 
413 		/* physical cpuid */
414 		pid = chip->chip_cpus[i].cpumap_pid;
415 		cnode = cpu_tnode_create(mod, rnode, name,
416 					(topo_instance_t)pid, sbuf, NULL);
417 		if (cnode == NULL) {
418 			topo_mod_dprintf(mod,
419 					"failed to create a cpu=%d node: %s\n",
420 					pid, topo_mod_errmsg(mod));
421 			nerr++;
422 			continue;
423 		}
424 
425 	}
426 
427 	if (nerr != 0)
428 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
429 
430 	return (0);
431 }
432 
433 /*ARGSUSED*/
434 static int
435 cpu_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
436     topo_instance_t min, topo_instance_t max, void *arg, void *notused)
437 {
438 	topo_mod_dprintf(mod, "%s enumerating %s\n", PLATFORM_CPU_NAME, name);
439 	if (strcmp(name, CPU_NODE_NAME) == 0)
440 		return (cpu_create(mod, rnode, name, (chip_t *)arg));
441 
442 	return (0);
443 }
444 
445 /*ARGSUSED*/
446 static void
447 cpu_release(topo_mod_t *mp, tnode_t *node)
448 {
449 }
450