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 2008 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 { A4FPLUS_CHIP_LBL, "Property method", 0, 81 TOPO_STABILITY_INTERNAL, a4fplus_chip_label}, 82 { NULL } 83 }; 84 85 int 86 _topo_init(topo_mod_t *mod) 87 { 88 chip_t *chip; 89 90 if (getenv("TOPOCHIPDBG")) 91 topo_mod_setdebug(mod); 92 topo_mod_dprintf(mod, "initializing chip enumerator\n"); 93 94 if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL) 95 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 96 97 if ((chip->chip_kc = kstat_open()) == NULL) { 98 whinge(mod, NULL, "kstat_open failed: %s\n", 99 strerror(errno)); 100 topo_mod_free(mod, chip, sizeof (chip_t)); 101 return (topo_mod_seterrno(mod, errno)); 102 } 103 104 chip->chip_ncpustats = sysconf(_SC_CPUID_MAX); 105 if ((chip->chip_cpustats = topo_mod_zalloc(mod, ( 106 chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) { 107 (void) kstat_close(chip->chip_kc); 108 topo_mod_free(mod, chip, sizeof (chip_t)); 109 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 110 } 111 112 if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) { 113 whinge(mod, NULL, "failed to register hc: " 114 "%s\n", topo_mod_errmsg(mod)); 115 topo_mod_free(mod, chip->chip_cpustats, 116 (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 117 (void) kstat_close(chip->chip_kc); 118 topo_mod_free(mod, chip, sizeof (chip_t)); 119 return (-1); /* mod errno set */ 120 } 121 topo_mod_setspecific(mod, (void *)chip); 122 123 return (0); 124 } 125 126 void 127 _topo_fini(topo_mod_t *mod) 128 { 129 chip_t *chip = topo_mod_getspecific(mod); 130 131 if (chip->chip_cpustats != NULL) 132 topo_mod_free(mod, chip->chip_cpustats, 133 (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 134 135 (void) kstat_close(chip->chip_kc); 136 topo_mod_free(mod, chip, sizeof (chip_t)); 137 138 topo_mod_unregister(mod); 139 } 140 141 static int 142 cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid, 143 chip_t *chip, nvlist_t *auth) 144 { 145 kstat_named_t *k; 146 nvlist_t *fmri, *asru; 147 tnode_t *cnode; 148 int err, nerr = 0; 149 int clogid, cpuid; 150 151 if (topo_node_range_create(mod, pnode, name, 0, 152 chip->chip_ncpustats) < 0) 153 return (-1); 154 155 for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) { 156 if (chip->chip_cpustats[cpuid] == NULL) 157 continue; 158 159 /* 160 * The chip_id in the cpu_info kstat numbers the individual 161 * chips from 0 to #chips - 1. 162 */ 163 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 164 "chip_id")) == NULL) { 165 whinge(mod, &nerr, "cpu_create: chip_id lookup via " 166 "kstats failed\n"); 167 continue; 168 } 169 170 if (k->value.l != chipid) 171 continue; /* not an error */ 172 173 /* 174 * The clog_id in the cpu_info kstat numbers the virtual 175 * processors of a single chip; these may be separate 176 * processor cores, or they may be hardware threads/strands 177 * of individual cores. 178 * 179 * The core_id in the cpu_info kstat tells us which cpus 180 * share the same core - i.e., are hardware strands of the 181 * same core. The core ids do not reset to zero for each 182 * distinct chip - they number across all cores of all chips. 183 * This enumerator does not distinguish stranded 184 * cores so core_id is unused. 185 */ 186 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 187 "clog_id")) == NULL) { 188 whinge(mod, &nerr, "cpu_create: clog_id lookup via " 189 "kstats failed\n"); 190 continue; 191 } 192 clogid = k->value.l; 193 194 if (mkrsrc(mod, pnode, name, clogid, auth, &fmri) != 0) { 195 whinge(mod, &nerr, "cpu_create: mkrsrc failed\n"); 196 continue; 197 } 198 199 if ((cnode = topo_node_bind(mod, pnode, name, clogid, fmri)) 200 == NULL) { 201 whinge(mod, &nerr, "cpu_create: node bind failed\n"); 202 nvlist_free(fmri); 203 continue; 204 } 205 nvlist_free(fmri); 206 207 if ((asru = cpu_fmri_create(mod, cpuid, NULL, 0)) != NULL) { 208 (void) topo_node_asru_set(cnode, asru, 0, &err); 209 nvlist_free(asru); 210 } else { 211 whinge(mod, &nerr, "cpu_create: cpu_fmri_create " 212 "failed\n"); 213 } 214 (void) topo_node_fru_set(cnode, NULL, 0, &err); 215 216 (void) topo_pgroup_create(cnode, &cpu_pgroup, &err); 217 218 (void) topo_prop_set_uint32(cnode, PGNAME(CPU), "cpuid", 219 TOPO_PROP_IMMUTABLE, cpuid, &err); 220 221 if (add_kstat_longprops(mod, cnode, chip->chip_cpustats[cpuid], 222 PGNAME(CPU), NULL, CPU_CHIP_ID, CPU_CORE_ID, CPU_CLOG_ID, 223 CPU_PKG_CORE_ID, NULL) != 0) 224 nerr++; /* have whinged elsewhere */ 225 } 226 227 return (nerr == 0 ? 0 : -1); 228 } 229 230 static int 231 chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 232 topo_instance_t min, topo_instance_t max, chip_t *chip, nvlist_t *auth) 233 { 234 int i, nerr = 0; 235 kstat_t *ksp; 236 ulong_t *chipmap; 237 tnode_t *cnode; 238 nvlist_t *fmri; 239 240 if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(max) * 241 sizeof (ulong_t))) == NULL) 242 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 243 244 /* 245 * Read in all cpu_info kstats, for all chip ids. The ks_instance 246 * argument to kstat_lookup is the logical cpu_id - we will use this 247 * in cpu_create. 248 */ 249 for (i = 0; i <= chip->chip_ncpustats; i++) { 250 if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) == 251 NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0) 252 continue; 253 254 chip->chip_cpustats[i] = ksp; 255 } 256 257 for (i = 0; i <= chip->chip_ncpustats; i++) { 258 const char *vendor; 259 int32_t fms[3]; 260 kstat_named_t *k; 261 int err, chipid; 262 263 if ((ksp = chip->chip_cpustats[i]) == NULL) 264 continue; 265 266 if ((k = kstat_data_lookup(ksp, "chip_id")) == NULL) { 267 whinge(mod, &nerr, "chip_create: chip_id lookup " 268 "via kstats failed\n"); 269 continue; 270 } 271 272 chipid = k->value.l; 273 if (BT_TEST(chipmap, chipid)) 274 continue; 275 276 if (chipid < min || chipid > max) 277 continue; 278 279 if (mkrsrc(mod, pnode, name, chipid, auth, &fmri) != 0) { 280 whinge(mod, &nerr, "chip_create: mkrsrc failed\n"); 281 continue; 282 } 283 284 if ((cnode = topo_node_bind(mod, pnode, name, chipid, fmri)) 285 == NULL) { 286 nvlist_free(fmri); 287 whinge(mod, &nerr, "chip_create: node bind " 288 "failed for chipid %d\n", chipid); 289 continue; 290 } 291 BT_SET(chipmap, chipid); 292 293 if (topo_method_register(mod, cnode, chip_methods) < 0) 294 whinge(mod, &nerr, "chip_create: " 295 "topo_method_register failed"); 296 297 (void) topo_node_fru_set(cnode, fmri, 0, &err); 298 299 nvlist_free(fmri); 300 301 (void) topo_pgroup_create(cnode, &chip_pgroup, &err); 302 if (add_kstat_strprop(mod, cnode, ksp, PGNAME(CHIP), 303 CHIP_VENDOR_ID, &vendor) != 0) 304 nerr++; /* have whinged elsewhere */ 305 306 if (add_kstat_longprops(mod, cnode, ksp, PGNAME(CHIP), 307 fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL) != 0) 308 nerr++; /* have whinged elsewhere */ 309 310 if (cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip, auth) 311 != 0) 312 nerr++; /* have whinged elsewhere */ 313 314 /* 315 * Create memory-controller node under a chip for architectures 316 * that may have on-chip memory-controller(s). 317 */ 318 if (strcmp(vendor, "AuthenticAMD") == 0) 319 amd_mc_create(mod, cnode, MCT_NODE_NAME, auth, 320 fms[0], fms[1], fms[2], &nerr); 321 } 322 323 topo_mod_free(mod, chipmap, BT_BITOUL(max) * sizeof (ulong_t)); 324 325 if (nerr == 0) { 326 return (0); 327 } else { 328 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 329 return (-1); 330 } 331 } 332 333 /*ARGSUSED*/ 334 static int 335 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 336 topo_instance_t min, topo_instance_t max, void *arg, void *notused) 337 { 338 int rv = 0; 339 chip_t *chip = (chip_t *)arg; 340 nvlist_t *auth = NULL; 341 int intel_mc; 342 343 auth = topo_mod_auth(mod, pnode); 344 345 intel_mc = mc_offchip_open(); 346 if (strcmp(name, CHIP_NODE_NAME) == 0) 347 rv = chip_create(mod, pnode, name, min, max, chip, auth); 348 349 if (intel_mc) 350 (void) mc_offchip_create(mod, pnode, "memory-controller", auth); 351 352 nvlist_free(auth); 353 354 return (rv); 355 } 356