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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
30 #include <sys/types.h>
31 #include <fm/topo_mod.h>
32 #include <fm/topo_hc.h>
33 #include <sys/fm/protocol.h>
36 #include <sys/param.h>
41 #include <cpu_mdesc.h>
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.
50 #define CHIP_VERSION TOPO_VERSION
51 #define CPU_NODE_NAME "cpu"
52 #define CHIP_NODE_NAME "chip"
54 extern topo_method_t pi_cpu_methods
[];
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
*);
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
};
67 static const topo_pgroup_info_t chip_auth_pgroup
= {
69 TOPO_STABILITY_PRIVATE
,
70 TOPO_STABILITY_PRIVATE
,
75 _topo_init(topo_mod_t
*mod
)
79 if (getenv("TOPOCHIPDBG"))
80 topo_mod_setdebug(mod
);
81 topo_mod_dprintf(mod
, "initializing chip enumerator\n");
83 if ((chip
= topo_mod_zalloc(mod
, sizeof (md_info_t
))) == NULL
)
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
));
92 topo_mod_setspecific(mod
, (void *)chip
);
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
));
102 topo_mod_dprintf(mod
, "chip enumerator inited\n");
108 _topo_fini(topo_mod_t
*mod
)
112 chip
= (md_info_t
*)topo_mod_getspecific(mod
);
114 cpu_mdesc_fini(mod
, chip
);
116 topo_mod_free(mod
, chip
, sizeof (md_info_t
));
118 topo_mod_unregister(mod
);
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
)
129 char *prod
= NULL
, *psn
= NULL
, *csn
= NULL
, *server
= NULL
;
130 nvlist_t
*auth
= NULL
;
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
,
137 topo_mod_strfree(mod
, prod
);
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
,
143 topo_mod_strfree(mod
, psn
);
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
,
149 topo_mod_strfree(mod
, server
);
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
,
155 topo_mod_strfree(mod
, csn
);
160 fmri
= topo_mod_hcfmri(mod
, parent
, FM_HC_SCHEME_VERSION
, name
, i
,
161 NULL
, auth
, NULL
, NULL
, serial
);
164 topo_mod_dprintf(mod
,
165 "Unable to make nvlist for %s bind: %s.\n",
166 name
, topo_mod_errmsg(mod
));
170 ntn
= topo_node_bind(mod
, parent
, name
, i
, fmri
);
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
),
176 topo_strerror(topo_mod_errno(mod
)));
181 topo_node_setspecific(ntn
, priv
);
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
);
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
);
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
));
209 cpu_fmri_create(topo_mod_t
*mod
, uint32_t cpuid
, char *serial
, uint8_t cpumask
)
214 if (topo_mod_nvalloc(mod
, &fmri
, NV_UNIQUE_NAME
) != 0)
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
);
221 err
|= nvlist_add_string(fmri
, FM_FMRI_CPU_SERIAL_ID
, serial
);
224 (void) topo_mod_seterrno(mod
, EMOD_FMRI_NVL
);
233 cpu_create(topo_mod_t
*mod
, tnode_t
*rnode
, const char *name
, md_info_t
*chip
,
247 topo_mod_dprintf(mod
, "enumerating cpus\n");
250 * find the min/max id of cpus per this cmp and create a cpu range
252 for (i
= 0, mcmp
= chip
->cpus
; i
< chip
->ncpus
; i
++, mcmp
++) {
253 if (mcmp
->cpumap_serialno
!= serial
)
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
;
260 if (min
< 0 || max
< 0) {
261 topo_mod_dprintf(mod
, "Invalid cpu range(%d,%d)\n", min
, max
);
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
));
270 (void) snprintf(sbuf
, sizeof (sbuf
), "%llx", serial
);
273 * Create the cpu[i] nodes of a given cmp i
275 for (i
= 0, mcmp
= chip
->cpus
; i
< chip
->ncpus
; i
++, mcmp
++) {
277 if (mcmp
->cpumap_serialno
== 0 ||
278 mcmp
->cpumap_serialno
!= serial
) {
283 pid
= mcmp
->cpumap_pid
;
284 cnode
= chip_tnode_create(mod
, rnode
, name
,
285 (topo_instance_t
)pid
, sbuf
, NULL
, NULL
, NULL
);
287 topo_mod_dprintf(mod
,
288 "failed to create a cpu=%d node: %s\n",
289 pid
, topo_mod_errmsg(mod
));
294 if ((asru
= cpu_fmri_create(mod
, pid
, sbuf
, 0)) != NULL
) {
295 (void) topo_node_asru_set(cnode
, asru
, 0, &err
);
303 (void) topo_mod_seterrno(mod
, EMOD_PARTIAL_ENUM
);
309 dimm_instantiate(tnode_t
*parent
, const char *name
, topo_mod_t
*mod
)
311 if (strcmp(name
, CHIP
) != 0) {
312 topo_mod_dprintf(mod
,
313 "Currently only know how to enumerate %s components.\n",
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
));
327 dimm_enum_load(topo_mod_t
*mp
)
329 topo_mod_t
*rp
= NULL
;
331 topo_mod_dprintf(mp
, "dimm_enum_load: %s\n", CHIP
);
332 if ((rp
= topo_mod_load(mp
, DIMM
, TOPO_VERSION
)) == NULL
) {
334 "%s enumerator could not load %s enum. (%d: %s)\n",
335 CHIP
, DIMM
, errno
, strerror(errno
));
337 topo_mod_dprintf(mp
, "dimm_enum_load(EXIT): %s, rp=%p\n", CHIP
, rp
);
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
)
351 nvlist_t
*fru
= NULL
;
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
);
361 if (dimm_enum_load(mod
) == NULL
)
365 * Create the chip[i] nodes, one for each CMP chip uniquely identified
366 * by the serial number.
368 for (i
= min
; i
<= max
; i
++) {
370 /* Skip the processors with no serial number */
371 if ((procp
= cpu_find_proc(chip
, i
)) == NULL
) {
374 if (procp
->serialno
== 0) {
378 (void) snprintf(sbuf
, sizeof (sbuf
), "%llx", procp
->serialno
);
379 topo_mod_dprintf(mod
, "node chip[%d], sn=%s\n", i
, sbuf
);
381 cnode
= chip_tnode_create(mod
, rnode
, name
, (topo_instance_t
)i
,
382 sbuf
, fru
, label
, NULL
);
384 topo_mod_dprintf(mod
, "failed to create a chip node: "
385 "%s\n", topo_mod_errmsg(mod
));
390 /* Enumerate all cpu strands of this CMP chip */
391 err
= cpu_create(mod
, cnode
, CPU_NODE_NAME
, chip
,
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
));
406 (void) topo_mod_seterrno(mod
, EMOD_PARTIAL_ENUM
);
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
)
416 md_info_t
*chip
= (md_info_t
*)arg
;
418 if (strcmp(name
, CHIP_NODE_NAME
) == 0)
419 return (chip_create(mod
, rnode
, name
, min
, max
, chip
));
426 chip_release(topo_mod_t
*mp
, tnode_t
*node
)