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 2006 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 <sys/errno.h> 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/cpu.h> 32 #include <sys/cpuvar.h> 33 #include <sys/clock.h> 34 #include <sys/promif.h> 35 #include <sys/promimpl.h> 36 #include <sys/systm.h> 37 #include <sys/machsystm.h> 38 #include <sys/debug.h> 39 #include <sys/sunddi.h> 40 #include <sys/modctl.h> 41 #include <sys/cpu_module.h> 42 #include <sys/kobj.h> 43 #include <sys/cmp.h> 44 #include <sys/async.h> 45 #include <vm/page.h> 46 #include <vm/hat_sfmmu.h> 47 #include <sys/sysmacros.h> 48 #include <sys/mach_descrip.h> 49 #include <sys/mdesc.h> 50 #include <sys/archsystm.h> 51 #include <sys/error.h> 52 #include <sys/mmu.h> 53 #include <sys/bitmap.h> 54 55 int ncpunode; 56 struct cpu_node cpunodes[NCPU]; 57 58 uint64_t cpu_q_entries; 59 uint64_t dev_q_entries; 60 uint64_t cpu_rq_entries; 61 uint64_t cpu_nrq_entries; 62 63 void fill_cpu(md_t *, mde_cookie_t); 64 65 static uint64_t get_mmu_ctx_bits(md_t *, mde_cookie_t); 66 static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t); 67 static char *construct_isalist(md_t *, mde_cookie_t, char **); 68 static void set_at_flags(char *, int, char **); 69 static void init_md_broken(md_t *); 70 static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *, 71 uint64_t *); 72 static id_t get_exec_unit_mapping(md_t *, mde_cookie_t, mde_cookie_t *); 73 static int find_exec_unit_id(mde_cookie_t, mde_cookie_t *); 74 static void get_q_sizes(md_t *, mde_cookie_t); 75 static void get_va_bits(md_t *, mde_cookie_t); 76 static size_t get_ra_limit(md_t *); 77 78 uint64_t system_clock_freq; 79 int niobus = 0; 80 uint_t niommu_tsbs = 0; 81 82 void 83 map_wellknown_devices() 84 { 85 } 86 87 #define S_VAC_SIZE MMU_PAGESIZE 88 #define S_VAC_SHIFT MMU_PAGESHIFT 89 90 /* 91 * For backward compatibility we need to verify that we can handle 92 * running on platforms which shipped with missing MD properties. 93 */ 94 #define ONTARIO_PLATNAME1 "SUNW,Sun-Fire-T200" 95 #define ONTARIO_PLATNAME2 "SUNW,Sun-Fire-T2000" 96 #define ERIE_PLATNAME1 "SUNW,Sun-Fire-T100" 97 #define ERIE_PLATNAME2 "SUNW,Sun-Fire-T1000" 98 99 void 100 fill_cpu(md_t *mdp, mde_cookie_t cpuc) 101 { 102 struct cpu_node *cpunode; 103 uint64_t cpuid; 104 uint64_t clk_freq; 105 char *namebuf; 106 char *namebufp; 107 int namelen; 108 uint64_t associativity = 0, linesize = 0, size = 0; 109 int status; 110 111 if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) { 112 return; 113 } 114 115 if (cpuid >= NCPU) { 116 cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - " 117 "cpu excluded from configuration", cpuid); 118 119 mutex_enter(&cpu_lock); 120 121 /* 122 * Since the CPU cannot be used, make sure it 123 * is in a safe place. If the firmware does not 124 * support CPU stop, this is known to be true. 125 * If it fails to stop for any other reason, the 126 * system is in an inconsistent state and cannot 127 * be allowed to continue. 128 */ 129 status = stopcpu_bycpuid(cpuid); 130 131 if ((status != 0) && (status != ENOTSUP)) { 132 cmn_err(CE_PANIC, "failed to stop cpu %lu (%d)", 133 cpuid, status); 134 } 135 136 mutex_exit(&cpu_lock); 137 return; 138 } 139 140 cpunode = &cpunodes[cpuid]; 141 cpunode->cpuid = (int)cpuid; 142 cpunode->device_id = cpuid; 143 144 if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI)) 145 (void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI); 146 147 if (md_get_prop_data(mdp, cpuc, 148 "compatible", (uint8_t **)&namebuf, &namelen)) { 149 cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible " 150 "property"); 151 } 152 namebufp = namebuf; 153 if (strncmp(namebufp, "SUNW,", 5) == 0) 154 namebufp += 5; 155 if (strlen(namebufp) > sizeof (cpunode->name)) 156 cmn_err(CE_PANIC, "Compatible property too big to " 157 "fit into the cpunode name buffer"); 158 (void) strcpy(cpunode->name, namebufp); 159 160 if (md_get_prop_val(mdp, cpuc, 161 "clock-frequency", &clk_freq)) { 162 clk_freq = 0; 163 } 164 cpunode->clock_freq = clk_freq; 165 166 ASSERT(cpunode->clock_freq != 0); 167 /* 168 * Compute scaling factor based on rate of %tick. This is used 169 * to convert from ticks derived from %tick to nanoseconds. See 170 * comment in sun4u/sys/clock.h for details. 171 */ 172 cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << 173 (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); 174 175 /* 176 * The nodeid is not used in sun4v at all. Setting it 177 * to positive value to make starting of slave CPUs 178 * code happy. 179 */ 180 cpunode->nodeid = cpuid + 1; 181 182 /* 183 * Obtain the L2 cache information from MD. 184 * If "Cache" node exists, then set L2 cache properties 185 * as read from MD. 186 * If node does not exists, then set the L2 cache properties 187 * in individual CPU module. 188 */ 189 if ((!get_l2_cache_info(mdp, cpuc, 190 &associativity, &size, &linesize)) || 191 associativity == 0 || size == 0 || linesize == 0) { 192 cpu_fiximp(cpunode); 193 } else { 194 /* 195 * Do not expect L2 cache properties to be bigger 196 * than 32-bit quantity. 197 */ 198 cpunode->ecache_associativity = (int)associativity; 199 cpunode->ecache_size = (int)size; 200 cpunode->ecache_linesize = (int)linesize; 201 } 202 203 cpunode->ecache_setsize = 204 cpunode->ecache_size / cpunode->ecache_associativity; 205 206 /* 207 * Start off by assigning the cpu id as the default 208 * mapping index. 209 */ 210 211 cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND; 212 213 if (ecache_setsize == 0) 214 ecache_setsize = cpunode->ecache_setsize; 215 if (ecache_alignsize == 0) 216 ecache_alignsize = cpunode->ecache_linesize; 217 218 ncpunode++; 219 } 220 221 void 222 empty_cpu(int cpuid) 223 { 224 bzero(&cpunodes[cpuid], sizeof (struct cpu_node)); 225 ncpunode--; 226 } 227 228 void 229 setup_exec_unit_mappings(md_t *mdp) 230 { 231 uint64_t num, num_eunits; 232 mde_cookie_t cpus_node; 233 mde_cookie_t *node, *eunit; 234 int idx, i, j; 235 processorid_t cpuid; 236 char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit"; 237 238 /* 239 * Find the cpu integer exec units - and 240 * setup the mappings appropriately. 241 */ 242 num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node); 243 if (num < 1) 244 cmn_err(CE_PANIC, "No cpus node in machine desccription"); 245 if (num > 1) 246 cmn_err(CE_PANIC, "More than 1 cpus node in machine" 247 " description"); 248 249 cpus_node = node[0]; 250 md_free_scan_dag(mdp, &node); 251 252 num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name, 253 "fwd", &eunit); 254 if (num_eunits > 0) { 255 char *match_type = broken_md_flag ? "int" : "integer"; 256 257 /* Spin through and find all the integer exec units */ 258 for (i = 0; i < num_eunits; i++) { 259 char *p; 260 char *val; 261 int vallen; 262 uint64_t lcpuid; 263 264 /* ignore nodes with no type */ 265 if (md_get_prop_data(mdp, eunit[i], "type", 266 (uint8_t **)&val, &vallen)) continue; 267 268 for (p = val; *p != '\0'; p += strlen(p) + 1) { 269 if (strcmp(p, match_type) == 0) 270 goto found; 271 } 272 273 continue; 274 found: 275 idx = NCPU + i; 276 /* 277 * find the cpus attached to this EU and 278 * update their mapping indices 279 */ 280 num = md_alloc_scan_dag(mdp, eunit[i], "cpu", 281 "back", &node); 282 283 if (num < 1) 284 cmn_err(CE_PANIC, "exec-unit node in MD" 285 " not attached to a cpu node"); 286 287 for (j = 0; j < num; j++) { 288 if (md_get_prop_val(mdp, node[j], "id", 289 &lcpuid)) 290 continue; 291 if (lcpuid >= NCPU) 292 continue; 293 cpuid = (processorid_t)lcpuid; 294 cpunodes[cpuid].exec_unit_mapping = idx; 295 } 296 md_free_scan_dag(mdp, &node); 297 } 298 299 300 md_free_scan_dag(mdp, &eunit); 301 } 302 } 303 304 /* 305 * All the common setup of sun4v CPU modules is done by this routine. 306 */ 307 void 308 cpu_setup_common(char **cpu_module_isa_set) 309 { 310 extern int disable_delay_tlb_flush, delay_tlb_flush; 311 extern int mmu_exported_pagesize_mask; 312 extern int vac_size, vac_shift; 313 extern uint_t vac_mask; 314 int nocpus, i; 315 size_t ra_limit; 316 mde_cookie_t *cpulist; 317 md_t *mdp; 318 319 if ((mdp = md_get_handle()) == NULL) 320 cmn_err(CE_PANIC, "Unable to initialize machine description"); 321 322 init_md_broken(mdp); 323 324 nocpus = md_alloc_scan_dag(mdp, 325 md_root_node(mdp), "cpu", "fwd", &cpulist); 326 if (nocpus < 1) { 327 cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation " 328 "failed or incorrect number of CPUs in MD"); 329 } 330 331 if (use_page_coloring) { 332 do_pg_coloring = 1; 333 if (use_virtual_coloring) { 334 /* 335 * XXX Sun4v cpus don't have virtual caches 336 */ 337 do_virtual_coloring = 1; 338 } 339 } 340 341 /* 342 * Get the valid mmu page sizes mask, Q sizes and isalist/r 343 * from the MD for the first available CPU in cpulist. 344 * 345 * Do not expect the MMU page sizes mask to be more than 32-bit. 346 */ 347 mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]); 348 349 for (i = 0; i < nocpus; i++) 350 fill_cpu(mdp, cpulist[i]); 351 352 setup_exec_unit_mappings(mdp); 353 354 vac_size = S_VAC_SIZE; 355 vac_mask = MMU_PAGEMASK & (vac_size - 1); 356 vac_shift = S_VAC_SHIFT; 357 shm_alignment = vac_size; 358 vac = 0; 359 360 /* 361 * If MD is broken then append the passed ISA set, 362 * otherwise trust the MD. 363 */ 364 365 if (broken_md_flag) 366 isa_list = construct_isalist(mdp, cpulist[0], 367 cpu_module_isa_set); 368 else 369 isa_list = construct_isalist(mdp, cpulist[0], NULL); 370 371 get_q_sizes(mdp, cpulist[0]); 372 373 get_va_bits(mdp, cpulist[0]); 374 375 /* 376 * ra_limit is the highest real address in the machine. 377 */ 378 ra_limit = get_ra_limit(mdp); 379 380 md_free_scan_dag(mdp, &cpulist); 381 382 (void) md_fini_handle(mdp); 383 384 /* 385 * Block stores invalidate all pages of the d$ so pagecopy 386 * et. al. do not need virtual translations with virtual 387 * coloring taken into consideration. 388 */ 389 pp_consistent_coloring = 0; 390 391 /* 392 * The kpm mapping window. 393 * kpm_size: 394 * The size of a single kpm range. 395 * The overall size will be: kpm_size * vac_colors. 396 * kpm_vbase: 397 * The virtual start address of the kpm range within the kernel 398 * virtual address space. kpm_vbase has to be kpm_size aligned. 399 */ 400 401 /* 402 * Make kpm_vbase, kpm_size aligned to kpm_size_shift. 403 * To do this find the nearest power of 2 size that the 404 * actual ra_limit fits within. 405 * If it is an even power of two use that, otherwise use the 406 * next power of two larger than ra_limit. 407 */ 408 409 ASSERT(ra_limit != 0); 410 411 kpm_size_shift = (ra_limit & (ra_limit - 1)) != 0 ? 412 highbit(ra_limit) : highbit(ra_limit) - 1; 413 414 /* 415 * No virtual caches on sun4v so size matches size shift 416 */ 417 kpm_size = 1ul << kpm_size_shift; 418 419 if (va_bits < VA_ADDRESS_SPACE_BITS) { 420 /* 421 * In case of VA hole 422 * kpm_base = hole_end + 1TB 423 * Starting 1TB beyond where VA hole ends because on Niagara 424 * processor software must not use pages within 4GB of the 425 * VA hole as instruction pages to avoid problems with 426 * prefetching into the VA hole. 427 */ 428 kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) + 429 (1ull << 40)); 430 } else { /* Number of VA bits 64 ... no VA hole */ 431 kpm_vbase = (caddr_t)0x8000000000000000ull; /* 8 EB */ 432 } 433 434 /* 435 * The traptrace code uses either %tick or %stick for 436 * timestamping. The sun4v require use of %stick. 437 */ 438 traptrace_use_stick = 1; 439 440 /* 441 * sun4v provides demap_all 442 */ 443 if (!disable_delay_tlb_flush) 444 delay_tlb_flush = 1; 445 } 446 447 /* 448 * Get the nctxs from MD. If absent panic. 449 */ 450 static uint64_t 451 get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 452 { 453 uint64_t ctx_bits; 454 455 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits", 456 &ctx_bits)) 457 ctx_bits = 0; 458 459 if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS) 460 cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits " 461 "returned by MD", ctx_bits); 462 463 return (ctx_bits); 464 } 465 466 /* 467 * Initalize supported page sizes information. 468 * Set to 0, if the page sizes mask information is absent in MD. 469 */ 470 static uint64_t 471 get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 472 { 473 uint64_t mmu_page_size_list; 474 475 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list", 476 &mmu_page_size_list)) 477 mmu_page_size_list = 0; 478 479 if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK) 480 cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned" 481 "by MD", mmu_page_size_list); 482 483 return (mmu_page_size_list); 484 } 485 486 /* 487 * This routine gets the isalist information from MD and appends 488 * the CPU module ISA set if required. 489 */ 490 static char * 491 construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie, 492 char **cpu_module_isa_set) 493 { 494 extern int at_flags; 495 char *md_isalist; 496 int md_isalen; 497 char *isabuf; 498 int isalen; 499 char **isa_set; 500 char *p, *q; 501 int cpu_module_isalen = 0, found = 0; 502 503 (void) md_get_prop_data(mdp, cpu_node_cookie, 504 "isalist", (uint8_t **)&isabuf, &isalen); 505 506 /* 507 * We support binaries for all the cpus that have shipped so far. 508 * The kernel emulates instructions that are not supported by hardware. 509 */ 510 at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1; 511 512 /* 513 * Construct the space separated isa_list. 514 */ 515 if (cpu_module_isa_set != NULL) { 516 for (isa_set = cpu_module_isa_set; *isa_set != NULL; 517 isa_set++) { 518 cpu_module_isalen += strlen(*isa_set); 519 cpu_module_isalen++; /* for space character */ 520 } 521 } 522 523 /* 524 * Allocate the buffer of MD isa buffer length + CPU module 525 * isa buffer length. 526 */ 527 md_isalen = isalen + cpu_module_isalen + 2; 528 md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0); 529 if (md_isalist == NULL) 530 cmn_err(CE_PANIC, "construct_isalist: Allocation failed for " 531 "md_isalist"); 532 533 md_isalist[0] = '\0'; /* create an empty string to start */ 534 for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) { 535 (void) strlcat(md_isalist, p, md_isalen); 536 (void) strcat(md_isalist, " "); 537 } 538 539 /* 540 * Check if the isa_set is present in isalist returned by MD. 541 * If yes, then no need to append it, if no then append it to 542 * isalist returned by MD. 543 */ 544 if (cpu_module_isa_set != NULL) { 545 for (isa_set = cpu_module_isa_set; *isa_set != NULL; 546 isa_set++) { 547 found = 0; 548 for (p = isabuf, q = p + isalen; p < q; 549 p += strlen(p) + 1) { 550 if (strcmp(p, *isa_set) == 0) { 551 found = 1; 552 break; 553 } 554 } 555 if (!found) { 556 (void) strlcat(md_isalist, *isa_set, md_isalen); 557 (void) strcat(md_isalist, " "); 558 } 559 } 560 } 561 562 /* Get rid of any trailing white spaces */ 563 md_isalist[strlen(md_isalist) - 1] = '\0'; 564 565 return (md_isalist); 566 } 567 568 uint64_t 569 get_ra_limit(md_t *mdp) 570 { 571 mde_cookie_t *mem_list; 572 mde_cookie_t *mblock_list; 573 int i; 574 int memnodes; 575 int nmblock; 576 uint64_t base; 577 uint64_t size; 578 uint64_t ra_limit = 0, new_limit = 0; 579 580 memnodes = md_alloc_scan_dag(mdp, 581 md_root_node(mdp), "memory", "fwd", &mem_list); 582 583 ASSERT(memnodes == 1); 584 585 nmblock = md_alloc_scan_dag(mdp, 586 mem_list[0], "mblock", "fwd", &mblock_list); 587 if (nmblock < 1) 588 cmn_err(CE_PANIC, "cannot find mblock nodes in MD"); 589 590 for (i = 0; i < nmblock; i++) { 591 if (md_get_prop_val(mdp, mblock_list[i], "base", &base)) 592 cmn_err(CE_PANIC, "base property missing from MD" 593 " mblock node"); 594 if (md_get_prop_val(mdp, mblock_list[i], "size", &size)) 595 cmn_err(CE_PANIC, "size property missing from MD" 596 " mblock node"); 597 598 ASSERT(size != 0); 599 600 new_limit = base + size; 601 602 if (base > new_limit) 603 cmn_err(CE_PANIC, "mblock in MD wrapped around"); 604 605 if (new_limit > ra_limit) 606 ra_limit = new_limit; 607 } 608 609 ASSERT(ra_limit != 0); 610 611 if (ra_limit > MAX_REAL_ADDRESS) { 612 cmn_err(CE_WARN, "Highest real address in MD too large" 613 " clipping to %llx\n", MAX_REAL_ADDRESS); 614 ra_limit = MAX_REAL_ADDRESS; 615 } 616 617 md_free_scan_dag(mdp, &mblock_list); 618 619 md_free_scan_dag(mdp, &mem_list); 620 621 return (ra_limit); 622 } 623 624 /* 625 * This routine sets the globals for CPU and DEV mondo queue entries and 626 * resumable and non-resumable error queue entries. 627 */ 628 static uint64_t 629 get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie, 630 char *qnamep, uint64_t default_entries) 631 { 632 uint64_t entries; 633 634 if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) { 635 if (!broken_md_flag) 636 cmn_err(CE_PANIC, "Missing %s property in MD cpu node", 637 qnamep); 638 entries = default_entries; 639 } else { 640 entries = 1 << entries; 641 } 642 return (entries); 643 } 644 645 646 static void 647 get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 648 { 649 cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie, 650 "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES); 651 652 dev_q_entries = get_single_q_size(mdp, cpu_node_cookie, 653 "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES); 654 655 cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie, 656 "q-resumable-#bits", CPU_RQ_ENTRIES); 657 658 cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie, 659 "q-nonresumable-#bits", CPU_NRQ_ENTRIES); 660 } 661 662 663 static void 664 get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 665 { 666 uint64_t value = VA_ADDRESS_SPACE_BITS; 667 668 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value)) 669 cmn_err(CE_PANIC, "mmu-#va-bits property not found in MD"); 670 671 672 if (value == 0 || value > VA_ADDRESS_SPACE_BITS) 673 cmn_err(CE_PANIC, "Incorrect number of va bits in MD"); 674 675 /* Do not expect number of VA bits to be more than 32-bit quantity */ 676 677 va_bits = (int)value; 678 679 /* 680 * Correct the value for VA bits on UltraSPARC-T1 based systems 681 * in case of broken MD. 682 */ 683 if (broken_md_flag) 684 va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS; 685 } 686 687 /* 688 * This routine returns the L2 cache information such as -- associativity, 689 * size and linesize. 690 */ 691 static int 692 get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie, 693 uint64_t *associativity, uint64_t *size, uint64_t *linesize) 694 { 695 mde_cookie_t *cachelist; 696 int ncaches, i; 697 uint64_t max_level; 698 699 ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache", 700 "fwd", &cachelist); 701 /* 702 * The "cache" node is optional in MD, therefore ncaches can be 0. 703 */ 704 if (ncaches < 1) { 705 return (0); 706 } 707 708 max_level = 0; 709 for (i = 0; i < ncaches; i++) { 710 uint64_t cache_level; 711 uint64_t local_assoc; 712 uint64_t local_size; 713 uint64_t local_lsize; 714 715 if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 716 continue; 717 718 if (cache_level <= max_level) continue; 719 720 /* If properties are missing from this cache ignore it */ 721 722 if ((md_get_prop_val(mdp, cachelist[i], 723 "associativity", &local_assoc))) { 724 continue; 725 } 726 727 if ((md_get_prop_val(mdp, cachelist[i], 728 "size", &local_size))) { 729 continue; 730 } 731 732 if ((md_get_prop_val(mdp, cachelist[i], 733 "line-size", &local_lsize))) { 734 continue; 735 } 736 737 max_level = cache_level; 738 *associativity = local_assoc; 739 *size = local_size; 740 *linesize = local_lsize; 741 } 742 743 md_free_scan_dag(mdp, &cachelist); 744 745 return ((max_level > 0) ? 1 : 0); 746 } 747 748 /* 749 * The broken_md_flag is set to 1, if the MD doesn't have 750 * the domaining-enabled property in the platform node and the platforms 751 * are Ontario and Erie. This flag is used to workaround some of the 752 * incorrect MD properties. 753 */ 754 static void 755 init_md_broken(md_t *mdp) 756 { 757 int nrnode; 758 mde_cookie_t *platlist, rootnode; 759 char *vbuf; 760 uint64_t val = 0; 761 762 rootnode = md_root_node(mdp); 763 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 764 765 nrnode = md_alloc_scan_dag(mdp, md_root_node(mdp), "platform", "fwd", 766 &platlist); 767 768 ASSERT(nrnode == 1); 769 770 if (md_get_prop_str(mdp, platlist[0], "name", &vbuf) != 0) 771 panic("platform name not found in machine description"); 772 773 /* 774 * If domaining-enable prop doesn't exist and the platform name is 775 * Ontario or Erie the md is broken. 776 */ 777 778 if (md_get_prop_val(mdp, platlist[0], "domaining-enabled", &val) != 0 && 779 ((strcmp(vbuf, ONTARIO_PLATNAME1) == 0) || 780 (strcmp(vbuf, ONTARIO_PLATNAME2) == 0) || 781 (strcmp(vbuf, ERIE_PLATNAME1) == 0) || 782 (strcmp(vbuf, ERIE_PLATNAME2) == 0))) 783 broken_md_flag = 1; 784 785 md_free_scan_dag(mdp, &platlist); 786 } 787