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
39typedef struct cpuwalk_s {
40	topo_mod_t	*mod;
41	char		*serial;
42} cpuwalk_t;
43
44static int pi_enum_cpu_serial(topo_mod_t *, md_t *, mde_cookie_t, char **);
45static int pi_enum_cpu_serial_cb(md_t *, mde_cookie_t, mde_cookie_t, void *);
46
47int
48pi_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
134static int
135pi_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*/
163static int
164pi_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