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 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 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 * 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 * 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 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 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 * 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 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 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 426 chip_release(topo_mod_t *mp, tnode_t *node) 427 { 428 } 429