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