xref: /titanic_52/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu_mdesc.c (revision 6876da76f91687fee15a706830b990a2c0d55157)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <string.h>
28 #include <umem.h>
29 #include <sys/mdesc.h>
30 #include <sys/fm/ldom.h>
31 
32 #include <cpu_mdesc.h>
33 
34 static void *
35 cpu_alloc(size_t size)
36 {
37 	return (umem_alloc(size, UMEM_DEFAULT));
38 }
39 
40 static void
41 cpu_free(void *data, size_t size)
42 {
43 	umem_free(data, size);
44 }
45 
46 md_proc_t *
47 cpu_find_proc(md_info_t *chip, uint32_t procid) {
48 	int i;
49 	md_proc_t *procp;
50 
51 	/* search the processor based on the physical id */
52 	for (i = 0, procp = chip->procs; i < chip->nprocs; i++, procp++) {
53 		if (procp->serialno != 0 && procid == procp->id) {
54 			return (procp);
55 		}
56 	}
57 
58 	return (NULL);
59 }
60 
61 md_cpumap_t *
62 cpu_find_cpumap(md_info_t *chip, uint32_t cpuid) {
63 	int i;
64 	md_cpumap_t *mcmp;
65 
66 	for (i = 0, mcmp = chip->cpus; i < chip->ncpus; i++, mcmp++) {
67 		if (cpuid == mcmp->cpumap_pid) {
68 			return (mcmp);
69 		}
70 	}
71 	return (NULL);
72 }
73 
74 int
75 cpu_get_serialid_mdesc(md_info_t *chip, uint32_t cpuid, uint64_t *serialidp)
76 {
77 	md_cpumap_t *mcmp;
78 	if ((mcmp = cpu_find_cpumap(chip, cpuid)) != NULL) {
79 		*serialidp = mcmp->cpumap_serialno;
80 		return (0);
81 	}
82 	return (-1);
83 }
84 
85 static int
86 cpu_n1_mdesc_init(topo_mod_t *mod, md_t *mdp, md_info_t *chip)
87 {
88 	mde_cookie_t *listp;
89 	md_cpumap_t *mcmp;
90 	int i, num_nodes, idx;
91 	uint64_t x;
92 
93 	num_nodes = md_node_count(mdp);
94 	listp = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * num_nodes);
95 
96 	chip->ncpus = md_scan_dag(mdp,
97 	    MDE_INVAL_ELEM_COOKIE,
98 	    md_find_name(mdp, "cpu"),
99 	    md_find_name(mdp, "fwd"),
100 	    listp);
101 	topo_mod_dprintf(mod, "Found %d cpus\n", chip->ncpus);
102 
103 	chip->cpus = topo_mod_zalloc(mod, chip->ncpus * sizeof (md_cpumap_t));
104 	chip->nprocs = chip->ncpus;
105 	chip->procs = topo_mod_zalloc(mod, chip->nprocs * sizeof (md_proc_t));
106 
107 	for (idx = 0, mcmp = chip->cpus; idx < chip->ncpus; idx++, mcmp++) {
108 
109 		if (md_get_prop_val(mdp, listp[idx], MD_STR_ID, &x) < 0)
110 			x = (uint64_t)-1; /* invalid value */
111 		mcmp->cpumap_id = x;
112 
113 		if (md_get_prop_val(mdp, listp[idx], MD_STR_PID, &x) < 0)
114 			x = mcmp->cpumap_id;
115 		mcmp->cpumap_pid = x;
116 
117 		mcmp->cpumap_serialno = 0;
118 		mcmp->cpumap_chipidx = -1;
119 		if (md_get_prop_val(mdp, listp[idx], MD_STR_CPU_SERIAL,
120 		    &mcmp->cpumap_serialno) < 0) {
121 			continue;
122 		}
123 		if (mcmp->cpumap_serialno == 0) {
124 			continue;
125 		}
126 
127 		/*
128 		 * This PRI/MD has no indentity info. of the FRU and no
129 		 * physical proc id.
130 		 * Find if there is already an existing processor entry
131 		 * Assign procid based on the order found during reading
132 		 */
133 		for (i = 0; i < chip->nprocs &&
134 		    chip->procs[i].serialno != 0; i++) {
135 			if (mcmp->cpumap_serialno == chip->procs[i].serialno) {
136 				break;
137 			}
138 		}
139 		if (i < chip->nprocs) {
140 			mcmp->cpumap_chipidx = i;
141 			if (chip->procs[i].serialno == 0) {
142 				chip->procs[i].id = i;
143 				chip->procs[i].serialno = mcmp->cpumap_serialno;
144 				topo_mod_dprintf(mod,
145 				    "chip[%d] serial is %llx\n",
146 				    i, chip->procs[i].serialno);
147 			}
148 		}
149 
150 	}
151 
152 	topo_mod_free(mod, listp, sizeof (mde_cookie_t) * num_nodes);
153 
154 	return (0);
155 }
156 
157 static int
158 cpu_n2_mdesc_init(topo_mod_t *mod, md_t *mdp, md_info_t *chip)
159 {
160 	mde_cookie_t *list1p, *list2p;
161 	md_cpumap_t *mcmp;
162 	md_proc_t *procp;
163 	md_fru_t *frup;
164 	int i, j, cnt;
165 	int procid_flag = 0;
166 	int nnode, ncomp, nproc, ncpu;
167 	char *str = NULL;
168 	uint64_t x, sn;
169 	char *strserial, *end;
170 
171 	nnode = md_node_count(mdp);
172 	list1p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * nnode);
173 
174 	/* Count the number of processors and strands */
175 	ncomp = md_scan_dag(mdp,
176 	    MDE_INVAL_ELEM_COOKIE,
177 	    md_find_name(mdp, MD_STR_COMPONENT),
178 	    md_find_name(mdp, "fwd"),
179 	    list1p);
180 	if (ncomp <= 0) {
181 		topo_mod_dprintf(mod, "Component nodes not found\n");
182 		topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode);
183 		return (-1);
184 	}
185 	for (i = 0, nproc = 0, ncpu = 0; i < ncomp; i++) {
186 		if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 &&
187 		    str != NULL && strcmp(str, MD_STR_PROCESSOR) == 0) {
188 			nproc++;
189 			/* check if the physical id exists */
190 			if (md_get_prop_val(mdp, list1p[i], MD_STR_ID, &x)
191 			    == 0) {
192 				procid_flag = 1;
193 			}
194 		}
195 		if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 &&
196 		    str && strcmp(str, MD_STR_STRAND) == 0) {
197 			ncpu++;
198 		}
199 	}
200 	topo_mod_dprintf(mod, "Found %d procs and %d strands\n", nproc, ncpu);
201 	if (nproc == 0 || ncpu == 0) {
202 		topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode);
203 		return (-1);
204 	}
205 
206 	/* Alloc processors and strand entries */
207 	list2p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * 2 * ncpu);
208 	chip->nprocs = nproc;
209 	chip->procs = topo_mod_zalloc(mod, nproc * sizeof (md_proc_t));
210 	chip->ncpus = ncpu;
211 	chip->cpus = topo_mod_zalloc(mod, ncpu * sizeof (md_cpumap_t));
212 
213 	/* Visit each processor node */
214 	procp = chip->procs;
215 	mcmp = chip->cpus;
216 	for (i = 0, nproc = 0, ncpu = 0; i < ncomp; i++) {
217 		if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) < 0 ||
218 		    str == NULL || strcmp(str, MD_STR_PROCESSOR))
219 			continue;
220 		if (md_get_prop_val(mdp, list1p[i], MD_STR_SERIAL, &sn) < 0) {
221 			if (md_get_prop_str(mdp, list1p[i], MD_STR_SERIAL,
222 			    &strserial) < 0) {
223 				topo_mod_dprintf(mod,
224 				    "Failed to get the serial number of"
225 				    "proc[%d]\n", nproc);
226 				continue;
227 			} else {
228 				sn = (uint64_t)strtoull(strserial, &end, 16);
229 				if (strserial == end) {
230 					topo_mod_dprintf(mod,
231 					    "Failed to convert the serial "
232 					    "string to serial int of "
233 					    "proc[%d]\n", nproc);
234 					continue;
235 				}
236 			}
237 		}
238 		procp->serialno = sn;
239 
240 		/* Assign physical proc id */
241 		procp->id = -1;
242 		if (procid_flag) {
243 			if (md_get_prop_val(mdp, list1p[i], MD_STR_ID, &x)
244 			    == 0) {
245 				procp->id = x;
246 			}
247 		} else {
248 			procp->id = nproc;
249 		}
250 		topo_mod_dprintf(mod, "proc %d: sn=%llx, id=%d\n", nproc,
251 		    procp->serialno, procp->id);
252 
253 		/* Get all the strands below this proc */
254 		cnt = md_scan_dag(mdp,
255 		    list1p[i],
256 		    md_find_name(mdp, MD_STR_COMPONENT),
257 		    md_find_name(mdp, "fwd"),
258 		    list2p);
259 		topo_mod_dprintf(mod, "proc[%llx]: Found %d fwd components\n",
260 		    sn, cnt);
261 		if (cnt <= 0) {
262 			nproc++;
263 			procp++;
264 			continue;
265 		}
266 		for (j = 0; j < cnt; j++) {
267 			/* Consider only the strand nodes */
268 			if (md_get_prop_str(mdp, list2p[j], MD_STR_TYPE, &str)
269 			    < 0 || str == NULL || strcmp(str, MD_STR_STRAND))
270 				continue;
271 
272 			if (md_get_prop_val(mdp, list2p[j], MD_STR_ID, &x) < 0)
273 				x = (uint64_t)-1; /* invalid value */
274 			mcmp->cpumap_id = x;
275 
276 			if (md_get_prop_val(mdp, list2p[j], MD_STR_PID, &x) < 0)
277 				x = mcmp->cpumap_id;
278 			mcmp->cpumap_pid = x;
279 
280 			mcmp->cpumap_serialno = sn;
281 			mcmp->cpumap_chipidx = nproc;
282 			ncpu++;
283 			mcmp++;
284 		}
285 
286 		/*
287 		 * To get the fru of this proc, follow the back arc up to
288 		 * find the first node whose fru field is set
289 		 */
290 		cnt = md_scan_dag(mdp,
291 		    list1p[i],
292 		    md_find_name(mdp, MD_STR_COMPONENT),
293 		    md_find_name(mdp, "back"),
294 		    list2p);
295 		topo_mod_dprintf(mod, "proc[%d]: Found %d back components\n",
296 		    nproc, cnt);
297 		if (cnt <= 0) {
298 			nproc++;
299 			procp++;
300 			continue;
301 		}
302 		for (j = 0; j < cnt; j++) {
303 			/* test the fru field which must be positive number */
304 			if ((md_get_prop_val(mdp, list2p[j], MD_STR_FRU, &x)
305 			    == 0) && x > 0)
306 				break;
307 		}
308 		if (j < cnt) {
309 			/* Found the FRU node, get the fru identity */
310 			topo_mod_dprintf(mod, "proc[%d] sn=%llx has a fru %d\n",
311 			    nproc, procp->serialno, j);
312 			frup = topo_mod_zalloc(mod, sizeof (md_fru_t));
313 			procp->fru = frup;
314 			if (!md_get_prop_str(mdp, list2p[j], MD_STR_NAC, &str))
315 				frup->nac = topo_mod_strdup(mod, str);
316 			else
317 				frup->nac = topo_mod_strdup(mod, MD_FRU_DEF);
318 			if (!md_get_prop_str(mdp, list2p[j], MD_STR_PART, &str))
319 				frup->part = topo_mod_strdup(mod, str);
320 			if (!md_get_prop_str(mdp, list2p[j], MD_STR_SERIAL,
321 			    &str))
322 				frup->serial = topo_mod_strdup(mod, str);
323 			if (!md_get_prop_str(mdp, list2p[j], MD_STR_DASH, &str))
324 				frup->dash = topo_mod_strdup(mod, str);
325 		} else {
326 			topo_mod_dprintf(mod, "proc[%d] sn=%llx has no fru\n",
327 			    i, procp->serialno);
328 		}
329 
330 		nproc++;
331 		procp++;
332 	} /* for i */
333 
334 	topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode);
335 	topo_mod_free(mod, list2p, sizeof (mde_cookie_t) * 2*chip->ncpus);
336 
337 	return (0);
338 }
339 
340 /*
341  * Extract from the PRI the processor, strand and their fru identity
342  */
343 int
344 cpu_mdesc_init(topo_mod_t *mod, md_info_t *chip)
345 {
346 	int rc = -1;
347 	md_t *mdp;
348 	ssize_t bufsiz = 0;
349 	uint64_t *bufp;
350 	ldom_hdl_t *lhp;
351 	uint32_t type = 0;
352 
353 	/* get the PRI/MD */
354 	if ((lhp = ldom_init(cpu_alloc, cpu_free)) == NULL) {
355 		topo_mod_dprintf(mod, "ldom_init() failed\n");
356 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
357 	}
358 
359 	(void) ldom_get_type(lhp, &type);
360 	if ((type & LDOM_TYPE_CONTROL) != 0) {
361 		bufsiz = ldom_get_core_md(lhp, &bufp);
362 	} else {
363 		bufsiz = ldom_get_local_md(lhp, &bufp);
364 	}
365 	if (bufsiz <= 0) {
366 		topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
367 		ldom_fini(lhp);
368 		return (-1);
369 	}
370 
371 	if ((mdp = md_init_intern(bufp, cpu_alloc, cpu_free)) == NULL ||
372 	    md_node_count(mdp) <= 0) {
373 		cpu_free(bufp, (size_t)bufsiz);
374 		ldom_fini(lhp);
375 		return (-1);
376 	}
377 
378 	/*
379 	 * N1 MD contains cpu nodes while N2 MD contains component nodes.
380 	 */
381 	if (md_find_name(mdp, MD_STR_COMPONENT) != MDE_INVAL_STR_COOKIE) {
382 		rc = cpu_n2_mdesc_init(mod, mdp, chip);
383 	} else if (md_find_name(mdp, MD_STR_CPU) != MDE_INVAL_STR_COOKIE) {
384 		rc =  cpu_n1_mdesc_init(mod, mdp, chip);
385 	} else {
386 		topo_mod_dprintf(mod, "Unsupported PRI/MD\n");
387 		rc = -1;
388 	}
389 
390 	cpu_free(bufp, (size_t)bufsiz);
391 	(void) md_fini(mdp);
392 	ldom_fini(lhp);
393 
394 	return (rc);
395 }
396 
397 void
398 cpu_mdesc_fini(topo_mod_t *mod, md_info_t *chip)
399 {
400 	int i;
401 	md_proc_t *procp;
402 	md_fru_t *frup;
403 
404 	if (chip->cpus != NULL)
405 		topo_mod_free(mod, chip->cpus,
406 		    chip->ncpus * sizeof (md_cpumap_t));
407 
408 	if (chip->procs != NULL) {
409 		procp = chip->procs;
410 		for (i = 0; i < chip->nprocs; i++) {
411 			if ((frup = procp->fru) != NULL) {
412 				topo_mod_strfree(mod, frup->nac);
413 				topo_mod_strfree(mod, frup->serial);
414 				topo_mod_strfree(mod, frup->part);
415 				topo_mod_strfree(mod, frup->dash);
416 				topo_mod_free(mod, frup, sizeof (md_fru_t));
417 			}
418 			procp++;
419 		}
420 		topo_mod_free(mod, chip->procs,
421 		    chip->nprocs * sizeof (md_proc_t));
422 	}
423 }
424