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 *
cpu_alloc(size_t size)35 cpu_alloc(size_t size)
36 {
37 return (umem_alloc(size, UMEM_DEFAULT));
38 }
39
40 static void
cpu_free(void * data,size_t size)41 cpu_free(void *data, size_t size)
42 {
43 umem_free(data, size);
44 }
45
46 md_proc_t *
cpu_find_proc(md_info_t * chip,uint32_t procid)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 *
cpu_find_cpumap(md_info_t * chip,uint32_t cpuid)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
cpu_get_serialid_mdesc(md_info_t * chip,uint32_t cpuid,uint64_t * serialidp)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
cpu_n1_mdesc_init(topo_mod_t * mod,md_t * mdp,md_info_t * chip)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
cpu_n2_mdesc_init(topo_mod_t * mod,md_t * mdp,md_info_t * chip)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
cpu_mdesc_init(topo_mod_t * mod,md_info_t * chip)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
cpu_mdesc_fini(topo_mod_t * mod,md_info_t * chip)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