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