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
set_prop_info(ptree_propinfo_t * propinfo,int size,char * name,int type)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
prop_exists(picl_nodehdl_t node,char * name)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
add_md_prop(picl_nodehdl_t node,int size,char * name,void * value,int type)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
add_tlb_props(picl_nodehdl_t node,mde_cookie_t * tlblistp,int ntlbs)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
add_cache_props(picl_nodehdl_t node,mde_cookie_t * cachelistp,int ncaches)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
add_clock_frequency(picl_nodehdl_t pnode,mde_cookie_t mnode)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
get_string_count(char * strdat,int length)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
add_compatible(picl_nodehdl_t pnode,mde_cookie_t mnode)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
add_device_type(picl_nodehdl_t pnode)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
add_cpu_prop(picl_nodehdl_t node,void * args)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