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 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 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 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 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 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 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 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 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 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 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