xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4v/mdesc/cpu_prop_update.c (revision b7daf79982d77b491ef9662483cd4549e0e5da9a)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include "mdescplugin.h"
29 #include <limits.h>
30 
31 /* These 3 variable are defined and set in mdescplugin.c */
32 extern picl_nodehdl_t	root_node;
33 extern md_t		*mdp;
34 extern mde_cookie_t	rootnode;
35 
36 void
37 set_prop_info(ptree_propinfo_t *propinfo, int size, char *name, int type)
38 {
39 	propinfo->version = PICLD_PLUGIN_VERSION_1;
40 	propinfo->read = NULL;
41 	propinfo->write = NULL;
42 	propinfo->piclinfo.type = type;
43 	propinfo->piclinfo.accessmode = PICL_READ;
44 	propinfo->piclinfo.size = size;
45 	(void) strncpy(propinfo->piclinfo.name, name,
46 	    sizeof (propinfo->piclinfo.name));
47 }
48 
49 static boolean_t
50 prop_exists(picl_nodehdl_t node, char *name)
51 {
52 	int status;
53 	picl_prophdl_t proph;
54 
55 	status = ptree_get_prop_by_name(node, name, &proph);
56 	if (status == PICL_SUCCESS)
57 		return (B_TRUE);
58 	else
59 		return (B_FALSE);
60 }
61 
62 static void
63 add_md_prop(picl_nodehdl_t node, int size, char *name, void* value, int type)
64 {
65 	ptree_propinfo_t propinfo;
66 	picl_prophdl_t proph;
67 
68 	if (!prop_exists(node, name)) {
69 		set_prop_info(&propinfo, size, name, type);
70 
71 		(void) ptree_create_and_add_prop(node, &propinfo,
72 		    value, &proph);
73 	}
74 }
75 static void
76 add_tlb_props(picl_nodehdl_t node, mde_cookie_t *tlblistp, int ntlbs)
77 {
78 	int i;
79 	uint64_t int_value;
80 	uint8_t *type;
81 	char str[MAXSTRLEN];
82 	char property[MAXSTRLEN];
83 	char tlb_str[MAXSTRLEN];
84 	int type_size, str_size, total_size, type_flag;
85 
86 	for (i = 0; i < ntlbs; i++) {
87 		if (md_get_prop_data(mdp, tlblistp[i], "type", &type,
88 		    &type_size)) {
89 			return;
90 		}
91 
92 		total_size = type_flag = 0;
93 
94 		while (total_size < type_size) {
95 			str_size = strlen((char *)type + total_size) + 1;
96 			(void) strncpy(str, (char *)type + total_size,
97 			    sizeof (str));
98 			if (strncmp(str, "instn", sizeof (str)) == 0)
99 				type_flag |= ICACHE_FLAG;
100 			if (strncmp(str, "data", sizeof (str)) == 0)
101 				type_flag |= DCACHE_FLAG;
102 			total_size += str_size;
103 		}
104 
105 		switch (type_flag) {
106 		case 1:
107 			(void) snprintf(tlb_str, sizeof (tlb_str),
108 			    "itlb");
109 			break;
110 		case 2:
111 			(void) snprintf(tlb_str, sizeof (tlb_str),
112 			    "dtlb");
113 			break;
114 		default:
115 			(void) snprintf(tlb_str, sizeof (tlb_str),
116 			    "Not a known cache type");
117 		}
118 
119 		if (!(md_get_prop_val(mdp, tlblistp[i], "entries",
120 		    &int_value))) {
121 			(void) snprintf(property, sizeof (property),
122 			    "%s-entries", tlb_str);
123 			add_md_prop(node, sizeof (int_value), property,
124 			    &int_value, PICL_PTYPE_INT);
125 		}
126 	}
127 }
128 
129 static void
130 add_cache_props(picl_nodehdl_t node, mde_cookie_t *cachelistp, int ncaches)
131 {
132 	int i;
133 	uint64_t int_value;
134 	uint8_t *type;
135 	char str[MAXSTRLEN];
136 	char property[MAXSTRLEN];
137 	char cache_str[MAXSTRLEN];
138 	int type_size, str_size, total_size, type_flag;
139 
140 	for (i = 0; i < ncaches; i++) {
141 		if (md_get_prop_data(mdp, cachelistp[i], "type", &type,
142 		    &type_size)) {
143 			return;
144 		}
145 
146 		if (md_get_prop_val(mdp, cachelistp[i], "level", &int_value)) {
147 			return;
148 		}
149 
150 		total_size = type_flag = 0;
151 
152 		while (total_size < type_size) {
153 			str_size = strlen((char *)type + total_size) + 1;
154 			(void) strncpy(str, (char *)type + total_size,
155 			    sizeof (str));
156 			if (strncmp(str, "instn", sizeof (str)) == 0)
157 				type_flag |= ICACHE_FLAG;
158 			if (strncmp(str, "data", sizeof (str)) == 0)
159 				type_flag |= DCACHE_FLAG;
160 			total_size += str_size;
161 		}
162 
163 		switch (type_flag) {
164 		case 1:
165 			(void) snprintf(cache_str, sizeof (cache_str),
166 			    "l%d-icache", (int)int_value);
167 			break;
168 		case 2:
169 			(void) snprintf(cache_str, sizeof (cache_str),
170 			    "l%d-dcache", (int)int_value);
171 			break;
172 		case 3:
173 			(void) snprintf(cache_str, sizeof (cache_str),
174 			    "l%d-cache", (int)int_value);
175 			break;
176 		default:
177 			(void) snprintf(cache_str, sizeof (cache_str),
178 			    "Not a known cache type");
179 		}
180 
181 		if (!(md_get_prop_val(mdp, cachelistp[i], "associativity",
182 		    &int_value))) {
183 			(void) snprintf(property, sizeof (property),
184 			    "%s-associativity", cache_str);
185 			add_md_prop(node, sizeof (int_value), property,
186 			    &int_value, PICL_PTYPE_INT);
187 		}
188 
189 		if (!(md_get_prop_val(mdp, cachelistp[i], "size",
190 		    &int_value))) {
191 			(void) snprintf(property, sizeof (property), "%s-size",
192 			    cache_str);
193 			add_md_prop(node, sizeof (int_value), property,
194 			    &int_value, PICL_PTYPE_INT);
195 		}
196 
197 		if (!(md_get_prop_val(mdp, cachelistp[i], "line-size",
198 		    &int_value))) {
199 			(void) snprintf(property, sizeof (property),
200 			    "%s-line-size", cache_str);
201 			add_md_prop(node, sizeof (int_value), property,
202 			    &int_value, PICL_PTYPE_INT);
203 		}
204 	}
205 }
206 
207 static void
208 add_clock_frequency(picl_nodehdl_t pnode, mde_cookie_t mnode)
209 {
210 	uint64_t	uint64_value;
211 	uint32_t	uint32_value;
212 
213 	if (md_get_prop_val(mdp, mnode, "clock-frequency",
214 	    &uint64_value)) {
215 		return;
216 	}
217 	uint32_value = (uint32_t)(uint64_value & UINT32_MAX);
218 	add_md_prop(pnode, sizeof (uint32_value), "clock-frequency",
219 	    &uint32_value, PICL_PTYPE_UNSIGNED_INT);
220 }
221 
222 /*
223  * Return the number of strings in the buffer
224  */
225 static int
226 get_string_count(char *strdat, int length)
227 {
228 	int	count;
229 	char	*lastnull;
230 	char	*nullptr;
231 
232 	count = 1;
233 	for (lastnull = &strdat[length - 1], nullptr = strchr(strdat, '\0');
234 	    nullptr != lastnull; nullptr = strchr(nullptr + 1, '\0'))
235 		count++;
236 
237 	return (count);
238 }
239 
240 static void
241 add_compatible(picl_nodehdl_t pnode, mde_cookie_t mnode)
242 {
243 	char	*compat;
244 	int	len;
245 	int	count;
246 	void	add_string_list_prop(picl_nodehdl_t, char *, char *,
247 	    unsigned int);
248 
249 	if (prop_exists(pnode, "compatible"))
250 		return;
251 	if (md_get_prop_data(mdp, mnode, "compatible", (uint8_t **)&compat,
252 	    &len)) {
253 		return;
254 	}
255 	if (compat[0] == '\0' || compat[len - 1] != '\0')
256 		return;
257 	count = get_string_count(compat, len);
258 	if (count == 1) {
259 		add_md_prop(pnode, len, "compatible", compat,
260 		    PICL_PTYPE_CHARSTRING);
261 		return;
262 	}
263 	(void) add_string_list_prop(pnode, "compatible", compat, count);
264 }
265 
266 static void
267 add_device_type(picl_nodehdl_t pnode)
268 {
269 	char	*device_type = "cpu";
270 
271 	add_md_prop(pnode, strlen(device_type) + 1, "device_type", device_type,
272 	    PICL_PTYPE_CHARSTRING);
273 }
274 
275 int
276 add_cpu_prop(picl_nodehdl_t node, void *args)
277 {
278 	mde_cookie_t *cpulistp;
279 	mde_cookie_t *cachelistp;
280 	mde_cookie_t *tlblistp;
281 	int x, num_nodes;
282 	int ncpus, ncaches, ntlbs;
283 	int status;
284 	int reg_prop[SUN4V_CPU_REGSIZE], cpuid;
285 	uint64_t int64_value;
286 	int int_value;
287 
288 	status = ptree_get_propval_by_name(node, OBP_REG, reg_prop,
289 	    sizeof (reg_prop));
290 	if (status != PICL_SUCCESS) {
291 		return (PICL_WALK_TERMINATE);
292 	}
293 
294 	cpuid = CFGHDL_TO_CPUID(reg_prop[0]);
295 
296 	/*
297 	 * Allocate space for our searches.
298 	 */
299 
300 	num_nodes = md_node_count(mdp);
301 
302 	cpulistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes);
303 	if (cpulistp == NULL) {
304 		return (PICL_WALK_TERMINATE);
305 	}
306 
307 	cachelistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes);
308 	if (cachelistp == NULL) {
309 		return (PICL_WALK_TERMINATE);
310 	}
311 
312 	tlblistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes);
313 	if (tlblistp == NULL) {
314 		return (PICL_WALK_TERMINATE);
315 	}
316 
317 	/*
318 	 * Starting at the root node, scan the "fwd" dag for
319 	 * all the cpus in this description.
320 	 */
321 
322 	ncpus = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"),
323 	    md_find_name(mdp, "fwd"), cpulistp);
324 
325 	if (ncpus < 0) {
326 		return (PICL_WALK_TERMINATE);
327 	}
328 
329 	/*
330 	 * Create PD cpus with a few select properties
331 	 */
332 
333 	for (x = 0; x < ncpus; x++) {
334 		if (md_get_prop_val(mdp, cpulistp[x], "id", &int64_value)) {
335 			continue;
336 		}
337 
338 		if (int64_value != cpuid)
339 			continue;
340 
341 		int_value = (int)(int64_value & INT32_MAX);
342 
343 		add_md_prop(node, sizeof (int_value), OBP_PROP_CPUID,
344 		    &int_value, PICL_PTYPE_INT);
345 
346 		add_md_prop(node, sizeof (int_value), OBP_PROP_PORTID,
347 		    &int_value, PICL_PTYPE_INT);
348 
349 		add_clock_frequency(node, cpulistp[x]);
350 
351 		add_compatible(node, cpulistp[x]);
352 
353 		add_device_type(node);
354 
355 		/* get caches for CPU */
356 		ncaches = md_scan_dag(mdp, cpulistp[x],
357 		    md_find_name(mdp, "cache"),
358 		    md_find_name(mdp, "fwd"),
359 		    cachelistp);
360 
361 		add_cache_props(node, cachelistp, ncaches);
362 
363 		/* get tlbs for CPU */
364 		ntlbs = md_scan_dag(mdp, cpulistp[x],
365 		    md_find_name(mdp, "tlb"),
366 		    md_find_name(mdp, "fwd"),
367 		    tlblistp);
368 
369 		add_tlb_props(node, tlblistp, ntlbs);
370 	}
371 
372 	return (PICL_WALK_CONTINUE);
373 }
374