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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <unistd.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <stdarg.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <limits.h> 36 #include <alloca.h> 37 #include <kstat.h> 38 #include <errno.h> 39 #include <libnvpair.h> 40 #include <sys/types.h> 41 #include <sys/bitmap.h> 42 #include <sys/processor.h> 43 #include <sys/param.h> 44 #include <sys/fm/protocol.h> 45 #include <sys/systeminfo.h> 46 #include <sys/mc.h> 47 #include <sys/mc_amd.h> 48 #include <sys/mc_intel.h> 49 #include <fm/topo_mod.h> 50 51 #include "chip.h" 52 53 #define MAX_DIMMNUM 7 54 #define MAX_CSNUM 7 55 56 /* 57 * Enumerates the processing chips, or sockets, (as distinct from cores) in a 58 * system. For each chip found, the necessary nodes (one or more cores, and 59 * possibly a memory controller) are constructed underneath. 60 */ 61 62 static int chip_enum(topo_mod_t *, tnode_t *, const char *, 63 topo_instance_t, topo_instance_t, void *, void *); 64 65 static const topo_modops_t chip_ops = 66 { chip_enum, NULL}; 67 static const topo_modinfo_t chip_info = 68 { CHIP_NODE_NAME, FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops }; 69 70 static const topo_pgroup_info_t chip_pgroup = 71 { PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 72 static const topo_pgroup_info_t cpu_pgroup = 73 { PGNAME(CPU), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 74 75 static const topo_method_t chip_methods[] = { 76 { SIMPLE_CHIP_LBL, "Property method", 0, 77 TOPO_STABILITY_INTERNAL, simple_chip_label}, 78 { G4_CHIP_LBL, "Property method", 0, 79 TOPO_STABILITY_INTERNAL, g4_chip_label}, 80 { NULL } 81 }; 82 83 int 84 _topo_init(topo_mod_t *mod) 85 { 86 chip_t *chip; 87 88 if (getenv("TOPOCHIPDBG")) 89 topo_mod_setdebug(mod); 90 topo_mod_dprintf(mod, "initializing chip enumerator\n"); 91 92 if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL) 93 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 94 95 if ((chip->chip_kc = kstat_open()) == NULL) { 96 whinge(mod, NULL, "kstat_open failed: %s\n", 97 strerror(errno)); 98 topo_mod_free(mod, chip, sizeof (chip_t)); 99 return (topo_mod_seterrno(mod, errno)); 100 } 101 102 chip->chip_ncpustats = sysconf(_SC_CPUID_MAX); 103 if ((chip->chip_cpustats = topo_mod_zalloc(mod, ( 104 chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) { 105 (void) kstat_close(chip->chip_kc); 106 topo_mod_free(mod, chip, sizeof (chip_t)); 107 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 108 } 109 110 if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) { 111 whinge(mod, NULL, "failed to register hc: " 112 "%s\n", topo_mod_errmsg(mod)); 113 topo_mod_free(mod, chip->chip_cpustats, 114 (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 115 (void) kstat_close(chip->chip_kc); 116 topo_mod_free(mod, chip, sizeof (chip_t)); 117 return (-1); /* mod errno set */ 118 } 119 topo_mod_setspecific(mod, (void *)chip); 120 121 return (0); 122 } 123 124 void 125 _topo_fini(topo_mod_t *mod) 126 { 127 chip_t *chip = topo_mod_getspecific(mod); 128 129 if (chip->chip_cpustats != NULL) 130 topo_mod_free(mod, chip->chip_cpustats, 131 (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 132 133 (void) kstat_close(chip->chip_kc); 134 topo_mod_free(mod, chip, sizeof (chip_t)); 135 136 topo_mod_unregister(mod); 137 } 138 139 static int 140 cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid, 141 chip_t *chip, nvlist_t *auth) 142 { 143 kstat_named_t *k; 144 nvlist_t *fmri, *asru; 145 tnode_t *cnode; 146 int err, nerr = 0; 147 int clogid, cpuid; 148 149 if (topo_node_range_create(mod, pnode, name, 0, 150 chip->chip_ncpustats) < 0) 151 return (-1); 152 153 for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) { 154 if (chip->chip_cpustats[cpuid] == NULL) 155 continue; 156 157 /* 158 * The chip_id in the cpu_info kstat numbers the individual 159 * chips from 0 to #chips - 1. 160 */ 161 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 162 "chip_id")) == NULL) { 163 whinge(mod, &nerr, "cpu_create: chip_id lookup via " 164 "kstats failed\n"); 165 continue; 166 } 167 168 if (k->value.l != chipid) 169 continue; /* not an error */ 170 171 /* 172 * The clog_id in the cpu_info kstat numbers the virtual 173 * processors of a single chip; these may be separate 174 * processor cores, or they may be hardware threads/strands 175 * of individual cores. 176 * 177 * The core_id in the cpu_info kstat tells us which cpus 178 * share the same core - i.e., are hardware strands of the 179 * same core. The core ids do not reset to zero for each 180 * distinct chip - they number across all cores of all chips. 181 * This enumerator does not distinguish stranded 182 * cores so core_id is unused. 183 */ 184 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 185 "clog_id")) == NULL) { 186 whinge(mod, &nerr, "cpu_create: clog_id lookup via " 187 "kstats failed\n"); 188 continue; 189 } 190 clogid = k->value.l; 191 192 if (mkrsrc(mod, pnode, name, clogid, auth, &fmri) != 0) { 193 whinge(mod, &nerr, "cpu_create: mkrsrc failed\n"); 194 continue; 195 } 196 197 if ((cnode = topo_node_bind(mod, pnode, name, clogid, fmri)) 198 == NULL) { 199 whinge(mod, &nerr, "cpu_create: node bind failed\n"); 200 nvlist_free(fmri); 201 continue; 202 } 203 nvlist_free(fmri); 204 205 if ((asru = cpu_fmri_create(mod, cpuid, NULL, 0)) != NULL) { 206 (void) topo_node_asru_set(cnode, asru, 0, &err); 207 nvlist_free(asru); 208 } else { 209 whinge(mod, &nerr, "cpu_create: cpu_fmri_create " 210 "failed\n"); 211 } 212 (void) topo_node_fru_set(cnode, NULL, 0, &err); 213 214 (void) topo_pgroup_create(cnode, &cpu_pgroup, &err); 215 216 (void) topo_prop_set_uint32(cnode, PGNAME(CPU), "cpuid", 217 TOPO_PROP_IMMUTABLE, cpuid, &err); 218 219 if (add_kstat_longprops(mod, cnode, chip->chip_cpustats[cpuid], 220 PGNAME(CPU), NULL, CPU_CHIP_ID, CPU_CORE_ID, CPU_CLOG_ID, 221 NULL) != 0) 222 nerr++; /* have whinged elsewhere */ 223 } 224 225 return (nerr == 0 ? 0 : -1); 226 } 227 228 static int 229 chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 230 topo_instance_t min, topo_instance_t max, chip_t *chip, nvlist_t *auth) 231 { 232 int i, nerr = 0; 233 kstat_t *ksp; 234 ulong_t *chipmap; 235 tnode_t *cnode; 236 nvlist_t *fmri; 237 238 if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(max) * 239 sizeof (ulong_t))) == NULL) 240 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 241 242 /* 243 * Read in all cpu_info kstats, for all chip ids. The ks_instance 244 * argument to kstat_lookup is the logical cpu_id - we will use this 245 * in cpu_create. 246 */ 247 for (i = 0; i <= chip->chip_ncpustats; i++) { 248 if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) == 249 NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0) 250 continue; 251 252 chip->chip_cpustats[i] = ksp; 253 } 254 255 for (i = 0; i <= chip->chip_ncpustats; i++) { 256 const char *vendor; 257 int32_t fms[3]; 258 kstat_named_t *k; 259 int err, chipid; 260 261 if ((ksp = chip->chip_cpustats[i]) == NULL) 262 continue; 263 264 if ((k = kstat_data_lookup(ksp, "chip_id")) == NULL) { 265 whinge(mod, &nerr, "chip_create: chip_id lookup " 266 "via kstats failed\n"); 267 continue; 268 } 269 270 chipid = k->value.l; 271 if (BT_TEST(chipmap, chipid)) 272 continue; 273 274 if (chipid < min || chipid > max) 275 continue; 276 277 if (mkrsrc(mod, pnode, name, chipid, auth, &fmri) != 0) { 278 whinge(mod, &nerr, "chip_create: mkrsrc failed\n"); 279 continue; 280 } 281 282 if ((cnode = topo_node_bind(mod, pnode, name, chipid, fmri)) 283 == NULL) { 284 nvlist_free(fmri); 285 whinge(mod, &nerr, "chip_create: node bind " 286 "failed for chipid %d\n", chipid); 287 continue; 288 } 289 BT_SET(chipmap, chipid); 290 291 if (topo_method_register(mod, cnode, chip_methods) < 0) 292 whinge(mod, &nerr, "chip_create: " 293 "topo_method_register failed"); 294 295 (void) topo_node_fru_set(cnode, fmri, 0, &err); 296 297 nvlist_free(fmri); 298 299 (void) topo_pgroup_create(cnode, &chip_pgroup, &err); 300 if (add_kstat_strprop(mod, cnode, ksp, PGNAME(CHIP), 301 CHIP_VENDOR_ID, &vendor) != 0) 302 nerr++; /* have whinged elsewhere */ 303 304 if (add_kstat_longprops(mod, cnode, ksp, PGNAME(CHIP), 305 fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL) != 0) 306 nerr++; /* have whinged elsewhere */ 307 308 if (cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip, auth) 309 != 0) 310 nerr++; /* have whinged elsewhere */ 311 312 /* 313 * Create memory-controller node under a chip for architectures 314 * that may have on-chip memory-controller(s). 315 */ 316 if (strcmp(vendor, "AuthenticAMD") == 0) 317 amd_mc_create(mod, cnode, MCT_NODE_NAME, auth, 318 fms[0], fms[1], fms[2], &nerr); 319 } 320 321 topo_mod_free(mod, chipmap, BT_BITOUL(max) * sizeof (ulong_t)); 322 323 if (nerr == 0) { 324 return (0); 325 } else { 326 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 327 return (-1); 328 } 329 } 330 331 /*ARGSUSED*/ 332 static int 333 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 334 topo_instance_t min, topo_instance_t max, void *arg, void *notused) 335 { 336 int rv = 0; 337 chip_t *chip = (chip_t *)arg; 338 nvlist_t *auth = NULL; 339 int intel_mc; 340 341 auth = topo_mod_auth(mod, pnode); 342 343 intel_mc = mc_offchip_open(); 344 if (strcmp(name, CHIP_NODE_NAME) == 0) 345 rv = chip_create(mod, pnode, name, min, max, chip, auth); 346 347 if (intel_mc) 348 (void) mc_offchip_create(mod, pnode, "memory-controller", auth); 349 350 nvlist_free(auth); 351 352 return (rv); 353 } 354