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