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
pi_enum_cpu(topo_mod_t * mod,md_t * mdp,mde_cookie_t mde_node,topo_instance_t inst,tnode_t * t_parent,const char * hc_name,tnode_t ** t_node)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
pi_enum_cpu_serial(topo_mod_t * mod,md_t * mdp,mde_cookie_t mde_node,char ** serial)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
pi_enum_cpu_serial_cb(md_t * mdp,mde_cookie_t mde_parent,mde_cookie_t mde_node,void * private)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