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