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