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