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 contexts, mmu page sizes mask, Q sizes and isalist/r 343 * from the MD for the first available CPU in cpulist. 344 */ 345 346 if (nctxs == 0) 347 nctxs = (uint_t)(1 << get_mmu_ctx_bits(mdp, cpulist[0])); 348 349 if (nctxs > MAX_NCTXS) 350 nctxs = MAX_NCTXS; 351 352 /* Do not expect the MMU page sizes mask to be more than 32-bit. */ 353 mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]); 354 355 for (i = 0; i < nocpus; i++) 356 fill_cpu(mdp, cpulist[i]); 357 358 setup_exec_unit_mappings(mdp); 359 360 vac_size = S_VAC_SIZE; 361 vac_mask = MMU_PAGEMASK & (vac_size - 1); 362 vac_shift = S_VAC_SHIFT; 363 shm_alignment = vac_size; 364 vac = 0; 365 366 /* 367 * If MD is broken then append the passed ISA set, 368 * otherwise trust the MD. 369 */ 370 371 if (broken_md_flag) 372 isa_list = construct_isalist(mdp, cpulist[0], 373 cpu_module_isa_set); 374 else 375 isa_list = construct_isalist(mdp, cpulist[0], NULL); 376 377 get_q_sizes(mdp, cpulist[0]); 378 379 get_va_bits(mdp, cpulist[0]); 380 381 /* 382 * ra_limit is the highest real address in the machine. 383 */ 384 ra_limit = get_ra_limit(mdp); 385 386 md_free_scan_dag(mdp, &cpulist); 387 388 (void) md_fini_handle(mdp); 389 390 /* 391 * Block stores invalidate all pages of the d$ so pagecopy 392 * et. al. do not need virtual translations with virtual 393 * coloring taken into consideration. 394 */ 395 pp_consistent_coloring = 0; 396 397 /* 398 * The kpm mapping window. 399 * kpm_size: 400 * The size of a single kpm range. 401 * The overall size will be: kpm_size * vac_colors. 402 * kpm_vbase: 403 * The virtual start address of the kpm range within the kernel 404 * virtual address space. kpm_vbase has to be kpm_size aligned. 405 */ 406 407 /* 408 * Make kpm_vbase, kpm_size aligned to kpm_size_shift. 409 * To do this find the nearest power of 2 size that the 410 * actual ra_limit fits within. 411 * If it is an even power of two use that, otherwise use the 412 * next power of two larger than ra_limit. 413 */ 414 415 ASSERT(ra_limit != 0); 416 417 kpm_size_shift = (ra_limit & (ra_limit - 1)) != 0 ? 418 highbit(ra_limit) : highbit(ra_limit) - 1; 419 420 /* 421 * No virtual caches on sun4v so size matches size shift 422 */ 423 kpm_size = 1ul << kpm_size_shift; 424 425 if (va_bits < VA_ADDRESS_SPACE_BITS) { 426 /* 427 * In case of VA hole 428 * kpm_base = hole_end + 1TB 429 * Starting 1TB beyond where VA hole ends because on Niagara 430 * processor software must not use pages within 4GB of the 431 * VA hole as instruction pages to avoid problems with 432 * prefetching into the VA hole. 433 */ 434 kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) + 435 (1ull << 40)); 436 } else { /* Number of VA bits 64 ... no VA hole */ 437 kpm_vbase = (caddr_t)0x8000000000000000ull; /* 8 EB */ 438 } 439 440 /* 441 * The traptrace code uses either %tick or %stick for 442 * timestamping. The sun4v require use of %stick. 443 */ 444 traptrace_use_stick = 1; 445 446 /* 447 * sun4v provides demap_all 448 */ 449 if (!disable_delay_tlb_flush) 450 delay_tlb_flush = 1; 451 } 452 453 /* 454 * Get the nctxs from MD. If absent panic. 455 */ 456 static uint64_t 457 get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 458 { 459 uint64_t ctx_bits; 460 461 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits", 462 &ctx_bits)) 463 ctx_bits = 0; 464 465 if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS) 466 cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits " 467 "returned by MD", ctx_bits); 468 469 return (ctx_bits); 470 } 471 472 /* 473 * Initalize supported page sizes information. 474 * Set to 0, if the page sizes mask information is absent in MD. 475 */ 476 static uint64_t 477 get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 478 { 479 uint64_t mmu_page_size_list; 480 481 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list", 482 &mmu_page_size_list)) 483 mmu_page_size_list = 0; 484 485 if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK) 486 cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned" 487 "by MD", mmu_page_size_list); 488 489 return (mmu_page_size_list); 490 } 491 492 /* 493 * This routine gets the isalist information from MD and appends 494 * the CPU module ISA set if required. 495 */ 496 static char * 497 construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie, 498 char **cpu_module_isa_set) 499 { 500 extern int at_flags; 501 char *md_isalist; 502 int md_isalen; 503 char *isabuf; 504 int isalen; 505 char **isa_set; 506 char *p, *q; 507 int cpu_module_isalen = 0, found = 0; 508 509 (void) md_get_prop_data(mdp, cpu_node_cookie, 510 "isalist", (uint8_t **)&isabuf, &isalen); 511 512 /* 513 * We support binaries for all the cpus that have shipped so far. 514 * The kernel emulates instructions that are not supported by hardware. 515 */ 516 at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1; 517 518 /* 519 * Construct the space separated isa_list. 520 */ 521 if (cpu_module_isa_set != NULL) { 522 for (isa_set = cpu_module_isa_set; *isa_set != NULL; 523 isa_set++) { 524 cpu_module_isalen += strlen(*isa_set); 525 cpu_module_isalen++; /* for space character */ 526 } 527 } 528 529 /* 530 * Allocate the buffer of MD isa buffer length + CPU module 531 * isa buffer length. 532 */ 533 md_isalen = isalen + cpu_module_isalen + 2; 534 md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0); 535 if (md_isalist == NULL) 536 cmn_err(CE_PANIC, "construct_isalist: Allocation failed for " 537 "md_isalist"); 538 539 md_isalist[0] = '\0'; /* create an empty string to start */ 540 for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) { 541 (void) strlcat(md_isalist, p, md_isalen); 542 (void) strcat(md_isalist, " "); 543 } 544 545 /* 546 * Check if the isa_set is present in isalist returned by MD. 547 * If yes, then no need to append it, if no then append it to 548 * isalist returned by MD. 549 */ 550 if (cpu_module_isa_set != NULL) { 551 for (isa_set = cpu_module_isa_set; *isa_set != NULL; 552 isa_set++) { 553 found = 0; 554 for (p = isabuf, q = p + isalen; p < q; 555 p += strlen(p) + 1) { 556 if (strcmp(p, *isa_set) == 0) { 557 found = 1; 558 break; 559 } 560 } 561 if (!found) { 562 (void) strlcat(md_isalist, *isa_set, md_isalen); 563 (void) strcat(md_isalist, " "); 564 } 565 } 566 } 567 568 /* Get rid of any trailing white spaces */ 569 md_isalist[strlen(md_isalist) - 1] = '\0'; 570 571 return (md_isalist); 572 } 573 574 uint64_t 575 get_ra_limit(md_t *mdp) 576 { 577 mde_cookie_t *mem_list; 578 mde_cookie_t *mblock_list; 579 int i; 580 int memnodes; 581 int nmblock; 582 uint64_t base; 583 uint64_t size; 584 uint64_t ra_limit = 0, new_limit = 0; 585 586 memnodes = md_alloc_scan_dag(mdp, 587 md_root_node(mdp), "memory", "fwd", &mem_list); 588 589 ASSERT(memnodes == 1); 590 591 nmblock = md_alloc_scan_dag(mdp, 592 mem_list[0], "mblock", "fwd", &mblock_list); 593 if (nmblock < 1) 594 cmn_err(CE_PANIC, "cannot find mblock nodes in MD"); 595 596 for (i = 0; i < nmblock; i++) { 597 if (md_get_prop_val(mdp, mblock_list[i], "base", &base)) 598 cmn_err(CE_PANIC, "base property missing from MD" 599 " mblock node"); 600 if (md_get_prop_val(mdp, mblock_list[i], "size", &size)) 601 cmn_err(CE_PANIC, "size property missing from MD" 602 " mblock node"); 603 604 ASSERT(size != 0); 605 606 new_limit = base + size; 607 608 if (base > new_limit) 609 cmn_err(CE_PANIC, "mblock in MD wrapped around"); 610 611 if (new_limit > ra_limit) 612 ra_limit = new_limit; 613 } 614 615 ASSERT(ra_limit != 0); 616 617 if (ra_limit > MAX_REAL_ADDRESS) { 618 cmn_err(CE_WARN, "Highest real address in MD too large" 619 " clipping to %llx\n", MAX_REAL_ADDRESS); 620 ra_limit = MAX_REAL_ADDRESS; 621 } 622 623 md_free_scan_dag(mdp, &mblock_list); 624 625 md_free_scan_dag(mdp, &mem_list); 626 627 return (ra_limit); 628 } 629 630 /* 631 * This routine sets the globals for CPU and DEV mondo queue entries and 632 * resumable and non-resumable error queue entries. 633 */ 634 static uint64_t 635 get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie, 636 char *qnamep, uint64_t default_entries) 637 { 638 uint64_t entries; 639 640 if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) { 641 if (!broken_md_flag) 642 cmn_err(CE_PANIC, "Missing %s property in MD cpu node", 643 qnamep); 644 entries = default_entries; 645 } else { 646 entries = 1 << entries; 647 } 648 return (entries); 649 } 650 651 652 static void 653 get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 654 { 655 cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie, 656 "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES); 657 658 dev_q_entries = get_single_q_size(mdp, cpu_node_cookie, 659 "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES); 660 661 cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie, 662 "q-resumable-#bits", CPU_RQ_ENTRIES); 663 664 cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie, 665 "q-nonresumable-#bits", CPU_NRQ_ENTRIES); 666 } 667 668 669 static void 670 get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 671 { 672 uint64_t value = VA_ADDRESS_SPACE_BITS; 673 674 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value)) 675 cmn_err(CE_PANIC, "mmu-#va-bits property not found in MD"); 676 677 678 if (value == 0 || value > VA_ADDRESS_SPACE_BITS) 679 cmn_err(CE_PANIC, "Incorrect number of va bits in MD"); 680 681 /* Do not expect number of VA bits to be more than 32-bit quantity */ 682 683 va_bits = (int)value; 684 685 /* 686 * Correct the value for VA bits on UltraSPARC-T1 based systems 687 * in case of broken MD. 688 */ 689 if (broken_md_flag) 690 va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS; 691 } 692 693 /* 694 * This routine returns the L2 cache information such as -- associativity, 695 * size and linesize. 696 */ 697 static int 698 get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie, 699 uint64_t *associativity, uint64_t *size, uint64_t *linesize) 700 { 701 mde_cookie_t *cachelist; 702 int ncaches, i; 703 uint64_t max_level; 704 705 ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache", 706 "fwd", &cachelist); 707 /* 708 * The "cache" node is optional in MD, therefore ncaches can be 0. 709 */ 710 if (ncaches < 1) { 711 return (0); 712 } 713 714 max_level = 0; 715 for (i = 0; i < ncaches; i++) { 716 uint64_t cache_level; 717 uint64_t local_assoc; 718 uint64_t local_size; 719 uint64_t local_lsize; 720 721 if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 722 continue; 723 724 if (cache_level <= max_level) continue; 725 726 /* If properties are missing from this cache ignore it */ 727 728 if ((md_get_prop_val(mdp, cachelist[i], 729 "associativity", &local_assoc))) { 730 continue; 731 } 732 733 if ((md_get_prop_val(mdp, cachelist[i], 734 "size", &local_size))) { 735 continue; 736 } 737 738 if ((md_get_prop_val(mdp, cachelist[i], 739 "line-size", &local_lsize))) { 740 continue; 741 } 742 743 max_level = cache_level; 744 *associativity = local_assoc; 745 *size = local_size; 746 *linesize = local_lsize; 747 } 748 749 md_free_scan_dag(mdp, &cachelist); 750 751 return ((max_level > 0) ? 1 : 0); 752 } 753 754 /* 755 * The broken_md_flag is set to 1, if the MD doesn't have 756 * the domaining-enabled property in the platform node and the platforms 757 * are Ontario and Erie. This flag is used to workaround some of the 758 * incorrect MD properties. 759 */ 760 static void 761 init_md_broken(md_t *mdp) 762 { 763 int nrnode; 764 mde_cookie_t *platlist, rootnode; 765 char *vbuf; 766 uint64_t val = 0; 767 768 rootnode = md_root_node(mdp); 769 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 770 771 nrnode = md_alloc_scan_dag(mdp, md_root_node(mdp), "platform", "fwd", 772 &platlist); 773 774 ASSERT(nrnode == 1); 775 776 if (md_get_prop_str(mdp, platlist[0], "name", &vbuf) != 0) 777 panic("platform name not found in machine description"); 778 779 /* 780 * If domaining-enable prop doesn't exist and the platform name is 781 * Ontario or Erie the md is broken. 782 */ 783 784 if (md_get_prop_val(mdp, platlist[0], "domaining-enabled", &val) != 0 && 785 ((strcmp(vbuf, ONTARIO_PLATNAME1) == 0) || 786 (strcmp(vbuf, ONTARIO_PLATNAME2) == 0) || 787 (strcmp(vbuf, ERIE_PLATNAME1) == 0) || 788 (strcmp(vbuf, ERIE_PLATNAME2) == 0))) 789 broken_md_flag = 1; 790 791 md_free_scan_dag(mdp, &platlist); 792 } 793