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