Home | History | Annotate | Download | only in platform-cpu
      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