1*3325Ssd77468 /*
2*3325Ssd77468 * CDDL HEADER START
3*3325Ssd77468 *
4*3325Ssd77468 * The contents of this file are subject to the terms of the
5*3325Ssd77468 * Common Development and Distribution License (the "License").
6*3325Ssd77468 * You may not use this file except in compliance with the License.
7*3325Ssd77468 *
8*3325Ssd77468 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3325Ssd77468 * or http://www.opensolaris.org/os/licensing.
10*3325Ssd77468 * See the License for the specific language governing permissions
11*3325Ssd77468 * and limitations under the License.
12*3325Ssd77468 *
13*3325Ssd77468 * When distributing Covered Code, include this CDDL HEADER in each
14*3325Ssd77468 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3325Ssd77468 * If applicable, add the following below this CDDL HEADER, with the
16*3325Ssd77468 * fields enclosed by brackets "[]" replaced with your own identifying
17*3325Ssd77468 * information: Portions Copyright [yyyy] [name of copyright owner]
18*3325Ssd77468 *
19*3325Ssd77468 * CDDL HEADER END
20*3325Ssd77468 */
21*3325Ssd77468
22*3325Ssd77468 /*
23*3325Ssd77468 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24*3325Ssd77468 * Use is subject to license terms.
25*3325Ssd77468 */
26*3325Ssd77468
27*3325Ssd77468 #pragma ident "%Z%%M% %I% %E% SMI"
28*3325Ssd77468
29*3325Ssd77468 #include <unistd.h>
30*3325Ssd77468 #include <stdio.h>
31*3325Ssd77468 #include <stdlib.h>
32*3325Ssd77468 #include <string.h>
33*3325Ssd77468 #include <strings.h>
34*3325Ssd77468 #include <limits.h>
35*3325Ssd77468 #include <alloca.h>
36*3325Ssd77468 #include <kstat.h>
37*3325Ssd77468 #include <errno.h>
38*3325Ssd77468 #include <libnvpair.h>
39*3325Ssd77468 #include <sys/types.h>
40*3325Ssd77468 #include <sys/bitmap.h>
41*3325Ssd77468 #include <sys/processor.h>
42*3325Ssd77468 #include <sys/param.h>
43*3325Ssd77468 #include <sys/fm/protocol.h>
44*3325Ssd77468 #include <sys/systeminfo.h>
45*3325Ssd77468 #include <fm/topo_mod.h>
46*3325Ssd77468
47*3325Ssd77468 /*
48*3325Ssd77468 * Enumerates the processing chips, or sockets, (as distinct from cores) in a
49*3325Ssd77468 * system. For each chip found, the necessary nodes (one or more cores, and
50*3325Ssd77468 * possibly a memory controller) are constructed underneath.
51*3325Ssd77468 */
52*3325Ssd77468
53*3325Ssd77468 #ifdef __cplusplus
54*3325Ssd77468 extern "C" {
55*3325Ssd77468 #endif
56*3325Ssd77468
57*3325Ssd77468 #define CHIP_VERSION TOPO_VERSION
58*3325Ssd77468 #define CPU_NODE_NAME "cpu"
59*3325Ssd77468 #define CHIP_NODE_NAME "chip"
60*3325Ssd77468
61*3325Ssd77468 typedef struct chip {
62*3325Ssd77468 kstat_ctl_t *chip_kc;
63*3325Ssd77468 kstat_t **chip_cpustats;
64*3325Ssd77468 uint_t chip_ncpustats;
65*3325Ssd77468 } chip_t;
66*3325Ssd77468
67*3325Ssd77468 static int chip_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
68*3325Ssd77468 topo_instance_t, void *, void *);
69*3325Ssd77468
70*3325Ssd77468 static const topo_modops_t chip_ops =
71*3325Ssd77468 { chip_enum, NULL};
72*3325Ssd77468 static const topo_modinfo_t chip_info =
73*3325Ssd77468 { "chip", FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops };
74*3325Ssd77468
75*3325Ssd77468 int
_topo_init(topo_mod_t * mod)76*3325Ssd77468 _topo_init(topo_mod_t *mod)
77*3325Ssd77468 {
78*3325Ssd77468 chip_t *chip;
79*3325Ssd77468
80*3325Ssd77468 if (getenv("TOPOCHIPDBG"))
81*3325Ssd77468 topo_mod_setdebug(mod);
82*3325Ssd77468 topo_mod_dprintf(mod, "initializing chip enumerator\n");
83*3325Ssd77468
84*3325Ssd77468 if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL)
85*3325Ssd77468 return (-1);
86*3325Ssd77468
87*3325Ssd77468 if ((chip->chip_kc = kstat_open()) == NULL) {
88*3325Ssd77468 topo_mod_dprintf(mod, "kstat_open failed: %s\n",
89*3325Ssd77468 strerror(errno));
90*3325Ssd77468 topo_mod_free(mod, chip, sizeof (chip_t));
91*3325Ssd77468 return (-1);
92*3325Ssd77468 }
93*3325Ssd77468
94*3325Ssd77468 chip->chip_ncpustats = sysconf(_SC_CPUID_MAX);
95*3325Ssd77468 if ((chip->chip_cpustats = topo_mod_zalloc(mod, (
96*3325Ssd77468 chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) {
97*3325Ssd77468 (void) kstat_close(chip->chip_kc);
98*3325Ssd77468 topo_mod_free(mod, chip, sizeof (chip_t));
99*3325Ssd77468 return (-1);
100*3325Ssd77468 }
101*3325Ssd77468
102*3325Ssd77468 if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
103*3325Ssd77468 topo_mod_dprintf(mod, "failed to register hc: "
104*3325Ssd77468 "%s\n", topo_mod_errmsg(mod));
105*3325Ssd77468 topo_mod_free(mod, chip->chip_cpustats,
106*3325Ssd77468 (chip->chip_ncpustats + 1) * sizeof (kstat_t *));
107*3325Ssd77468 (void) kstat_close(chip->chip_kc);
108*3325Ssd77468 topo_mod_free(mod, chip, sizeof (chip_t));
109*3325Ssd77468 return (-1);
110*3325Ssd77468 }
111*3325Ssd77468 topo_mod_setspecific(mod, (void *)chip);
112*3325Ssd77468
113*3325Ssd77468 return (0);
114*3325Ssd77468 }
115*3325Ssd77468
116*3325Ssd77468 void
_topo_fini(topo_mod_t * mod)117*3325Ssd77468 _topo_fini(topo_mod_t *mod)
118*3325Ssd77468 {
119*3325Ssd77468 chip_t *chip;
120*3325Ssd77468
121*3325Ssd77468 chip = topo_mod_getspecific(mod);
122*3325Ssd77468
123*3325Ssd77468 if (chip->chip_cpustats != NULL)
124*3325Ssd77468 topo_mod_free(mod, chip->chip_cpustats,
125*3325Ssd77468 (chip->chip_ncpustats + 1) * sizeof (kstat_t *));
126*3325Ssd77468
127*3325Ssd77468 (void) kstat_close(chip->chip_kc);
128*3325Ssd77468 topo_mod_free(mod, chip, sizeof (chip_t));
129*3325Ssd77468
130*3325Ssd77468 topo_mod_unregister(mod);
131*3325Ssd77468 }
132*3325Ssd77468
133*3325Ssd77468 static int
cpu_kstat_init(chip_t * chip,int i)134*3325Ssd77468 cpu_kstat_init(chip_t *chip, int i)
135*3325Ssd77468 {
136*3325Ssd77468 kstat_t *ksp;
137*3325Ssd77468
138*3325Ssd77468 if (chip->chip_cpustats[i] == NULL) {
139*3325Ssd77468 if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) ==
140*3325Ssd77468 NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0)
141*3325Ssd77468 return (-1);
142*3325Ssd77468
143*3325Ssd77468 chip->chip_cpustats[i] = ksp;
144*3325Ssd77468 } else {
145*3325Ssd77468 ksp = chip->chip_cpustats[i];
146*3325Ssd77468 }
147*3325Ssd77468
148*3325Ssd77468 return (ksp->ks_instance);
149*3325Ssd77468 }
150*3325Ssd77468
151*3325Ssd77468 static nvlist_t *
cpu_fmri_create(topo_mod_t * mod,uint32_t cpuid,char * s,uint8_t cpumask)152*3325Ssd77468 cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *s, uint8_t cpumask)
153*3325Ssd77468 {
154*3325Ssd77468 int err;
155*3325Ssd77468 nvlist_t *asru;
156*3325Ssd77468
157*3325Ssd77468 if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0)
158*3325Ssd77468 return (NULL);
159*3325Ssd77468
160*3325Ssd77468 err = nvlist_add_uint8(asru, FM_VERSION, FM_CPU_SCHEME_VERSION);
161*3325Ssd77468 err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
162*3325Ssd77468 err |= nvlist_add_uint32(asru, FM_FMRI_CPU_ID, cpuid);
163*3325Ssd77468 err |= nvlist_add_uint8(asru, FM_FMRI_CPU_MASK, cpumask);
164*3325Ssd77468 if (s != NULL)
165*3325Ssd77468 err |= nvlist_add_string(asru, FM_FMRI_CPU_SERIAL_ID, s);
166*3325Ssd77468 if (err != 0) {
167*3325Ssd77468 nvlist_free(asru);
168*3325Ssd77468 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
169*3325Ssd77468 return (NULL);
170*3325Ssd77468 }
171*3325Ssd77468
172*3325Ssd77468 return (asru);
173*3325Ssd77468 }
174*3325Ssd77468
175*3325Ssd77468 /*ARGSUSED*/
176*3325Ssd77468 static int
cpu_create(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,chip_t * chip)177*3325Ssd77468 cpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name,
178*3325Ssd77468 topo_instance_t min, topo_instance_t max, chip_t *chip)
179*3325Ssd77468 {
180*3325Ssd77468 int i, err, chip_id, nerr = 0;
181*3325Ssd77468 char *s, sbuf[21];
182*3325Ssd77468 tnode_t *cnode;
183*3325Ssd77468 kstat_named_t *ks, *kf;
184*3325Ssd77468 nvlist_t *fmri, *asru;
185*3325Ssd77468 nvlist_t *auth = topo_mod_auth(mod, rnode);
186*3325Ssd77468
187*3325Ssd77468 /*
188*3325Ssd77468 * Override what was created for us
189*3325Ssd77468 */
190*3325Ssd77468 topo_node_range_destroy(rnode, name);
191*3325Ssd77468 if (topo_node_range_create(mod, rnode, name, 0, chip->chip_ncpustats)
192*3325Ssd77468 < 0)
193*3325Ssd77468 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
194*3325Ssd77468
195*3325Ssd77468 for (i = 0; i <= chip->chip_ncpustats; i++) {
196*3325Ssd77468
197*3325Ssd77468 if ((chip_id = cpu_kstat_init(chip, i)) < 0)
198*3325Ssd77468 continue;
199*3325Ssd77468
200*3325Ssd77468 if ((ks = kstat_data_lookup(chip->chip_cpustats[i],
201*3325Ssd77468 "device_ID")) != NULL) {
202*3325Ssd77468 (void) snprintf(sbuf, 21, "%llX", ks->value.ui64);
203*3325Ssd77468 s = sbuf;
204*3325Ssd77468 } else {
205*3325Ssd77468 s = NULL;
206*3325Ssd77468 }
207*3325Ssd77468
208*3325Ssd77468 fmri = topo_mod_hcfmri(mod, rnode, FM_HC_SCHEME_VERSION, name,
209*3325Ssd77468 (topo_instance_t)chip_id, NULL, auth, NULL, NULL, s);
210*3325Ssd77468 if (fmri == NULL || (cnode = topo_node_bind(mod,
211*3325Ssd77468 rnode, name, i, fmri)) == NULL) {
212*3325Ssd77468 ++nerr;
213*3325Ssd77468 nvlist_free(fmri);
214*3325Ssd77468 continue;
215*3325Ssd77468 }
216*3325Ssd77468 nvlist_free(fmri);
217*3325Ssd77468
218*3325Ssd77468 if ((asru = cpu_fmri_create(mod, i, s, 0)) != NULL) {
219*3325Ssd77468 (void) topo_node_asru_set(cnode, asru, 0, &err);
220*3325Ssd77468 nvlist_free(asru);
221*3325Ssd77468 } else {
222*3325Ssd77468 ++nerr;
223*3325Ssd77468 }
224*3325Ssd77468
225*3325Ssd77468 /*
226*3325Ssd77468 * We look for a cpu_fru kstat. If one is available and
227*3325Ssd77468 * it contains something useful, use it as the label and
228*3325Ssd77468 * and the FRU.
229*3325Ssd77468 *
230*3325Ssd77468 * This is a problem for platforms that do not properly
231*3325Ssd77468 * support the cpu_fru kstat like Ontario or if
232*3325Ssd77468 * we start exporting a different type of FRU label
233*3325Ssd77468 */
234*3325Ssd77468 if ((kf = kstat_data_lookup(chip->chip_cpustats[i], "cpu_fru"))
235*3325Ssd77468 != NULL && strcmp(KSTAT_NAMED_STR_PTR(kf),
236*3325Ssd77468 "hc:///component=") != 0) {
237*3325Ssd77468 nvlist_t *fru;
238*3325Ssd77468 char *lp;
239*3325Ssd77468
240*3325Ssd77468 if (topo_mod_str2nvl(mod, KSTAT_NAMED_STR_PTR(kf),
241*3325Ssd77468 &fru) == 0) {
242*3325Ssd77468 (void) topo_node_fru_set(cnode, fru, 0, &err);
243*3325Ssd77468 nvlist_free(fru);
244*3325Ssd77468 }
245*3325Ssd77468
246*3325Ssd77468 if ((lp = strchr(KSTAT_NAMED_STR_PTR(kf), '='))
247*3325Ssd77468 == NULL) {
248*3325Ssd77468 (void) topo_node_label_set(cnode, NULL, &err);
249*3325Ssd77468 } else {
250*3325Ssd77468 ++lp;
251*3325Ssd77468 (void) topo_node_label_set(cnode, lp, &err);
252*3325Ssd77468 }
253*3325Ssd77468 } else {
254*3325Ssd77468 (void) topo_node_label_set(cnode, NULL, &err);
255*3325Ssd77468 }
256*3325Ssd77468 }
257*3325Ssd77468
258*3325Ssd77468 nvlist_free(auth);
259*3325Ssd77468
260*3325Ssd77468 if (nerr != 0)
261*3325Ssd77468 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
262*3325Ssd77468 else
263*3325Ssd77468 return (0);
264*3325Ssd77468 }
265*3325Ssd77468
266*3325Ssd77468 /*ARGSUSED*/
267*3325Ssd77468 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)268*3325Ssd77468 chip_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
269*3325Ssd77468 topo_instance_t min, topo_instance_t max, void *arg, void *notused)
270*3325Ssd77468 {
271*3325Ssd77468 chip_t *chip = (chip_t *)arg;
272*3325Ssd77468
273*3325Ssd77468 if (strcmp(name, CPU_NODE_NAME) == 0)
274*3325Ssd77468 return (cpu_create(mod, rnode, name, min, max, chip));
275*3325Ssd77468
276*3325Ssd77468 return (0);
277*3325Ssd77468 }
278