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 <stdio.h>
28 #include <stdlib.h>
29 #include <strings.h>
30 #include <sys/types.h>
31 #include <fm/topo_mod.h>
32 #include <fm/topo_hc.h>
33 #include <sys/fm/protocol.h>
34
35 #include <unistd.h>
36 #include <sys/param.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <umem.h>
40
41 #include <cpu_mdesc.h>
42
43
44 /*
45 * Enumerates the processing chips, or sockets, (as distinct from cores) in a
46 * system. For each chip found, the necessary nodes (one or more cores, and
47 * possibly a memory controller) are constructed underneath.
48 */
49
50 #define CHIP_VERSION TOPO_VERSION
51 #define CPU_NODE_NAME "cpu"
52 #define CHIP_NODE_NAME "chip"
53
54 extern topo_method_t pi_cpu_methods[];
55
56 /* Forward declaration */
57 static int chip_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
58 topo_instance_t, void *, void *);
59 static void chip_release(topo_mod_t *, tnode_t *);
60
61 static const topo_modops_t chip_ops =
62 { chip_enum, chip_release };
63 static const topo_modinfo_t chip_info =
64 { "chip", FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops };
65
66
67 static const topo_pgroup_info_t chip_auth_pgroup = {
68 FM_FMRI_AUTHORITY,
69 TOPO_STABILITY_PRIVATE,
70 TOPO_STABILITY_PRIVATE,
71 1
72 };
73
74 int
_topo_init(topo_mod_t * mod)75 _topo_init(topo_mod_t *mod)
76 {
77 md_info_t *chip;
78
79 if (getenv("TOPOCHIPDBG"))
80 topo_mod_setdebug(mod);
81 topo_mod_dprintf(mod, "initializing chip enumerator\n");
82
83 if ((chip = topo_mod_zalloc(mod, sizeof (md_info_t))) == NULL)
84 return (-1);
85
86 if (cpu_mdesc_init(mod, chip) != 0) {
87 topo_mod_dprintf(mod, "failed to get cpus from the PRI/MD\n");
88 topo_mod_free(mod, chip, sizeof (md_info_t));
89 return (-1);
90 }
91
92 topo_mod_setspecific(mod, (void *)chip);
93
94 if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
95 topo_mod_dprintf(mod, "failed to register hc: "
96 "%s\n", topo_mod_errmsg(mod));
97 cpu_mdesc_fini(mod, chip);
98 topo_mod_free(mod, chip, sizeof (md_info_t));
99 return (-1);
100 }
101
102 topo_mod_dprintf(mod, "chip enumerator inited\n");
103
104 return (0);
105 }
106
107 void
_topo_fini(topo_mod_t * mod)108 _topo_fini(topo_mod_t *mod)
109 {
110 md_info_t *chip;
111
112 chip = (md_info_t *)topo_mod_getspecific(mod);
113
114 cpu_mdesc_fini(mod, chip);
115
116 topo_mod_free(mod, chip, sizeof (md_info_t));
117
118 topo_mod_unregister(mod);
119 }
120
121 static tnode_t *
chip_tnode_create(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t i,char * serial,nvlist_t * fru,char * label,void * priv)122 chip_tnode_create(topo_mod_t *mod, tnode_t *parent,
123 const char *name, topo_instance_t i, char *serial,
124 nvlist_t *fru, char *label, void *priv)
125 {
126 int err;
127 nvlist_t *fmri;
128 tnode_t *ntn;
129 char *prod = NULL, *psn = NULL, *csn = NULL, *server = NULL;
130 nvlist_t *auth = NULL;
131
132 if (topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME) == 0) {
133 if (topo_prop_get_string(parent, FM_FMRI_AUTHORITY,
134 FM_FMRI_AUTH_PRODUCT, &prod, &err) == 0) {
135 (void) nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT,
136 prod);
137 topo_mod_strfree(mod, prod);
138 }
139 if (topo_prop_get_string(parent, FM_FMRI_AUTHORITY,
140 FM_FMRI_AUTH_PRODUCT_SN, &psn, &err) == 0) {
141 (void) nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN,
142 psn);
143 topo_mod_strfree(mod, psn);
144 }
145 if (topo_prop_get_string(parent, FM_FMRI_AUTHORITY,
146 FM_FMRI_AUTH_SERVER, &server, &err) == 0) {
147 (void) nvlist_add_string(auth, FM_FMRI_AUTH_SERVER,
148 server);
149 topo_mod_strfree(mod, server);
150 }
151 if (topo_prop_get_string(parent, FM_FMRI_AUTHORITY,
152 FM_FMRI_AUTH_CHASSIS, &csn, &err) == 0) {
153 (void) nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS,
154 csn);
155 topo_mod_strfree(mod, csn);
156 }
157 }
158
159
160 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i,
161 NULL, auth, NULL, NULL, serial);
162 nvlist_free(auth);
163 if (fmri == NULL) {
164 topo_mod_dprintf(mod,
165 "Unable to make nvlist for %s bind: %s.\n",
166 name, topo_mod_errmsg(mod));
167 return (NULL);
168 }
169
170 ntn = topo_node_bind(mod, parent, name, i, fmri);
171 if (ntn == NULL) {
172 topo_mod_dprintf(mod,
173 "topo_node_bind (%s%d/%s%d) failed: %s\n",
174 topo_node_name(parent), topo_node_instance(parent),
175 name, i,
176 topo_strerror(topo_mod_errno(mod)));
177 nvlist_free(fmri);
178 return (NULL);
179 }
180 nvlist_free(fmri);
181 topo_node_setspecific(ntn, priv);
182
183 if (topo_pgroup_create(ntn, &chip_auth_pgroup, &err) == 0) {
184 (void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
185 FM_FMRI_AUTH_PRODUCT, &err);
186 (void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
187 FM_FMRI_AUTH_PRODUCT_SN, &err);
188 (void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
189 FM_FMRI_AUTH_CHASSIS, &err);
190 (void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
191 FM_FMRI_AUTH_SERVER, &err);
192 }
193
194 /* Inherit the Label FRU fields from the parent */
195 (void) topo_node_label_set(ntn, label, &err);
196 (void) topo_node_fru_set(ntn, fru, 0, &err);
197
198 /* Register retire methods */
199 if (topo_method_register(mod, ntn, pi_cpu_methods) < 0)
200 topo_mod_dprintf(mod, "Unsable to register retire methods "
201 "for %s%d/%s%d: %s\n",
202 topo_node_name(parent), topo_node_instance(parent),
203 name, i, topo_mod_errmsg(mod));
204
205 return (ntn);
206 }
207
208 static nvlist_t *
cpu_fmri_create(topo_mod_t * mod,uint32_t cpuid,char * serial,uint8_t cpumask)209 cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *serial, uint8_t cpumask)
210 {
211 int err;
212 nvlist_t *fmri;
213
214 if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
215 return (NULL);
216 err = nvlist_add_uint8(fmri, FM_VERSION, FM_CPU_SCHEME_VERSION);
217 err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
218 err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpuid);
219 err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, cpumask);
220 if (serial != NULL)
221 err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, serial);
222 if (err != 0) {
223 nvlist_free(fmri);
224 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
225 return (NULL);
226 }
227
228 return (fmri);
229 }
230
231 /*ARGSUSED*/
232 static int
cpu_create(topo_mod_t * mod,tnode_t * rnode,const char * name,md_info_t * chip,uint64_t serial)233 cpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name, md_info_t *chip,
234 uint64_t serial)
235 {
236 int i;
237 int min = -1;
238 int max = -1;
239 int err;
240 int nerr = 0;
241 int pid;
242 char sbuf[32];
243 tnode_t *cnode;
244 nvlist_t *asru;
245 md_cpumap_t *mcmp;
246
247 topo_mod_dprintf(mod, "enumerating cpus\n");
248
249 /*
250 * find the min/max id of cpus per this cmp and create a cpu range
251 */
252 for (i = 0, mcmp = chip->cpus; i < chip->ncpus; i++, mcmp++) {
253 if (mcmp->cpumap_serialno != serial)
254 continue;
255 if ((min < 0) || (mcmp->cpumap_pid < min))
256 min = mcmp->cpumap_pid;
257 if ((max < 0) || (mcmp->cpumap_pid > max))
258 max = mcmp->cpumap_pid;
259 }
260 if (min < 0 || max < 0) {
261 topo_mod_dprintf(mod, "Invalid cpu range(%d,%d)\n", min, max);
262 return (-1);
263 }
264 if (topo_node_range_create(mod, rnode, name, 0, max+1) < 0) {
265 topo_mod_dprintf(mod, "failed to create cpu range[0,%d]: %s\n",
266 max, topo_mod_errmsg(mod));
267 return (-1);
268 }
269
270 (void) snprintf(sbuf, sizeof (sbuf), "%llx", serial);
271
272 /*
273 * Create the cpu[i] nodes of a given cmp i
274 */
275 for (i = 0, mcmp = chip->cpus; i < chip->ncpus; i++, mcmp++) {
276
277 if (mcmp->cpumap_serialno == 0 ||
278 mcmp->cpumap_serialno != serial) {
279 continue;
280 }
281
282 /* physical cpuid */
283 pid = mcmp->cpumap_pid;
284 cnode = chip_tnode_create(mod, rnode, name,
285 (topo_instance_t)pid, sbuf, NULL, NULL, NULL);
286 if (cnode == NULL) {
287 topo_mod_dprintf(mod,
288 "failed to create a cpu=%d node: %s\n",
289 pid, topo_mod_errmsg(mod));
290 nerr++;
291 continue;
292 }
293
294 if ((asru = cpu_fmri_create(mod, pid, sbuf, 0)) != NULL) {
295 (void) topo_node_asru_set(cnode, asru, 0, &err);
296 nvlist_free(asru);
297 } else {
298 nerr++;
299 }
300 }
301
302 if (nerr != 0)
303 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
304
305 return (0);
306 }
307
308 static int
dimm_instantiate(tnode_t * parent,const char * name,topo_mod_t * mod)309 dimm_instantiate(tnode_t *parent, const char *name, topo_mod_t *mod)
310 {
311 if (strcmp(name, CHIP) != 0) {
312 topo_mod_dprintf(mod,
313 "Currently only know how to enumerate %s components.\n",
314 CHIP);
315 return (0);
316 }
317 topo_mod_dprintf(mod,
318 "Calling dimm_enum\n");
319 if (topo_mod_enumerate(mod,
320 parent, DIMM, DIMM, 0, 0, NULL) != 0) {
321 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
322 }
323 return (0);
324 }
325
326 static topo_mod_t *
dimm_enum_load(topo_mod_t * mp)327 dimm_enum_load(topo_mod_t *mp)
328 {
329 topo_mod_t *rp = NULL;
330
331 topo_mod_dprintf(mp, "dimm_enum_load: %s\n", CHIP);
332 if ((rp = topo_mod_load(mp, DIMM, TOPO_VERSION)) == NULL) {
333 topo_mod_dprintf(mp,
334 "%s enumerator could not load %s enum. (%d: %s)\n",
335 CHIP, DIMM, errno, strerror(errno));
336 }
337 topo_mod_dprintf(mp, "dimm_enum_load(EXIT): %s, rp=%p\n", CHIP, rp);
338 return (rp);
339 }
340
341 /*ARGSUSED*/
342 static int
chip_create(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,md_info_t * chip)343 chip_create(topo_mod_t *mod, tnode_t *rnode, const char *name,
344 topo_instance_t min, topo_instance_t max, md_info_t *chip)
345 {
346 int nerr = 0;
347 int err;
348 int i;
349 char sbuf[32];
350 tnode_t *cnode;
351 nvlist_t *fru = NULL;
352 char *label = NULL;
353 md_proc_t *procp;
354
355 topo_mod_dprintf(mod, "enumerating cmp chip\n");
356 if (min < 0 || max < 0 || min > max) {
357 topo_mod_dprintf(mod, "Invalid chip range(%d,%d)\n", min, max);
358 return (-1);
359 }
360
361 if (dimm_enum_load(mod) == NULL)
362 return (-1);
363
364 /*
365 * Create the chip[i] nodes, one for each CMP chip uniquely identified
366 * by the serial number.
367 */
368 for (i = min; i <= max; i++) {
369
370 /* Skip the processors with no serial number */
371 if ((procp = cpu_find_proc(chip, i)) == NULL) {
372 continue;
373 }
374 if (procp->serialno == 0) {
375 continue;
376 }
377
378 (void) snprintf(sbuf, sizeof (sbuf), "%llx", procp->serialno);
379 topo_mod_dprintf(mod, "node chip[%d], sn=%s\n", i, sbuf);
380
381 cnode = chip_tnode_create(mod, rnode, name, (topo_instance_t)i,
382 sbuf, fru, label, NULL);
383 if (cnode == NULL) {
384 topo_mod_dprintf(mod, "failed to create a chip node: "
385 "%s\n", topo_mod_errmsg(mod));
386 nerr++;
387 continue;
388 }
389
390 /* Enumerate all cpu strands of this CMP chip */
391 err = cpu_create(mod, cnode, CPU_NODE_NAME, chip,
392 procp->serialno);
393 if (err != 0) {
394 nerr++;
395 }
396
397 /* Enumerate all DIMMs belonging to this chip */
398 if (dimm_instantiate(cnode, CHIP, mod) < 0) {
399 topo_mod_dprintf(mod, "Enumeration of dimm "
400 "failed %s\n", topo_mod_errmsg(mod));
401 return (-1);
402 }
403 }
404
405 if (nerr != 0)
406 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
407
408 return (0);
409 }
410
411 /*ARGSUSED*/
412 static int
chip_enum(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * notused)413 chip_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
414 topo_instance_t min, topo_instance_t max, void *arg, void *notused)
415 {
416 md_info_t *chip = (md_info_t *)arg;
417
418 if (strcmp(name, CHIP_NODE_NAME) == 0)
419 return (chip_create(mod, rnode, name, min, max, chip));
420
421 return (0);
422 }
423
424 /*ARGSUSED*/
425 static void
chip_release(topo_mod_t * mp,tnode_t * node)426 chip_release(topo_mod_t *mp, tnode_t *node)
427 {
428 }
429