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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/errno.h> 27 #include <sys/types.h> 28 #include <sys/param.h> 29 #include <sys/cpu.h> 30 #include <sys/cpuvar.h> 31 #include <sys/clock.h> 32 #include <sys/promif.h> 33 #include <sys/promimpl.h> 34 #include <sys/systm.h> 35 #include <sys/machsystm.h> 36 #include <sys/debug.h> 37 #include <sys/sunddi.h> 38 #include <sys/modctl.h> 39 #include <sys/cpu_module.h> 40 #include <sys/kobj.h> 41 #include <sys/cmp.h> 42 #include <sys/async.h> 43 #include <vm/page.h> 44 #include <vm/vm_dep.h> 45 #include <vm/hat_sfmmu.h> 46 #include <sys/sysmacros.h> 47 #include <sys/mach_descrip.h> 48 #include <sys/mdesc.h> 49 #include <sys/archsystm.h> 50 #include <sys/error.h> 51 #include <sys/mmu.h> 52 #include <sys/bitmap.h> 53 #include <sys/intreg.h> 54 55 struct cpu_node cpunodes[NCPU]; 56 57 uint64_t cpu_q_entries; 58 uint64_t dev_q_entries; 59 uint64_t cpu_rq_entries; 60 uint64_t cpu_nrq_entries; 61 uint64_t ncpu_guest_max; 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_mmu_tsbs(md_t *, mde_cookie_t); 67 static uint64_t get_mmu_shcontexts(md_t *, mde_cookie_t); 68 static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t); 69 static int check_mmu_pgsz_search(md_t *, mde_cookie_t); 70 static char *construct_isalist(md_t *, mde_cookie_t, char **); 71 static void init_md_broken(md_t *, mde_cookie_t *); 72 static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *, 73 uint64_t *); 74 static void get_hwcaps(md_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 static int get_l2_cache_node_count(md_t *); 79 static unsigned long names2bits(char *tokens, size_t tokenslen, 80 char *bit_formatter, char *warning); 81 82 uint64_t system_clock_freq; 83 uint_t niommu_tsbs = 0; 84 85 static int n_l2_caches = 0; 86 87 /* prevent compilation with VAC defined */ 88 #ifdef VAC 89 #error "The sun4v architecture does not support VAC" 90 #endif 91 92 #define S_VAC_SIZE MMU_PAGESIZE 93 #define S_VAC_SHIFT MMU_PAGESHIFT 94 95 int vac_size = S_VAC_SIZE; 96 uint_t vac_mask = MMU_PAGEMASK & (S_VAC_SIZE - 1); 97 int vac_shift = S_VAC_SHIFT; 98 uintptr_t shm_alignment = S_VAC_SIZE; 99 100 void 101 map_wellknown_devices() 102 { 103 } 104 105 void 106 fill_cpu(md_t *mdp, mde_cookie_t cpuc) 107 { 108 struct cpu_node *cpunode; 109 uint64_t cpuid; 110 uint64_t clk_freq; 111 char *namebuf; 112 char *namebufp; 113 int namelen; 114 uint64_t associativity = 0, linesize = 0, size = 0; 115 116 if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) { 117 return; 118 } 119 120 /* All out-of-range cpus will be stopped later. */ 121 if (cpuid >= NCPU) { 122 cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - " 123 "cpu excluded from configuration\n", cpuid); 124 125 return; 126 } 127 128 cpunode = &cpunodes[cpuid]; 129 cpunode->cpuid = (int)cpuid; 130 cpunode->device_id = cpuid; 131 132 if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI)) 133 (void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI); 134 135 if (md_get_prop_data(mdp, cpuc, 136 "compatible", (uint8_t **)&namebuf, &namelen)) { 137 cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible " 138 "property"); 139 } 140 namebufp = namebuf; 141 if (strncmp(namebufp, "SUNW,", 5) == 0) 142 namebufp += 5; 143 if (strlen(namebufp) > sizeof (cpunode->name)) 144 cmn_err(CE_PANIC, "Compatible property too big to " 145 "fit into the cpunode name buffer"); 146 (void) strcpy(cpunode->name, namebufp); 147 148 if (md_get_prop_val(mdp, cpuc, 149 "clock-frequency", &clk_freq)) { 150 clk_freq = 0; 151 } 152 cpunode->clock_freq = clk_freq; 153 154 ASSERT(cpunode->clock_freq != 0); 155 /* 156 * Compute scaling factor based on rate of %tick. This is used 157 * to convert from ticks derived from %tick to nanoseconds. See 158 * comment in sun4u/sys/clock.h for details. 159 */ 160 cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << 161 (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); 162 163 /* 164 * The nodeid is not used in sun4v at all. Setting it 165 * to positive value to make starting of slave CPUs 166 * code happy. 167 */ 168 cpunode->nodeid = cpuid + 1; 169 170 /* 171 * Obtain the L2 cache information from MD. 172 * If "Cache" node exists, then set L2 cache properties 173 * as read from MD. 174 * If node does not exists, then set the L2 cache properties 175 * in individual CPU module. 176 */ 177 if ((!get_l2_cache_info(mdp, cpuc, 178 &associativity, &size, &linesize)) || 179 associativity == 0 || size == 0 || linesize == 0) { 180 cpu_fiximp(cpunode); 181 } else { 182 /* 183 * Do not expect L2 cache properties to be bigger 184 * than 32-bit quantity. 185 */ 186 cpunode->ecache_associativity = (int)associativity; 187 cpunode->ecache_size = (int)size; 188 cpunode->ecache_linesize = (int)linesize; 189 } 190 191 cpunode->ecache_setsize = 192 cpunode->ecache_size / cpunode->ecache_associativity; 193 194 /* 195 * Initialize the mapping for exec unit, chip and core. 196 */ 197 cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND; 198 cpunode->l2_cache_mapping = NO_MAPPING_FOUND; 199 cpunode->core_mapping = NO_CORE_MAPPING_FOUND; 200 201 if (ecache_setsize == 0) 202 ecache_setsize = cpunode->ecache_setsize; 203 if (ecache_alignsize == 0) 204 ecache_alignsize = cpunode->ecache_linesize; 205 206 } 207 208 void 209 empty_cpu(int cpuid) 210 { 211 bzero(&cpunodes[cpuid], sizeof (struct cpu_node)); 212 } 213 214 /* 215 * Use L2 cache node to derive the chip mapping. 216 */ 217 void 218 setup_chip_mappings(md_t *mdp) 219 { 220 int ncache, ncpu; 221 mde_cookie_t *node, *cachelist; 222 int i, j; 223 processorid_t cpuid; 224 int idx = 0; 225 226 ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache", 227 "fwd", &cachelist); 228 229 /* 230 * The "cache" node is optional in MD, therefore ncaches can be 0. 231 */ 232 if (ncache < 1) { 233 return; 234 } 235 236 for (i = 0; i < ncache; i++) { 237 uint64_t cache_level; 238 uint64_t lcpuid; 239 240 if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 241 continue; 242 243 if (cache_level != 2) 244 continue; 245 246 /* 247 * Found a l2 cache node. Find out the cpu nodes it 248 * points to. 249 */ 250 ncpu = md_alloc_scan_dag(mdp, cachelist[i], "cpu", 251 "back", &node); 252 253 if (ncpu < 1) 254 continue; 255 256 for (j = 0; j < ncpu; j++) { 257 if (md_get_prop_val(mdp, node[j], "id", &lcpuid)) 258 continue; 259 if (lcpuid >= NCPU) 260 continue; 261 cpuid = (processorid_t)lcpuid; 262 cpunodes[cpuid].l2_cache_mapping = idx; 263 } 264 md_free_scan_dag(mdp, &node); 265 266 idx++; 267 } 268 269 md_free_scan_dag(mdp, &cachelist); 270 } 271 272 void 273 setup_exec_unit_mappings(md_t *mdp) 274 { 275 int num, num_eunits; 276 mde_cookie_t cpus_node; 277 mde_cookie_t *node, *eunit; 278 int idx, i, j; 279 processorid_t cpuid; 280 char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit"; 281 enum eu_type { INTEGER, FPU } etype; 282 283 /* 284 * Find the cpu integer exec units - and 285 * setup the mappings appropriately. 286 */ 287 num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node); 288 if (num < 1) 289 cmn_err(CE_PANIC, "No cpus node in machine description"); 290 if (num > 1) 291 cmn_err(CE_PANIC, "More than 1 cpus node in machine" 292 " description"); 293 294 cpus_node = node[0]; 295 md_free_scan_dag(mdp, &node); 296 297 num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name, 298 "fwd", &eunit); 299 if (num_eunits > 0) { 300 char *int_str = broken_md_flag ? "int" : "integer"; 301 char *fpu_str = "fp"; 302 303 /* Spin through and find all the integer exec units */ 304 for (i = 0; i < num_eunits; i++) { 305 char *p; 306 char *val; 307 int vallen; 308 uint64_t lcpuid; 309 310 /* ignore nodes with no type */ 311 if (md_get_prop_data(mdp, eunit[i], "type", 312 (uint8_t **)&val, &vallen)) 313 continue; 314 315 for (p = val; *p != '\0'; p += strlen(p) + 1) { 316 if (strcmp(p, int_str) == 0) { 317 etype = INTEGER; 318 goto found; 319 } 320 if (strcmp(p, fpu_str) == 0) { 321 etype = FPU; 322 goto found; 323 } 324 } 325 326 continue; 327 found: 328 idx = NCPU + i; 329 /* 330 * find the cpus attached to this EU and 331 * update their mapping indices 332 */ 333 num = md_alloc_scan_dag(mdp, eunit[i], "cpu", 334 "back", &node); 335 336 if (num < 1) 337 cmn_err(CE_PANIC, "exec-unit node in MD" 338 " not attached to a cpu node"); 339 340 for (j = 0; j < num; j++) { 341 if (md_get_prop_val(mdp, node[j], "id", 342 &lcpuid)) 343 continue; 344 if (lcpuid >= NCPU) 345 continue; 346 cpuid = (processorid_t)lcpuid; 347 switch (etype) { 348 case INTEGER: 349 cpunodes[cpuid].exec_unit_mapping = idx; 350 break; 351 case FPU: 352 cpunodes[cpuid].fpu_mapping = idx; 353 break; 354 } 355 } 356 md_free_scan_dag(mdp, &node); 357 } 358 md_free_scan_dag(mdp, &eunit); 359 } 360 } 361 362 /* 363 * Setup instruction cache coherency. The "memory-coherent" property 364 * is optional. Default for Icache_coherency is 1 (I$ is coherent). 365 * If we find an Icache with coherency == 0, then enable non-coherent 366 * Icache support. 367 */ 368 void 369 setup_icache_coherency(md_t *mdp) 370 { 371 int ncache; 372 mde_cookie_t *cachelist; 373 int i; 374 375 ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache", 376 "fwd", &cachelist); 377 378 /* 379 * The "cache" node is optional in MD, therefore ncaches can be 0. 380 */ 381 if (ncache < 1) { 382 return; 383 } 384 385 for (i = 0; i < ncache; i++) { 386 uint64_t cache_level; 387 uint64_t memory_coherent; 388 uint8_t *type; 389 int typelen; 390 391 if (md_get_prop_val(mdp, cachelist[i], "level", 392 &cache_level)) 393 continue; 394 395 if (cache_level != 1) 396 continue; 397 398 if (md_get_prop_data(mdp, cachelist[i], "type", 399 &type, &typelen)) 400 continue; 401 402 if (strcmp((char *)type, "instn") != 0) 403 continue; 404 405 if (md_get_prop_val(mdp, cachelist[i], "memory-coherent", 406 &memory_coherent)) 407 continue; 408 409 if (memory_coherent != 0) 410 continue; 411 412 mach_setup_icache(memory_coherent); 413 break; 414 } 415 416 md_free_scan_dag(mdp, &cachelist); 417 } 418 419 /* 420 * All the common setup of sun4v CPU modules is done by this routine. 421 */ 422 void 423 cpu_setup_common(char **cpu_module_isa_set) 424 { 425 extern int mmu_exported_pagesize_mask; 426 int nocpus, i; 427 size_t ra_limit; 428 mde_cookie_t *cpulist; 429 md_t *mdp; 430 431 if ((mdp = md_get_handle()) == NULL) 432 cmn_err(CE_PANIC, "Unable to initialize machine description"); 433 434 boot_ncpus = nocpus = md_alloc_scan_dag(mdp, 435 md_root_node(mdp), "cpu", "fwd", &cpulist); 436 if (nocpus < 1) { 437 cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation " 438 "failed or incorrect number of CPUs in MD"); 439 } 440 441 init_md_broken(mdp, cpulist); 442 443 if (use_page_coloring) { 444 do_pg_coloring = 1; 445 } 446 447 /* 448 * Get the valid mmu page sizes mask, Q sizes and isalist/r 449 * from the MD for the first available CPU in cpulist. 450 * 451 * Do not expect the MMU page sizes mask to be more than 32-bit. 452 */ 453 mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]); 454 455 /* 456 * Get the number of contexts and tsbs supported. 457 */ 458 if (get_mmu_shcontexts(mdp, cpulist[0]) >= MIN_NSHCONTEXTS && 459 get_mmu_tsbs(mdp, cpulist[0]) >= MIN_NTSBS) { 460 shctx_on = 1; 461 } 462 463 /* 464 * Get and check page search register properties. 465 */ 466 pgsz_search_on = check_mmu_pgsz_search(mdp, cpulist[0]); 467 468 for (i = 0; i < nocpus; i++) 469 fill_cpu(mdp, cpulist[i]); 470 471 /* setup l2 cache count. */ 472 n_l2_caches = get_l2_cache_node_count(mdp); 473 474 setup_chip_mappings(mdp); 475 setup_exec_unit_mappings(mdp); 476 setup_icache_coherency(mdp); 477 478 /* 479 * If MD is broken then append the passed ISA set, 480 * otherwise trust the MD. 481 */ 482 483 if (broken_md_flag) 484 isa_list = construct_isalist(mdp, cpulist[0], 485 cpu_module_isa_set); 486 else 487 isa_list = construct_isalist(mdp, cpulist[0], NULL); 488 489 get_hwcaps(mdp, cpulist[0]); 490 get_q_sizes(mdp, cpulist[0]); 491 get_va_bits(mdp, cpulist[0]); 492 493 /* 494 * ra_limit is the highest real address in the machine. 495 */ 496 ra_limit = get_ra_limit(mdp); 497 498 md_free_scan_dag(mdp, &cpulist); 499 500 (void) md_fini_handle(mdp); 501 502 /* 503 * Block stores invalidate all pages of the d$ so pagecopy 504 * et. al. do not need virtual translations with virtual 505 * coloring taken into consideration. 506 */ 507 pp_consistent_coloring = 0; 508 509 /* 510 * The kpm mapping window. 511 * kpm_size: 512 * The size of a single kpm range. 513 * The overall size will be: kpm_size * vac_colors. 514 * kpm_vbase: 515 * The virtual start address of the kpm range within the kernel 516 * virtual address space. kpm_vbase has to be kpm_size aligned. 517 */ 518 519 /* 520 * Make kpm_vbase, kpm_size aligned to kpm_size_shift. 521 * To do this find the nearest power of 2 size that the 522 * actual ra_limit fits within. 523 * If it is an even power of two use that, otherwise use the 524 * next power of two larger than ra_limit. 525 */ 526 527 ASSERT(ra_limit != 0); 528 529 kpm_size_shift = (ra_limit & (ra_limit - 1)) != 0 ? 530 highbit(ra_limit) : highbit(ra_limit) - 1; 531 532 /* 533 * No virtual caches on sun4v so size matches size shift 534 */ 535 kpm_size = 1ul << kpm_size_shift; 536 537 if (va_bits < VA_ADDRESS_SPACE_BITS) { 538 /* 539 * In case of VA hole 540 * kpm_base = hole_end + 1TB 541 * Starting 1TB beyond where VA hole ends because on Niagara 542 * processor software must not use pages within 4GB of the 543 * VA hole as instruction pages to avoid problems with 544 * prefetching into the VA hole. 545 */ 546 kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) + 547 (1ull << 40)); 548 } else { /* Number of VA bits 64 ... no VA hole */ 549 kpm_vbase = (caddr_t)0x8000000000000000ull; /* 8 EB */ 550 } 551 552 /* 553 * The traptrace code uses either %tick or %stick for 554 * timestamping. The sun4v require use of %stick. 555 */ 556 traptrace_use_stick = 1; 557 } 558 559 /* 560 * Get the nctxs from MD. If absent panic. 561 */ 562 static uint64_t 563 get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 564 { 565 uint64_t ctx_bits; 566 567 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits", 568 &ctx_bits)) 569 ctx_bits = 0; 570 571 if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS) 572 cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits " 573 "returned by MD", ctx_bits); 574 575 return (ctx_bits); 576 } 577 578 /* 579 * Get the number of tsbs from MD. If absent the default value is 0. 580 */ 581 static uint64_t 582 get_mmu_tsbs(md_t *mdp, mde_cookie_t cpu_node_cookie) 583 { 584 uint64_t number_tsbs; 585 586 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-#tsbs", 587 &number_tsbs)) 588 number_tsbs = 0; 589 590 return (number_tsbs); 591 } 592 593 /* 594 * Get the number of shared contexts from MD. If absent the default value is 0. 595 * 596 */ 597 static uint64_t 598 get_mmu_shcontexts(md_t *mdp, mde_cookie_t cpu_node_cookie) 599 { 600 uint64_t number_contexts; 601 602 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#shared-contexts", 603 &number_contexts)) 604 number_contexts = 0; 605 606 return (number_contexts); 607 } 608 609 /* 610 * Initalize supported page sizes information. 611 * Set to 0, if the page sizes mask information is absent in MD. 612 */ 613 static uint64_t 614 get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 615 { 616 uint64_t mmu_page_size_list; 617 618 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list", 619 &mmu_page_size_list)) 620 mmu_page_size_list = 0; 621 622 if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK) 623 cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned" 624 "by MD", mmu_page_size_list); 625 626 return (mmu_page_size_list); 627 } 628 629 /* 630 * This routine gets the isalist information from MD and appends 631 * the CPU module ISA set if required. 632 */ 633 static char * 634 construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie, 635 char **cpu_module_isa_set) 636 { 637 extern int at_flags; 638 char *md_isalist; 639 int md_isalen; 640 char *isabuf; 641 int isalen; 642 char **isa_set; 643 char *p, *q; 644 int cpu_module_isalen = 0, found = 0; 645 646 (void) md_get_prop_data(mdp, cpu_node_cookie, 647 "isalist", (uint8_t **)&isabuf, &isalen); 648 649 /* 650 * We support binaries for all the cpus that have shipped so far. 651 * The kernel emulates instructions that are not supported by hardware. 652 */ 653 at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1; 654 655 /* 656 * Construct the space separated isa_list. 657 */ 658 if (cpu_module_isa_set != NULL) { 659 for (isa_set = cpu_module_isa_set; *isa_set != NULL; 660 isa_set++) { 661 cpu_module_isalen += strlen(*isa_set); 662 cpu_module_isalen++; /* for space character */ 663 } 664 } 665 666 /* 667 * Allocate the buffer of MD isa buffer length + CPU module 668 * isa buffer length. 669 */ 670 md_isalen = isalen + cpu_module_isalen + 2; 671 md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0); 672 if (md_isalist == NULL) 673 cmn_err(CE_PANIC, "construct_isalist: Allocation failed for " 674 "md_isalist"); 675 676 md_isalist[0] = '\0'; /* create an empty string to start */ 677 for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) { 678 (void) strlcat(md_isalist, p, md_isalen); 679 (void) strcat(md_isalist, " "); 680 } 681 682 /* 683 * Check if the isa_set is present in isalist returned by MD. 684 * If yes, then no need to append it, if no then append it to 685 * isalist returned by MD. 686 */ 687 if (cpu_module_isa_set != NULL) { 688 for (isa_set = cpu_module_isa_set; *isa_set != NULL; 689 isa_set++) { 690 found = 0; 691 for (p = isabuf, q = p + isalen; p < q; 692 p += strlen(p) + 1) { 693 if (strcmp(p, *isa_set) == 0) { 694 found = 1; 695 break; 696 } 697 } 698 if (!found) { 699 (void) strlcat(md_isalist, *isa_set, md_isalen); 700 (void) strcat(md_isalist, " "); 701 } 702 } 703 } 704 705 /* Get rid of any trailing white spaces */ 706 md_isalist[strlen(md_isalist) - 1] = '\0'; 707 708 return (md_isalist); 709 } 710 711 static void 712 get_hwcaps(md_t *mdp, mde_cookie_t cpu_node_cookie) 713 { 714 char *hwcapbuf; 715 int hwcaplen; 716 717 if (md_get_prop_data(mdp, cpu_node_cookie, 718 "hwcap-list", (uint8_t **)&hwcapbuf, &hwcaplen)) { 719 /* Property not found */ 720 return; 721 } 722 723 cpu_hwcap_flags |= names2bits(hwcapbuf, hwcaplen, FMT_AV_SPARC, 724 "unrecognized token: %s"); 725 } 726 727 728 /* 729 * Does the opposite of cmn_err(9f) "%b" conversion specification: 730 * Given a list of strings, converts them to a bit-vector. 731 * 732 * tokens - is a buffer of [NUL-terminated] strings. 733 * tokenslen - length of tokenbuf in bytes. 734 * bit_formatter - is a %b format string, such as FMT_AV_SPARC 735 * from /usr/include/sys/auxv_SPARC.h, of the form: 736 * <base-char>[<bit-char><token-string>]... 737 * <base-char> is ignored. 738 * <bit-char> is [1-32], as per cmn_err(9f). 739 * warning - is a printf-style format string containing "%s", 740 * which is used to print a warning message when an unrecognized 741 * token is found. If warning is NULL, no warning is printed. 742 * Returns a bit-vector corresponding to the specified tokens. 743 */ 744 745 static unsigned long 746 names2bits(char *tokens, size_t tokenslen, char *bit_formatter, char *warning) 747 { 748 char *cur; 749 size_t curlen; 750 unsigned long ul = 0; 751 char *hit; 752 char *bs; 753 754 bit_formatter++; /* skip base; not needed for input */ 755 cur = tokens; 756 while (tokenslen) { 757 curlen = strlen(cur); 758 bs = bit_formatter; 759 /* 760 * We need a complicated while loop and the >=32 check, 761 * instead of a simple "if (strstr())" so that when the 762 * token is "vis", we don't match on "vis2" (for example). 763 */ 764 /* LINTED E_EQUALITY_NOT_ASSIGNMENT */ 765 while ((hit = strstr(bs, cur)) && 766 *(hit + curlen) >= 32) { 767 /* 768 * We're still in the middle of a word, i.e., not 769 * pointing at a <bit-char>. So advance ptr 770 * to ensure forward progress. 771 */ 772 bs = hit + curlen + 1; 773 } 774 775 if (hit != NULL) { 776 ul |= (1<<(*(hit-1) - 1)); 777 } else { 778 /* The token wasn't found in bit_formatter */ 779 if (warning != NULL) 780 cmn_err(CE_WARN, warning, cur); 781 } 782 tokenslen -= curlen + 1; 783 cur += curlen + 1; 784 } 785 return (ul); 786 } 787 788 789 uint64_t 790 get_ra_limit(md_t *mdp) 791 { 792 mde_cookie_t *mem_list; 793 mde_cookie_t *mblock_list; 794 int i; 795 int memnodes; 796 int nmblock; 797 uint64_t base; 798 uint64_t size; 799 uint64_t ra_limit = 0, new_limit = 0; 800 801 memnodes = md_alloc_scan_dag(mdp, 802 md_root_node(mdp), "memory", "fwd", &mem_list); 803 804 ASSERT(memnodes == 1); 805 806 nmblock = md_alloc_scan_dag(mdp, 807 mem_list[0], "mblock", "fwd", &mblock_list); 808 if (nmblock < 1) 809 cmn_err(CE_PANIC, "cannot find mblock nodes in MD"); 810 811 for (i = 0; i < nmblock; i++) { 812 if (md_get_prop_val(mdp, mblock_list[i], "base", &base)) 813 cmn_err(CE_PANIC, "base property missing from MD" 814 " mblock node"); 815 if (md_get_prop_val(mdp, mblock_list[i], "size", &size)) 816 cmn_err(CE_PANIC, "size property missing from MD" 817 " mblock node"); 818 819 ASSERT(size != 0); 820 821 new_limit = base + size; 822 823 if (base > new_limit) 824 cmn_err(CE_PANIC, "mblock in MD wrapped around"); 825 826 if (new_limit > ra_limit) 827 ra_limit = new_limit; 828 } 829 830 ASSERT(ra_limit != 0); 831 832 if (ra_limit > MAX_REAL_ADDRESS) { 833 cmn_err(CE_WARN, "Highest real address in MD too large" 834 " clipping to %llx\n", MAX_REAL_ADDRESS); 835 ra_limit = MAX_REAL_ADDRESS; 836 } 837 838 md_free_scan_dag(mdp, &mblock_list); 839 840 md_free_scan_dag(mdp, &mem_list); 841 842 return (ra_limit); 843 } 844 845 /* 846 * This routine sets the globals for CPU and DEV mondo queue entries and 847 * resumable and non-resumable error queue entries. 848 * 849 * First, look up the number of bits available to pass an entry number. 850 * This can vary by platform and may result in allocating an unreasonably 851 * (or impossibly) large amount of memory for the corresponding table, 852 * so we clamp it by 'max_entries'. Finally, since the q size is used when 853 * calling contig_mem_alloc(), which expects a power of 2, clamp the q size 854 * down to a power of 2. If the prop is missing, use 'default_entries'. 855 */ 856 static uint64_t 857 get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie, 858 char *qnamep, uint64_t default_entries, uint64_t max_entries) 859 { 860 uint64_t entries; 861 862 if (default_entries > max_entries) 863 cmn_err(CE_CONT, "!get_single_q_size: dflt %ld > " 864 "max %ld for %s\n", default_entries, max_entries, qnamep); 865 866 if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) { 867 if (!broken_md_flag) 868 cmn_err(CE_PANIC, "Missing %s property in MD cpu node", 869 qnamep); 870 entries = default_entries; 871 } else { 872 entries = 1 << entries; 873 } 874 875 entries = MIN(entries, max_entries); 876 /* If not a power of 2, truncate to a power of 2. */ 877 if ((entries & (entries - 1)) != 0) { 878 entries = 1 << (highbit(entries) - 1); 879 } 880 881 return (entries); 882 } 883 884 /* Scaling constant used to compute size of cpu mondo queue */ 885 #define CPU_MONDO_Q_MULTIPLIER 8 886 887 static void 888 get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 889 { 890 uint64_t max_qsize; 891 mde_cookie_t *platlist; 892 int nrnode; 893 894 /* 895 * Compute the maximum number of entries for the cpu mondo queue. 896 * Use the appropriate property in the platform node, if it is 897 * available. Else, base it on NCPU. 898 */ 899 nrnode = md_alloc_scan_dag(mdp, 900 md_root_node(mdp), "platform", "fwd", &platlist); 901 902 ASSERT(nrnode == 1); 903 904 ncpu_guest_max = NCPU; 905 (void) md_get_prop_val(mdp, platlist[0], "max-cpus", &ncpu_guest_max); 906 max_qsize = ncpu_guest_max * CPU_MONDO_Q_MULTIPLIER; 907 908 md_free_scan_dag(mdp, &platlist); 909 910 cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie, 911 "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES, max_qsize); 912 913 dev_q_entries = get_single_q_size(mdp, cpu_node_cookie, 914 "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES, MAXIVNUM); 915 916 cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie, 917 "q-resumable-#bits", CPU_RQ_ENTRIES, MAX_CPU_RQ_ENTRIES); 918 919 cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie, 920 "q-nonresumable-#bits", CPU_NRQ_ENTRIES, MAX_CPU_NRQ_ENTRIES); 921 } 922 923 924 static void 925 get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 926 { 927 uint64_t value = VA_ADDRESS_SPACE_BITS; 928 929 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value)) 930 cmn_err(CE_PANIC, "mmu-#va-bits property not found in MD"); 931 932 933 if (value == 0 || value > VA_ADDRESS_SPACE_BITS) 934 cmn_err(CE_PANIC, "Incorrect number of va bits in MD"); 935 936 /* Do not expect number of VA bits to be more than 32-bit quantity */ 937 938 va_bits = (int)value; 939 940 /* 941 * Correct the value for VA bits on UltraSPARC-T1 based systems 942 * in case of broken MD. 943 */ 944 if (broken_md_flag) 945 va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS; 946 } 947 948 int 949 l2_cache_node_count(void) 950 { 951 return (n_l2_caches); 952 } 953 954 /* 955 * count the number of l2 caches. 956 */ 957 int 958 get_l2_cache_node_count(md_t *mdp) 959 { 960 int i; 961 mde_cookie_t *cachenodes; 962 uint64_t level; 963 int n_cachenodes = md_alloc_scan_dag(mdp, md_root_node(mdp), 964 "cache", "fwd", &cachenodes); 965 int l2_caches = 0; 966 967 for (i = 0; i < n_cachenodes; i++) { 968 if (md_get_prop_val(mdp, cachenodes[i], "level", &level) != 0) { 969 level = 0; 970 } 971 if (level == 2) { 972 l2_caches++; 973 } 974 } 975 md_free_scan_dag(mdp, &cachenodes); 976 return (l2_caches); 977 } 978 979 /* 980 * This routine returns the L2 cache information such as -- associativity, 981 * size and linesize. 982 */ 983 static int 984 get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie, 985 uint64_t *associativity, uint64_t *size, uint64_t *linesize) 986 { 987 mde_cookie_t *cachelist; 988 int ncaches, i; 989 uint64_t cache_level = 0; 990 991 ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache", 992 "fwd", &cachelist); 993 /* 994 * The "cache" node is optional in MD, therefore ncaches can be 0. 995 */ 996 if (ncaches < 1) { 997 return (0); 998 } 999 1000 for (i = 0; i < ncaches; i++) { 1001 uint64_t local_assoc; 1002 uint64_t local_size; 1003 uint64_t local_lsize; 1004 1005 if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 1006 continue; 1007 1008 if (cache_level != 2) continue; 1009 1010 /* If properties are missing from this cache ignore it */ 1011 1012 if ((md_get_prop_val(mdp, cachelist[i], 1013 "associativity", &local_assoc))) { 1014 continue; 1015 } 1016 1017 if ((md_get_prop_val(mdp, cachelist[i], 1018 "size", &local_size))) { 1019 continue; 1020 } 1021 1022 if ((md_get_prop_val(mdp, cachelist[i], 1023 "line-size", &local_lsize))) { 1024 continue; 1025 } 1026 1027 *associativity = local_assoc; 1028 *size = local_size; 1029 *linesize = local_lsize; 1030 break; 1031 } 1032 1033 md_free_scan_dag(mdp, &cachelist); 1034 1035 return ((cache_level == 2) ? 1 : 0); 1036 } 1037 1038 1039 /* 1040 * Set the broken_md_flag to 1 if the MD doesn't have 1041 * the domaining-enabled property in the platform node and the 1042 * platform uses the UltraSPARC-T1 cpu. This flag is used to 1043 * workaround some of the incorrect MD properties. 1044 */ 1045 static void 1046 init_md_broken(md_t *mdp, mde_cookie_t *cpulist) 1047 { 1048 int nrnode; 1049 mde_cookie_t *platlist, rootnode; 1050 uint64_t val = 0; 1051 char *namebuf; 1052 int namelen; 1053 1054 rootnode = md_root_node(mdp); 1055 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 1056 ASSERT(cpulist); 1057 1058 nrnode = md_alloc_scan_dag(mdp, rootnode, "platform", "fwd", 1059 &platlist); 1060 1061 if (nrnode < 1) 1062 cmn_err(CE_PANIC, "init_md_broken: platform node missing"); 1063 1064 if (md_get_prop_data(mdp, cpulist[0], 1065 "compatible", (uint8_t **)&namebuf, &namelen)) { 1066 cmn_err(CE_PANIC, "init_md_broken: " 1067 "Cannot read 'compatible' property of 'cpu' node"); 1068 } 1069 1070 if (md_get_prop_val(mdp, platlist[0], 1071 "domaining-enabled", &val) == -1 && 1072 strcmp(namebuf, "SUNW,UltraSPARC-T1") == 0) 1073 broken_md_flag = 1; 1074 1075 md_free_scan_dag(mdp, &platlist); 1076 } 1077 1078 /* 1079 * This routine gets the MD properties associated with the TLB search order API 1080 * and compares these against the expected values for a processor which supports 1081 * this API. The return value is used to determine whether use the API. 1082 */ 1083 static int 1084 check_mmu_pgsz_search(md_t *mdp, mde_cookie_t cpu_node_cookie) 1085 { 1086 1087 uint64_t mmu_search_nshared_contexts; 1088 uint64_t mmu_max_search_order; 1089 uint64_t mmu_non_priv_search_unified; 1090 uint64_t mmu_search_page_size_list; 1091 1092 if (md_get_prop_val(mdp, cpu_node_cookie, 1093 "mmu-search-#shared-contexts", &mmu_search_nshared_contexts)) 1094 mmu_search_nshared_contexts = 0; 1095 1096 if (mmu_search_nshared_contexts == 0 || 1097 mmu_search_nshared_contexts != NSEARCH_SHCONTEXTS) 1098 return (0); 1099 1100 if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-search-order", 1101 &mmu_max_search_order)) 1102 mmu_max_search_order = 0; 1103 1104 if (mmu_max_search_order == 0 || mmu_max_search_order != 1105 MAX_PGSZ_SEARCH_ORDER) 1106 return (0); 1107 1108 if (md_get_prop_val(mdp, cpu_node_cookie, 1109 "mmu-non-priv-search-unified", &mmu_non_priv_search_unified)) 1110 mmu_non_priv_search_unified = -1; 1111 1112 if (mmu_non_priv_search_unified != 1) { 1113 return (0); 1114 } 1115 1116 if (md_get_prop_val(mdp, cpu_node_cookie, 1117 "mmu-search-page-size-list", &mmu_search_page_size_list)) { 1118 mmu_search_page_size_list = 0; 1119 return (0); 1120 } 1121 1122 return (1); 1123 } 1124