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 <string.h> 28 #include <umem.h> 29 #include <sys/mdesc.h> 30 #include <sys/fm/ldom.h> 31 32 #include <cpu_mdesc.h> 33 34 static void * 35 cpu_alloc(size_t size) 36 { 37 return (umem_alloc(size, UMEM_DEFAULT)); 38 } 39 40 static void 41 cpu_free(void *data, size_t size) 42 { 43 umem_free(data, size); 44 } 45 46 md_proc_t * 47 cpu_find_proc(md_info_t *chip, uint32_t procid) { 48 int i; 49 md_proc_t *procp; 50 51 /* search the processor based on the physical id */ 52 for (i = 0, procp = chip->procs; i < chip->nprocs; i++, procp++) { 53 if (procp->serialno != 0 && procid == procp->id) { 54 return (procp); 55 } 56 } 57 58 return (NULL); 59 } 60 61 md_cpumap_t * 62 cpu_find_cpumap(md_info_t *chip, uint32_t cpuid) { 63 int i; 64 md_cpumap_t *mcmp; 65 66 for (i = 0, mcmp = chip->cpus; i < chip->ncpus; i++, mcmp++) { 67 if (cpuid == mcmp->cpumap_pid) { 68 return (mcmp); 69 } 70 } 71 return (NULL); 72 } 73 74 int 75 cpu_get_serialid_mdesc(md_info_t *chip, uint32_t cpuid, uint64_t *serialidp) 76 { 77 md_cpumap_t *mcmp; 78 if ((mcmp = cpu_find_cpumap(chip, cpuid)) != NULL) { 79 *serialidp = mcmp->cpumap_serialno; 80 return (0); 81 } 82 return (-1); 83 } 84 85 static int 86 cpu_n1_mdesc_init(topo_mod_t *mod, md_t *mdp, md_info_t *chip) 87 { 88 mde_cookie_t *listp; 89 md_cpumap_t *mcmp; 90 int i, num_nodes, idx; 91 uint64_t x; 92 93 num_nodes = md_node_count(mdp); 94 listp = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * num_nodes); 95 96 chip->ncpus = md_scan_dag(mdp, 97 MDE_INVAL_ELEM_COOKIE, 98 md_find_name(mdp, "cpu"), 99 md_find_name(mdp, "fwd"), 100 listp); 101 topo_mod_dprintf(mod, "Found %d cpus\n", chip->ncpus); 102 103 chip->cpus = topo_mod_zalloc(mod, chip->ncpus * sizeof (md_cpumap_t)); 104 chip->nprocs = chip->ncpus; 105 chip->procs = topo_mod_zalloc(mod, chip->nprocs * sizeof (md_proc_t)); 106 107 for (idx = 0, mcmp = chip->cpus; idx < chip->ncpus; idx++, mcmp++) { 108 109 if (md_get_prop_val(mdp, listp[idx], MD_STR_ID, &x) < 0) 110 x = (uint64_t)-1; /* invalid value */ 111 mcmp->cpumap_id = x; 112 113 if (md_get_prop_val(mdp, listp[idx], MD_STR_PID, &x) < 0) 114 x = mcmp->cpumap_id; 115 mcmp->cpumap_pid = x; 116 117 mcmp->cpumap_serialno = 0; 118 mcmp->cpumap_chipidx = -1; 119 if (md_get_prop_val(mdp, listp[idx], MD_STR_CPU_SERIAL, 120 &mcmp->cpumap_serialno) < 0) { 121 continue; 122 } 123 if (mcmp->cpumap_serialno == 0) { 124 continue; 125 } 126 127 /* 128 * This PRI/MD has no indentity info. of the FRU and no 129 * physical proc id. 130 * Find if there is already an existing processor entry 131 * Assign procid based on the order found during reading 132 */ 133 for (i = 0; i < chip->nprocs && 134 chip->procs[i].serialno != 0; i++) { 135 if (mcmp->cpumap_serialno == chip->procs[i].serialno) { 136 break; 137 } 138 } 139 if (i < chip->nprocs) { 140 mcmp->cpumap_chipidx = i; 141 if (chip->procs[i].serialno == 0) { 142 chip->procs[i].id = i; 143 chip->procs[i].serialno = mcmp->cpumap_serialno; 144 topo_mod_dprintf(mod, 145 "chip[%d] serial is %llx\n", 146 i, chip->procs[i].serialno); 147 } 148 } 149 150 } 151 152 topo_mod_free(mod, listp, sizeof (mde_cookie_t) * num_nodes); 153 154 return (0); 155 } 156 157 static int 158 cpu_n2_mdesc_init(topo_mod_t *mod, md_t *mdp, md_info_t *chip) 159 { 160 mde_cookie_t *list1p, *list2p; 161 md_cpumap_t *mcmp; 162 md_proc_t *procp; 163 md_fru_t *frup; 164 int i, j, cnt; 165 int procid_flag = 0; 166 int nnode, ncomp, nproc, ncpu; 167 char *str = NULL; 168 uint64_t x, sn; 169 char *strserial, *end; 170 171 nnode = md_node_count(mdp); 172 list1p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * nnode); 173 174 /* Count the number of processors and strands */ 175 ncomp = md_scan_dag(mdp, 176 MDE_INVAL_ELEM_COOKIE, 177 md_find_name(mdp, MD_STR_COMPONENT), 178 md_find_name(mdp, "fwd"), 179 list1p); 180 if (ncomp <= 0) { 181 topo_mod_dprintf(mod, "Component nodes not found\n"); 182 topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode); 183 return (-1); 184 } 185 for (i = 0, nproc = 0, ncpu = 0; i < ncomp; i++) { 186 if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 && 187 str != NULL && strcmp(str, MD_STR_PROCESSOR) == 0) { 188 nproc++; 189 /* check if the physical id exists */ 190 if (md_get_prop_val(mdp, list1p[i], MD_STR_ID, &x) 191 == 0) { 192 procid_flag = 1; 193 } 194 } 195 if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 && 196 str && strcmp(str, MD_STR_STRAND) == 0) { 197 ncpu++; 198 } 199 } 200 topo_mod_dprintf(mod, "Found %d procs and %d strands\n", nproc, ncpu); 201 if (nproc == 0 || ncpu == 0) { 202 topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode); 203 return (-1); 204 } 205 206 /* Alloc processors and strand entries */ 207 list2p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * 2 * ncpu); 208 chip->nprocs = nproc; 209 chip->procs = topo_mod_zalloc(mod, nproc * sizeof (md_proc_t)); 210 chip->ncpus = ncpu; 211 chip->cpus = topo_mod_zalloc(mod, ncpu * sizeof (md_cpumap_t)); 212 213 /* Visit each processor node */ 214 procp = chip->procs; 215 mcmp = chip->cpus; 216 for (i = 0, nproc = 0, ncpu = 0; i < ncomp; i++) { 217 if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) < 0 || 218 str == NULL || strcmp(str, MD_STR_PROCESSOR)) 219 continue; 220 if (md_get_prop_val(mdp, list1p[i], MD_STR_SERIAL, &sn) < 0) { 221 if (md_get_prop_str(mdp, list1p[i], MD_STR_SERIAL, 222 &strserial) < 0) { 223 topo_mod_dprintf(mod, 224 "Failed to get the serial number of" 225 "proc[%d]\n", nproc); 226 continue; 227 } else { 228 sn = (uint64_t)strtoull(strserial, &end, 16); 229 if (strserial == end) { 230 topo_mod_dprintf(mod, 231 "Failed to convert the serial " 232 "string to serial int of " 233 "proc[%d]\n", nproc); 234 continue; 235 } 236 } 237 } 238 procp->serialno = sn; 239 240 /* Assign physical proc id */ 241 procp->id = -1; 242 if (procid_flag) { 243 if (md_get_prop_val(mdp, list1p[i], MD_STR_ID, &x) 244 == 0) { 245 procp->id = x; 246 } 247 } else { 248 procp->id = nproc; 249 } 250 topo_mod_dprintf(mod, "proc %d: sn=%llx, id=%d\n", nproc, 251 procp->serialno, procp->id); 252 253 /* Get all the strands below this proc */ 254 cnt = md_scan_dag(mdp, 255 list1p[i], 256 md_find_name(mdp, MD_STR_COMPONENT), 257 md_find_name(mdp, "fwd"), 258 list2p); 259 topo_mod_dprintf(mod, "proc[%llx]: Found %d fwd components\n", 260 sn, cnt); 261 if (cnt <= 0) { 262 nproc++; 263 procp++; 264 continue; 265 } 266 for (j = 0; j < cnt; j++) { 267 /* Consider only the strand nodes */ 268 if (md_get_prop_str(mdp, list2p[j], MD_STR_TYPE, &str) 269 < 0 || str == NULL || strcmp(str, MD_STR_STRAND)) 270 continue; 271 272 if (md_get_prop_val(mdp, list2p[j], MD_STR_ID, &x) < 0) 273 x = (uint64_t)-1; /* invalid value */ 274 mcmp->cpumap_id = x; 275 276 if (md_get_prop_val(mdp, list2p[j], MD_STR_PID, &x) < 0) 277 x = mcmp->cpumap_id; 278 mcmp->cpumap_pid = x; 279 280 mcmp->cpumap_serialno = sn; 281 mcmp->cpumap_chipidx = nproc; 282 ncpu++; 283 mcmp++; 284 } 285 286 /* 287 * To get the fru of this proc, follow the back arc up to 288 * find the first node whose fru field is set 289 */ 290 cnt = md_scan_dag(mdp, 291 list1p[i], 292 md_find_name(mdp, MD_STR_COMPONENT), 293 md_find_name(mdp, "back"), 294 list2p); 295 topo_mod_dprintf(mod, "proc[%d]: Found %d back components\n", 296 nproc, cnt); 297 if (cnt <= 0) { 298 nproc++; 299 procp++; 300 continue; 301 } 302 for (j = 0; j < cnt; j++) { 303 /* test the fru field which must be positive number */ 304 if ((md_get_prop_val(mdp, list2p[j], MD_STR_FRU, &x) 305 == 0) && x > 0) 306 break; 307 } 308 if (j < cnt) { 309 /* Found the FRU node, get the fru identity */ 310 topo_mod_dprintf(mod, "proc[%d] sn=%llx has a fru %d\n", 311 nproc, procp->serialno, j); 312 frup = topo_mod_zalloc(mod, sizeof (md_fru_t)); 313 procp->fru = frup; 314 if (!md_get_prop_str(mdp, list2p[j], MD_STR_NAC, &str)) 315 frup->nac = topo_mod_strdup(mod, str); 316 else 317 frup->nac = topo_mod_strdup(mod, MD_FRU_DEF); 318 if (!md_get_prop_str(mdp, list2p[j], MD_STR_PART, &str)) 319 frup->part = topo_mod_strdup(mod, str); 320 if (!md_get_prop_str(mdp, list2p[j], MD_STR_SERIAL, 321 &str)) 322 frup->serial = topo_mod_strdup(mod, str); 323 if (!md_get_prop_str(mdp, list2p[j], MD_STR_DASH, &str)) 324 frup->dash = topo_mod_strdup(mod, str); 325 } else { 326 topo_mod_dprintf(mod, "proc[%d] sn=%llx has no fru\n", 327 i, procp->serialno); 328 } 329 330 nproc++; 331 procp++; 332 } /* for i */ 333 334 topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode); 335 topo_mod_free(mod, list2p, sizeof (mde_cookie_t) * 2*chip->ncpus); 336 337 return (0); 338 } 339 340 /* 341 * Extract from the PRI the processor, strand and their fru identity 342 */ 343 int 344 cpu_mdesc_init(topo_mod_t *mod, md_info_t *chip) 345 { 346 int rc = -1; 347 md_t *mdp; 348 ssize_t bufsiz = 0; 349 uint64_t *bufp; 350 ldom_hdl_t *lhp; 351 uint32_t type = 0; 352 353 /* get the PRI/MD */ 354 if ((lhp = ldom_init(cpu_alloc, cpu_free)) == NULL) { 355 topo_mod_dprintf(mod, "ldom_init() failed\n"); 356 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 357 } 358 359 (void) ldom_get_type(lhp, &type); 360 if ((type & LDOM_TYPE_CONTROL) != 0) { 361 bufsiz = ldom_get_core_md(lhp, &bufp); 362 } else { 363 bufsiz = ldom_get_local_md(lhp, &bufp); 364 } 365 if (bufsiz <= 0) { 366 topo_mod_dprintf(mod, "failed to get the PRI/MD\n"); 367 ldom_fini(lhp); 368 return (-1); 369 } 370 371 if ((mdp = md_init_intern(bufp, cpu_alloc, cpu_free)) == NULL || 372 md_node_count(mdp) <= 0) { 373 cpu_free(bufp, (size_t)bufsiz); 374 ldom_fini(lhp); 375 return (-1); 376 } 377 378 /* 379 * N1 MD contains cpu nodes while N2 MD contains component nodes. 380 */ 381 if (md_find_name(mdp, MD_STR_COMPONENT) != MDE_INVAL_STR_COOKIE) { 382 rc = cpu_n2_mdesc_init(mod, mdp, chip); 383 } else if (md_find_name(mdp, MD_STR_CPU) != MDE_INVAL_STR_COOKIE) { 384 rc = cpu_n1_mdesc_init(mod, mdp, chip); 385 } else { 386 topo_mod_dprintf(mod, "Unsupported PRI/MD\n"); 387 rc = -1; 388 } 389 390 cpu_free(bufp, (size_t)bufsiz); 391 (void) md_fini(mdp); 392 ldom_fini(lhp); 393 394 return (rc); 395 } 396 397 void 398 cpu_mdesc_fini(topo_mod_t *mod, md_info_t *chip) 399 { 400 int i; 401 md_proc_t *procp; 402 md_fru_t *frup; 403 404 if (chip->cpus != NULL) 405 topo_mod_free(mod, chip->cpus, 406 chip->ncpus * sizeof (md_cpumap_t)); 407 408 if (chip->procs != NULL) { 409 procp = chip->procs; 410 for (i = 0; i < chip->nprocs; i++) { 411 if ((frup = procp->fru) != NULL) { 412 topo_mod_strfree(mod, frup->nac); 413 topo_mod_strfree(mod, frup->serial); 414 topo_mod_strfree(mod, frup->part); 415 topo_mod_strfree(mod, frup->dash); 416 topo_mod_free(mod, frup, sizeof (md_fru_t)); 417 } 418 procp++; 419 } 420 topo_mod_free(mod, chip->procs, 421 chip->nprocs * sizeof (md_proc_t)); 422 } 423 } 424