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