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 <stdio.h> 30 #include <strings.h> 31 #include <umem.h> 32 #include <sys/types.h> 33 #include <sys/mdesc.h> 34 #include <sys/fm/ldom.h> 35 #include <fm/topo_mod.h> 36 #include <sys/fm/protocol.h> 37 38 /* 39 * Enumerates the cpu strands in a system. For each strand found, the 40 * necessary cpu-schemed nodes are constructed underneath. 41 */ 42 43 #define PLATFORM_CPU_NAME "platform-cpu" 44 #define PLATFORM_CPU_VERSION TOPO_VERSION 45 #define CPU_NODE_NAME "cpu" 46 47 #define MD_STR_CPU "cpu" 48 #define MD_STR_COMPONENT "component" 49 #define MD_STR_TYPE "type" 50 #define MD_STR_PROCESSOR "processor" 51 #define MD_STR_STRAND "strand" 52 #define MD_STR_SERIAL "serial_number" 53 54 typedef struct md_cpumap { 55 uint32_t cpumap_id; /* virtual cpuid */ 56 uint32_t cpumap_pid; /* physical cpuid */ 57 uint64_t cpumap_serialno; /* cpu serial number */ 58 } md_cpumap_t; 59 60 typedef struct chip { 61 md_cpumap_t *chip_cpus; /* List of cpu maps */ 62 uint32_t chip_ncpus; /* size */ 63 } chip_t; 64 65 66 /* Forward declaration */ 67 static int cpu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 68 topo_instance_t, void *, void *); 69 static void cpu_release(topo_mod_t *, tnode_t *); 70 static int cpu_mdesc_init(topo_mod_t *mod, chip_t *chip); 71 72 73 static const topo_modops_t cpu_ops = 74 { cpu_enum, cpu_release }; 75 static const topo_modinfo_t cpu_info = 76 { PLATFORM_CPU_NAME, FM_FMRI_SCHEME_CPU, PLATFORM_CPU_VERSION, 77 &cpu_ops }; 78 79 80 static void * 81 cpu_alloc(size_t size) 82 { 83 return (umem_alloc(size, UMEM_DEFAULT)); 84 } 85 86 static void 87 cpu_free(void *data, size_t size) 88 { 89 umem_free(data, size); 90 } 91 92 int 93 _topo_init(topo_mod_t *mod) 94 { 95 chip_t *chip; 96 97 if (getenv("TOPOPLATFORMCPUDBG")) 98 topo_mod_setdebug(mod); 99 topo_mod_dprintf(mod, "initializing %s enumerator\n", 100 PLATFORM_CPU_NAME); 101 102 if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL) 103 return (-1); 104 105 if (cpu_mdesc_init(mod, chip) != 0) { 106 topo_mod_dprintf(mod, "failed to get cpus from the PRI/MD\n"); 107 topo_mod_free(mod, chip, sizeof (chip_t)); 108 return (-1); 109 } 110 111 if (topo_mod_register(mod, &cpu_info, TOPO_VERSION) != 0) { 112 topo_mod_dprintf(mod, "failed to register hc: " 113 "%s\n", topo_mod_errmsg(mod)); 114 topo_mod_free(mod, chip, sizeof (chip_t)); 115 return (-1); 116 } 117 topo_mod_setspecific(mod, (void *)chip); 118 119 topo_mod_dprintf(mod, "%s enumerator inited\n", PLATFORM_CPU_NAME); 120 121 return (0); 122 } 123 124 void 125 _topo_fini(topo_mod_t *mod) 126 { 127 chip_t *chip; 128 129 chip = (chip_t *)topo_mod_getspecific(mod); 130 131 if (chip->chip_cpus != NULL) 132 topo_mod_free(mod, chip->chip_cpus, 133 chip->chip_ncpus * sizeof (md_cpumap_t)); 134 135 topo_mod_free(mod, chip, sizeof (chip_t)); 136 137 topo_mod_unregister(mod); 138 139 } 140 141 static int 142 cpu_n1_mdesc_init(topo_mod_t *mod, md_t *mdp, chip_t *chip) 143 { 144 mde_cookie_t *listp; 145 md_cpumap_t *mcmp; 146 int num_nodes, idx; 147 148 num_nodes = md_node_count(mdp); 149 listp = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * num_nodes); 150 151 chip->chip_ncpus = md_scan_dag(mdp, 152 MDE_INVAL_ELEM_COOKIE, 153 md_find_name(mdp, "cpu"), 154 md_find_name(mdp, "fwd"), 155 listp); 156 topo_mod_dprintf(mod, "Found %d cpus\n", chip->chip_ncpus); 157 158 chip->chip_cpus = topo_mod_zalloc(mod, chip->chip_ncpus * 159 sizeof (md_cpumap_t)); 160 161 for (idx = 0, mcmp = chip->chip_cpus; 162 idx < chip->chip_ncpus; 163 idx++, mcmp++) { 164 uint64_t tl; 165 166 if (md_get_prop_val(mdp, listp[idx], "id", &tl) < 0) 167 tl = (uint64_t)-1; /* invalid value */ 168 mcmp->cpumap_id = tl; 169 170 if (md_get_prop_val(mdp, listp[idx], "pid", &tl) < 0) 171 tl = mcmp->cpumap_id; 172 mcmp->cpumap_pid = tl; 173 174 if (md_get_prop_val(mdp, listp[idx], "serial#", 175 &mcmp->cpumap_serialno) < 0) 176 mcmp->cpumap_serialno = 0; 177 } 178 179 topo_mod_free(mod, listp, sizeof (mde_cookie_t) * num_nodes); 180 181 return (0); 182 } 183 184 static int 185 cpu_n2_mdesc_init(topo_mod_t *mod, md_t *mdp, chip_t *chip) 186 { 187 mde_cookie_t *list1p, *list2p; 188 md_cpumap_t *mcmp; 189 int i, j; 190 int nnode, ncomp, nproc, ncpu; 191 char *str = NULL; 192 uint64_t sn; 193 194 nnode = md_node_count(mdp); 195 list1p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * nnode); 196 197 /* Count the number of strands */ 198 ncomp = md_scan_dag(mdp, 199 MDE_INVAL_ELEM_COOKIE, 200 md_find_name(mdp, MD_STR_COMPONENT), 201 md_find_name(mdp, "fwd"), 202 list1p); 203 if (ncomp <= 0) { 204 topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode); 205 return (-1); 206 } 207 for (i = 0, ncpu = 0; i < ncomp; i++) { 208 if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 && 209 str && strcmp(str, MD_STR_STRAND) == 0) { 210 ncpu++; 211 } 212 } 213 topo_mod_dprintf(mod, "Found %d strands\n", ncpu); 214 if (ncpu == 0) { 215 topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode); 216 return (-1); 217 } 218 219 /* Alloc strand entries */ 220 list2p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * 2 * ncpu); 221 chip->chip_ncpus = ncpu; 222 chip->chip_cpus = topo_mod_zalloc(mod, ncpu * sizeof (md_cpumap_t)); 223 224 /* Visit each processor node */ 225 mcmp = chip->chip_cpus; 226 for (i = 0, nproc = 0; i < ncomp; i++) { 227 if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) < 0 || 228 str == NULL || strcmp(str, MD_STR_PROCESSOR)) 229 continue; 230 if (md_get_prop_val(mdp, list1p[i], MD_STR_SERIAL, &sn) < 0) { 231 topo_mod_dprintf(mod, 232 "Failed to get the serial number of proc[%d]\n", 233 nproc); 234 continue; 235 } 236 nproc++; 237 238 /* Get all the strands below this proc */ 239 ncpu = md_scan_dag(mdp, 240 list1p[i], 241 md_find_name(mdp, MD_STR_COMPONENT), 242 md_find_name(mdp, "fwd"), 243 list2p); 244 topo_mod_dprintf(mod, "proc[%llx]: Found %d components\n", 245 sn, ncpu); 246 if (ncpu <= 0) { 247 continue; 248 } 249 for (j = 0; j < ncpu; j++) { 250 uint64_t tl; 251 252 /* Consider only the strand nodes */ 253 if (md_get_prop_str(mdp, list2p[j], MD_STR_TYPE, &str) 254 < 0 || str == NULL || strcmp(str, MD_STR_STRAND)) 255 continue; 256 257 if (md_get_prop_val(mdp, list2p[j], "id", &tl) < 0) 258 tl = (uint64_t)-1; /* invalid value */ 259 mcmp->cpumap_id = tl; 260 261 if (md_get_prop_val(mdp, list2p[j], "pid", &tl) < 0) 262 tl = mcmp->cpumap_id; 263 mcmp->cpumap_pid = tl; 264 265 mcmp->cpumap_serialno = sn; 266 mcmp++; 267 } 268 } 269 270 topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode); 271 topo_mod_free(mod, list2p, sizeof (mde_cookie_t) * 2*chip->chip_ncpus); 272 273 return (0); 274 } 275 276 static int 277 cpu_mdesc_init(topo_mod_t *mod, chip_t *chip) 278 { 279 int rc = -1; 280 md_t *mdp; 281 ssize_t bufsiz = 0; 282 uint64_t *bufp; 283 ldom_hdl_t *lhp; 284 285 /* get the PRI/MD */ 286 lhp = ldom_init(cpu_alloc, cpu_free); 287 if ((lhp == NULL) || (bufsiz = ldom_get_core_md(lhp, &bufp)) <= 0) { 288 topo_mod_dprintf(mod, "failed to get the PRI/MD\n"); 289 return (-1); 290 } 291 292 if ((mdp = md_init_intern(bufp, cpu_alloc, cpu_free)) == NULL || 293 md_node_count(mdp) <= 0) { 294 cpu_free(bufp, (size_t)bufsiz); 295 ldom_fini(lhp); 296 return (-1); 297 } 298 299 /* 300 * N1 MD contains cpu nodes while N2 MD contains component nodes. 301 */ 302 if (md_find_name(mdp, MD_STR_COMPONENT) != MDE_INVAL_STR_COOKIE) { 303 rc = cpu_n2_mdesc_init(mod, mdp, chip); 304 } else if (md_find_name(mdp, MD_STR_CPU) != MDE_INVAL_STR_COOKIE) { 305 rc = cpu_n1_mdesc_init(mod, mdp, chip); 306 } else { 307 topo_mod_dprintf(mod, "Unsupported PRI/MD\n"); 308 rc = -1; 309 } 310 311 cpu_free(bufp, (size_t)bufsiz); 312 (void) md_fini(mdp); 313 ldom_fini(lhp); 314 315 return (rc); 316 } 317 318 static nvlist_t * 319 cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *serial, uint8_t cpumask) 320 { 321 int err; 322 nvlist_t *fmri; 323 324 if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 325 return (NULL); 326 err = nvlist_add_uint8(fmri, FM_VERSION, FM_CPU_SCHEME_VERSION); 327 err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); 328 err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpuid); 329 err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, cpumask); 330 if (serial != NULL) 331 err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, serial); 332 if (err != 0) { 333 nvlist_free(fmri); 334 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); 335 return (NULL); 336 } 337 338 return (fmri); 339 } 340 341 static tnode_t * 342 cpu_tnode_create(topo_mod_t *mod, tnode_t *parent, 343 const char *name, topo_instance_t i, char *serial, void *priv) 344 { 345 int cpu_mask = 0; 346 nvlist_t *fmri; 347 tnode_t *ntn; 348 349 fmri = cpu_fmri_create(mod, i, serial, cpu_mask); 350 if (fmri == NULL) { 351 topo_mod_dprintf(mod, 352 "Unable to make nvlist for %s bind: %s.\n", 353 name, topo_mod_errmsg(mod)); 354 return (NULL); 355 } 356 357 ntn = topo_node_bind(mod, parent, name, i, fmri); 358 if (ntn == NULL) { 359 topo_mod_dprintf(mod, 360 "topo_node_bind (%s%d/%s%d) failed: %s\n", 361 topo_node_name(parent), topo_node_instance(parent), 362 name, i, 363 topo_strerror(topo_mod_errno(mod))); 364 nvlist_free(fmri); 365 return (NULL); 366 } 367 nvlist_free(fmri); 368 topo_node_setspecific(ntn, priv); 369 370 return (ntn); 371 } 372 373 /*ARGSUSED*/ 374 static int 375 cpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name, chip_t *chip) 376 { 377 int i; 378 int min = -1; 379 int max = -1; 380 int nerr = 0; 381 int pid; 382 char sbuf[32]; 383 tnode_t *cnode; 384 385 topo_mod_dprintf(mod, "enumerating cpus\n"); 386 387 /* 388 * find the min/max id of cpus per this cmp and create a cpu range 389 */ 390 for (i = 0; i < chip->chip_ncpus; i++) { 391 if ((min < 0) || (chip->chip_cpus[i].cpumap_pid < min)) 392 min = chip->chip_cpus[i].cpumap_pid; 393 if ((max < 0) || (chip->chip_cpus[i].cpumap_pid > max)) 394 max = chip->chip_cpus[i].cpumap_pid; 395 } 396 if (min < 0 || max < 0) 397 return (-1); 398 topo_node_range_destroy(rnode, name); 399 if (topo_node_range_create(mod, rnode, name, 0, max+1) < 0) { 400 topo_mod_dprintf(mod, "failed to create cpu range[0,%d]: %s\n", 401 max, topo_mod_errmsg(mod)); 402 return (-1); 403 } 404 405 /* 406 * Create the cpu nodes 407 */ 408 for (i = 0; i < chip->chip_ncpus; i++) { 409 410 (void) snprintf(sbuf, sizeof (sbuf), "%llx", 411 chip->chip_cpus[i].cpumap_serialno); 412 413 /* physical cpuid */ 414 pid = chip->chip_cpus[i].cpumap_pid; 415 cnode = cpu_tnode_create(mod, rnode, name, 416 (topo_instance_t)pid, sbuf, NULL); 417 if (cnode == NULL) { 418 topo_mod_dprintf(mod, 419 "failed to create a cpu=%d node: %s\n", 420 pid, topo_mod_errmsg(mod)); 421 nerr++; 422 continue; 423 } 424 425 } 426 427 if (nerr != 0) 428 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 429 430 return (0); 431 } 432 433 /*ARGSUSED*/ 434 static int 435 cpu_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, 436 topo_instance_t min, topo_instance_t max, void *arg, void *notused) 437 { 438 topo_mod_dprintf(mod, "%s enumerating %s\n", PLATFORM_CPU_NAME, name); 439 if (strcmp(name, CPU_NODE_NAME) == 0) 440 return (cpu_create(mod, rnode, name, (chip_t *)arg)); 441 442 return (0); 443 } 444 445 /*ARGSUSED*/ 446 static void 447 cpu_release(topo_mod_t *mp, tnode_t *node) 448 { 449 } 450