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 <unistd.h> 28 #include <fcntl.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <stdarg.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <limits.h> 35 #include <alloca.h> 36 #include <kstat.h> 37 #include <errno.h> 38 #include <libnvpair.h> 39 #include <sys/types.h> 40 #include <sys/bitmap.h> 41 #include <sys/processor.h> 42 #include <sys/param.h> 43 #include <sys/fm/protocol.h> 44 #include <sys/systeminfo.h> 45 #include <sys/mc.h> 46 #include <sys/mc_amd.h> 47 #include <sys/mc_intel.h> 48 #include <sys/devfm.h> 49 #include <fm/fmd_agent.h> 50 #include <fm/topo_mod.h> 51 52 #include "chip.h" 53 54 #define MAX_DIMMNUM 7 55 #define MAX_CSNUM 7 56 57 /* 58 * Enumerates the processing chips, or sockets, (as distinct from cores) in a 59 * system. For each chip found, the necessary nodes (one or more cores, and 60 * possibly a memory controller) are constructed underneath. 61 */ 62 63 static int chip_enum(topo_mod_t *, tnode_t *, const char *, 64 topo_instance_t, topo_instance_t, void *, void *); 65 66 static const topo_modops_t chip_ops = 67 { chip_enum, NULL}; 68 static const topo_modinfo_t chip_info = 69 { CHIP_NODE_NAME, FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops }; 70 71 static const topo_pgroup_info_t chip_pgroup = 72 { PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 73 74 static const topo_pgroup_info_t core_pgroup = 75 { PGNAME(CORE), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 76 77 static const topo_pgroup_info_t strand_pgroup = 78 { PGNAME(STRAND), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 79 80 static const topo_method_t chip_methods[] = { 81 { SIMPLE_CHIP_LBL, "Property method", 0, 82 TOPO_STABILITY_INTERNAL, simple_chip_label}, 83 { G4_CHIP_LBL, "Property method", 0, 84 TOPO_STABILITY_INTERNAL, g4_chip_label}, 85 { A4FPLUS_CHIP_LBL, "Property method", 0, 86 TOPO_STABILITY_INTERNAL, a4fplus_chip_label}, 87 { FSB2_CHIP_LBL, "Property method", 0, 88 TOPO_STABILITY_INTERNAL, fsb2_chip_label}, 89 { NULL } 90 }; 91 92 static const topo_method_t strands_retire_methods[] = { 93 { TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC, 94 TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL, 95 retire_strands }, 96 { TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC, 97 TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL, 98 unretire_strands }, 99 { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC, 100 TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL, 101 service_state_strands }, 102 { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, 103 TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, 104 unusable_strands }, 105 { NULL } 106 }; 107 108 int 109 _topo_init(topo_mod_t *mod) 110 { 111 if (getenv("TOPOCHIPDBG")) 112 topo_mod_setdebug(mod); 113 topo_mod_dprintf(mod, "initializing chip enumerator\n"); 114 115 if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) { 116 whinge(mod, NULL, "failed to register hc: " 117 "%s\n", topo_mod_errmsg(mod)); 118 return (-1); /* mod errno set */ 119 } 120 121 return (0); 122 } 123 124 void 125 _topo_fini(topo_mod_t *mod) 126 { 127 topo_mod_unregister(mod); 128 } 129 130 boolean_t 131 is_xpv(void) 132 { 133 static int r = -1; 134 char platform[MAXNAMELEN]; 135 136 if (r != -1) 137 return (r == 0); 138 139 (void) sysinfo(SI_PLATFORM, platform, sizeof (platform)); 140 r = strcmp(platform, "i86xpv"); 141 return (r == 0); 142 } 143 144 static tnode_t * 145 create_node(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, char *name, 146 topo_instance_t inst) 147 { 148 nvlist_t *fmri; 149 tnode_t *cnode; 150 151 if (mkrsrc(mod, pnode, name, inst, auth, &fmri) != 0) { 152 whinge(mod, NULL, "create_node: mkrsrc failed\n"); 153 return (NULL); 154 } 155 cnode = topo_node_bind(mod, pnode, name, inst, fmri); 156 nvlist_free(fmri); 157 if (cnode == NULL) 158 whinge(mod, NULL, "create_node: node bind failed for %s %d\n", 159 name, (int)inst); 160 161 return (cnode); 162 } 163 164 static int 165 create_strand(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu, nvlist_t *auth) 166 { 167 tnode_t *strand; 168 int32_t strandid, cpuid; 169 int err, nerr = 0; 170 nvlist_t *fmri; 171 172 if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_STRAND_ID, 173 &strandid)) != 0) { 174 whinge(mod, NULL, "create_strand: lookup strand_id failed: " 175 "%s\n", strerror(err)); 176 return (-1); 177 } 178 179 if ((strand = topo_node_lookup(pnode, STRAND_NODE_NAME, strandid)) 180 != NULL) { 181 whinge(mod, NULL, "create_strand: duplicate tuple found\n"); 182 return (-1); 183 } 184 185 if ((strand = create_node(mod, pnode, auth, STRAND_NODE_NAME, 186 strandid)) == NULL) 187 return (-1); 188 189 /* 190 * Inherit FRU from core node, in native use cpu scheme ASRU, 191 * in xpv, use hc scheme ASRU. 192 */ 193 (void) topo_node_fru_set(strand, NULL, 0, &err); 194 if (is_xpv()) { 195 if (topo_node_resource(strand, &fmri, &err) == -1) { 196 whinge(mod, &nerr, "create_strand: " 197 "topo_node_resource failed\n"); 198 } else { 199 (void) topo_node_asru_set(strand, fmri, 0, &err); 200 nvlist_free(fmri); 201 } 202 } else { 203 if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) { 204 whinge(mod, &nerr, "create_strand: lookup cpuid " 205 "failed\n"); 206 } else { 207 if ((fmri = cpu_fmri_create(mod, cpuid, NULL, 0)) 208 != NULL) { 209 (void) topo_node_asru_set(strand, fmri, 210 0, &err); 211 nvlist_free(fmri); 212 } else { 213 whinge(mod, &nerr, "create_strand: " 214 "cpu_fmri_create() failed\n"); 215 } 216 } 217 } 218 219 if (topo_method_register(mod, strand, strands_retire_methods) < 0) 220 whinge(mod, &nerr, "create_strand: " 221 "topo_method_register failed\n"); 222 223 (void) topo_pgroup_create(strand, &strand_pgroup, &err); 224 nerr -= add_nvlist_longprops(mod, strand, cpu, PGNAME(STRAND), NULL, 225 STRAND_CHIP_ID, STRAND_CORE_ID, STRAND_CPU_ID, NULL); 226 227 return (err == 0 && nerr == 0 ? 0 : -1); 228 } 229 230 static int 231 create_core(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu, nvlist_t *auth) 232 { 233 tnode_t *core; 234 int32_t coreid, cpuid; 235 int err, nerr = 0; 236 nvlist_t *fmri; 237 238 if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CORE_ID, &coreid)) 239 != 0) { 240 whinge(mod, NULL, "create_core: lookup core_id failed: %s\n", 241 strerror(err)); 242 return (-1); 243 } 244 if ((core = topo_node_lookup(pnode, CORE_NODE_NAME, coreid)) == NULL) { 245 if ((core = create_node(mod, pnode, auth, CORE_NODE_NAME, 246 coreid)) == NULL) 247 return (-1); 248 249 /* 250 * Inherit FRU from the chip node, for native, we use hc 251 * scheme ASRU for the core node. 252 */ 253 (void) topo_node_fru_set(core, NULL, 0, &err); 254 if (is_xpv()) { 255 if (topo_node_resource(core, &fmri, &err) == -1) { 256 whinge(mod, &nerr, "create_core: " 257 "topo_node_resource failed\n"); 258 } else { 259 (void) topo_node_asru_set(core, fmri, 0, &err); 260 nvlist_free(fmri); 261 } 262 } 263 if (topo_method_register(mod, core, strands_retire_methods) < 0) 264 whinge(mod, &nerr, "create_core: " 265 "topo_method_register failed\n"); 266 267 (void) topo_pgroup_create(core, &core_pgroup, &err); 268 nerr -= add_nvlist_longprop(mod, core, cpu, PGNAME(CORE), 269 CORE_CHIP_ID, NULL); 270 271 if (topo_node_range_create(mod, core, STRAND_NODE_NAME, 272 0, 255) != 0) 273 return (-1); 274 } 275 276 if (! is_xpv()) { 277 /* 278 * In native mode, we're in favor of cpu scheme ASRU for 279 * printing reason. More work needs to be done to support 280 * multi-strand cpu: the ASRU will be a list of cpuid then. 281 */ 282 if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) { 283 whinge(mod, &nerr, "create_core: lookup cpuid " 284 "failed\n"); 285 } else { 286 if ((fmri = cpu_fmri_create(mod, cpuid, NULL, 0)) 287 != NULL) { 288 (void) topo_node_asru_set(core, fmri, 0, &err); 289 nvlist_free(fmri); 290 } else { 291 whinge(mod, &nerr, "create_core: " 292 "cpu_fmri_create() failed\n"); 293 } 294 } 295 } 296 297 err = create_strand(mod, core, cpu, auth); 298 299 return (err == 0 && nerr == 0 ? 0 : -1); 300 } 301 302 static int 303 create_chip(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min, 304 topo_instance_t max, nvlist_t *cpu, nvlist_t *auth, 305 int mc_offchip) 306 { 307 tnode_t *chip; 308 int32_t chipid; 309 nvlist_t *fmri = NULL; 310 int err, nerr = 0; 311 int32_t fms[3]; 312 const char *vendor; 313 boolean_t create_mc = B_FALSE; 314 315 if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CHIP_ID, &chipid)) 316 != 0) { 317 whinge(mod, NULL, "create_chip: lookup chip_id failed: %s\n", 318 strerror(err)); 319 return (-1); 320 } 321 322 if (chipid < min || chipid > max) 323 return (-1); 324 325 if ((chip = topo_node_lookup(pnode, CHIP_NODE_NAME, chipid)) == NULL) { 326 if ((chip = create_node(mod, pnode, auth, CHIP_NODE_NAME, 327 chipid)) == NULL) 328 return (-1); 329 330 if (topo_method_register(mod, chip, chip_methods) < 0) 331 whinge(mod, &nerr, "create_chip: " 332 "topo_method_register failed\n"); 333 334 if (topo_node_resource(chip, &fmri, &err) == -1) { 335 whinge(mod, &nerr, "create_chip: " 336 "topo_node_resource failed\n"); 337 } else { 338 (void) topo_node_fru_set(chip, fmri, 0, &err); 339 nvlist_free(fmri); 340 } 341 342 (void) topo_pgroup_create(chip, &chip_pgroup, &err); 343 nerr -= add_nvlist_strprop(mod, chip, cpu, PGNAME(CHIP), 344 CHIP_VENDOR_ID, &vendor); 345 nerr -= add_nvlist_longprops(mod, chip, cpu, PGNAME(CHIP), 346 fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL); 347 348 if (topo_method_register(mod, chip, strands_retire_methods) < 0) 349 whinge(mod, &nerr, "create_chip: " 350 "topo_method_register failed\n"); 351 352 if (topo_node_range_create(mod, chip, CORE_NODE_NAME, 353 0, 255) != 0) 354 return (-1); 355 356 create_mc = B_TRUE; 357 } 358 359 err = create_core(mod, chip, cpu, auth); 360 361 /* 362 * Create memory-controller node under a chip for architectures 363 * that may have on-chip memory-controller(s). 364 */ 365 if (create_mc) { 366 if (strcmp(vendor, "AuthenticAMD") == 0) 367 amd_mc_create(mod, chip, MCT_NODE_NAME, auth, 368 fms[0], fms[1], fms[2], &nerr); 369 else if (!mc_offchip) 370 onchip_mc_create(mod, chip, MCT_NODE_NAME, auth); 371 } 372 373 return (err == 0 && nerr == 0 ? 0 : -1); 374 } 375 376 /*ARGSUSED*/ 377 static int 378 create_chips(topo_mod_t *mod, tnode_t *pnode, const char *name, 379 topo_instance_t min, topo_instance_t max, void *arg, nvlist_t *auth, 380 int mc_offchip) 381 { 382 fmd_agent_hdl_t *hdl; 383 nvlist_t **cpus; 384 int nerr = 0; 385 uint_t i, ncpu; 386 387 if (strcmp(name, CHIP_NODE_NAME) != 0) 388 return (0); 389 390 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) 391 return (-1); 392 if (fmd_agent_physcpu_info(hdl, &cpus, &ncpu) != 0) { 393 whinge(mod, NULL, "create_chip: fmd_agent_physcpu_info " 394 "failed: %s\n", fmd_agent_errmsg(hdl)); 395 fmd_agent_close(hdl); 396 return (-1); 397 } 398 fmd_agent_close(hdl); 399 400 for (i = 0; i < ncpu; i++) { 401 nerr -= create_chip(mod, pnode, min, max, cpus[i], auth, 402 mc_offchip); 403 nvlist_free(cpus[i]); 404 } 405 umem_free(cpus, sizeof (nvlist_t *) * ncpu); 406 407 if (nerr == 0) { 408 return (0); 409 } else { 410 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 411 return (-1); 412 } 413 } 414 415 /*ARGSUSED*/ 416 static int 417 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 418 topo_instance_t min, topo_instance_t max, void *arg, void *notused) 419 { 420 int rv = 0; 421 nvlist_t *auth = NULL; 422 int offchip_mc; 423 char buf[BUFSIZ]; 424 const char *dom0 = "control_d"; 425 426 /* 427 * Create nothing if we're running in domU. 428 */ 429 if (sysinfo(SI_PLATFORM, buf, sizeof (buf)) == -1) 430 return (-1); 431 432 if (strncmp(buf, "i86pc", sizeof (buf)) != 0 && 433 strncmp(buf, "i86xpv", sizeof (buf)) != 0) 434 return (0); 435 436 if (strncmp(buf, "i86xpv", sizeof (buf)) == 0) { 437 int fd = open("/dev/xen/domcaps", O_RDONLY); 438 439 if (fd != -1) { 440 if (read(fd, buf, sizeof (buf)) <= 0 || 441 strncmp(buf, dom0, strlen(dom0)) != 0) { 442 (void) close(fd); 443 return (0); 444 } 445 (void) close(fd); 446 } 447 } 448 449 auth = topo_mod_auth(mod, pnode); 450 451 offchip_mc = mc_offchip_open(); 452 if (strcmp(name, CHIP_NODE_NAME) == 0) 453 rv = create_chips(mod, pnode, name, min, max, NULL, auth, 454 offchip_mc); 455 456 if (offchip_mc) 457 (void) mc_offchip_create(mod, pnode, "memory-controller", auth); 458 459 nvlist_free(auth); 460 461 return (rv); 462 } 463