Home | History | Annotate | Download | only in sun4vpi
      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 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Enumerate a CPU node
     29  */
     30 #include <sys/types.h>
     31 #include <strings.h>
     32 #include <sys/fm/protocol.h>
     33 #include <fm/topo_mod.h>
     34 #include <fm/topo_hc.h>
     35 #include "pi_impl.h"
     36 
     37 #define	_ENUM_NAME	"enum_cpu"
     38 
     39 typedef struct cpuwalk_s {
     40 	topo_mod_t	*mod;
     41 	char		*serial;
     42 } cpuwalk_t;
     43 
     44 static int pi_enum_cpu_serial(topo_mod_t *, md_t *, mde_cookie_t, char **);
     45 static int pi_enum_cpu_serial_cb(md_t *, mde_cookie_t, mde_cookie_t, void *);
     46 
     47 int
     48 pi_enum_cpu(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
     49     topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
     50     tnode_t **t_node)
     51 {
     52 	int		result;
     53 	int		err;
     54 	int		cpumask;
     55 	nvlist_t	*asru = NULL;
     56 	char		*serial = NULL;
     57 
     58 	*t_node = NULL;
     59 
     60 	/*
     61 	 * Create the basic topology node for the CPU using the generic
     62 	 * enumerator.
     63 	 */
     64 	result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
     65 	    t_parent, hc_name, _ENUM_NAME, t_node, 0);
     66 	if (result != 0) {
     67 		/* Error messages are printed by the generic routine */
     68 		return (result);
     69 	}
     70 
     71 	/*
     72 	 * If the hc_name is "chip" or "core", set asru to resource,
     73 	 * otherwise for "cpu" and "strand", set asru to CPU scheme FMRI.
     74 	 */
     75 	if (strcmp(hc_name, CHIP) == 0 || strcmp(hc_name, CORE) == 0) {
     76 		result = topo_node_resource(*t_node, &asru, &err);
     77 		if (result != 0) {
     78 			topo_mod_dprintf(mod,
     79 			    "%s node_0x%llx failed to get resource: %s\n",
     80 			    _ENUM_NAME, (uint64_t)mde_node, topo_strerror(err));
     81 			return (-1);
     82 		}
     83 	} else {
     84 		/*
     85 		 * Compute ASRU for "cpu" and "strand" node.
     86 		 * Get the parameters required to create an FMRI.  The cpumask
     87 		 * is on the chip itself and while it may be part of an ereport
     88 		 * payload is unavailable here, so we set it to zero.
     89 		 */
     90 		cpumask = 0;
     91 
     92 		/*
     93 		 * Find the serial number, which is on the "chip" node, not the
     94 		 * "cpu" node.
     95 		 */
     96 		result = pi_enum_cpu_serial(mod, mdp, mde_node, &serial);
     97 		if (result != 0 || serial == NULL) {
     98 			topo_mod_dprintf(mod,
     99 			    "%s node_0x%llx failed to find serial number.\n",
    100 			    _ENUM_NAME, (uint64_t)mde_node);
    101 			return (result);
    102 		}
    103 
    104 		/*
    105 		 * Create a CPU scheme FMRI and set it as the ASRU for the CPU
    106 		 * node
    107 		 */
    108 		asru = topo_mod_cpufmri(mod, FM_CPU_SCHEME_VERSION, inst,
    109 		    cpumask, serial);
    110 		topo_mod_strfree(mod, serial);
    111 		if (asru == NULL) {
    112 			topo_mod_dprintf(mod, "%s node_0x%llx failed to "
    113 			    "compute cpu scheme ASRU: %s\n",
    114 			    _ENUM_NAME, (uint64_t)mde_node,
    115 			    topo_strerror(topo_mod_errno(mod)));
    116 			return (-1);
    117 		}
    118 	}
    119 
    120 	/* Set the ASRU on the node without flags (the 0) */
    121 	result = topo_node_asru_set(*t_node, asru, 0, &err);
    122 	nvlist_free(asru);
    123 	if (result != 0) {
    124 		topo_mod_dprintf(mod,
    125 		    "%s node_0x%llx failed to set ASRU: %s\n", _ENUM_NAME,
    126 		    (uint64_t)mde_node, topo_strerror(err));
    127 		return (-1);
    128 	}
    129 
    130 	return (0);
    131 }
    132 
    133 
    134 static int
    135 pi_enum_cpu_serial(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
    136     char **serial)
    137 {
    138 	int			result;
    139 	cpuwalk_t		args;
    140 	mde_str_cookie_t	component_cookie;
    141 	mde_str_cookie_t	back_cookie;
    142 
    143 	args.mod = mod;
    144 	args.serial = NULL;
    145 
    146 	/*
    147 	 * Search backwards through the PRI graph, starting at the current
    148 	 * strand (aka cpu) mde_node, and find the MD_STR_CHIP node.  This
    149 	 * node has the serial number for the cpu.
    150 	 */
    151 	component_cookie = md_find_name(mdp, MD_STR_COMPONENT);
    152 	back_cookie	 = md_find_name(mdp, MD_STR_BACK);
    153 
    154 	result = md_walk_dag(mdp, mde_node, component_cookie, back_cookie,
    155 	    pi_enum_cpu_serial_cb, (void *)&args);
    156 	*serial = args.serial;
    157 
    158 	return (result);
    159 }
    160 
    161 
    162 /*ARGSUSED*/
    163 static int
    164 pi_enum_cpu_serial_cb(md_t *mdp, mde_cookie_t mde_parent,
    165     mde_cookie_t mde_node, void *private)
    166 {
    167 	char		*hc_name;
    168 	cpuwalk_t	*args = (cpuwalk_t *)private;
    169 
    170 	if (args == NULL) {
    171 		return (MDE_WALK_ERROR);
    172 	}
    173 	args->serial = NULL;
    174 
    175 	hc_name = pi_get_topo_hc_name(args->mod, mdp, mde_node);
    176 	if (hc_name != NULL && strcmp(hc_name, MD_STR_CHIP) == 0) {
    177 		args->serial = pi_get_serial(args->mod, mdp, mde_node);
    178 	}
    179 	topo_mod_strfree(args->mod, hc_name);
    180 
    181 	return ((args->serial == NULL ? MDE_WALK_NEXT : MDE_WALK_DONE));
    182 }
    183