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