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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/systm.h> 31 #include <sys/archsystm.h> 32 #include <sys/machparam.h> 33 #include <sys/machsystm.h> 34 #include <sys/cpu.h> 35 #include <sys/elf_SPARC.h> 36 #include <vm/hat_sfmmu.h> 37 #include <vm/page.h> 38 #include <vm/vm_dep.h> 39 #include <sys/cpuvar.h> 40 #include <sys/async.h> 41 #include <sys/cmn_err.h> 42 #include <sys/debug.h> 43 #include <sys/dditypes.h> 44 #include <sys/sunddi.h> 45 #include <sys/cpu_module.h> 46 #include <sys/prom_debug.h> 47 #include <sys/vmsystm.h> 48 #include <sys/prom_plat.h> 49 #include <sys/sysmacros.h> 50 #include <sys/intreg.h> 51 #include <sys/machtrap.h> 52 #include <sys/ontrap.h> 53 #include <sys/ivintr.h> 54 #include <sys/atomic.h> 55 #include <sys/panic.h> 56 #include <sys/dtrace.h> 57 #include <sys/simulate.h> 58 #include <sys/fault.h> 59 #include <sys/niagara2regs.h> 60 #include <sys/hsvc.h> 61 #include <sys/trapstat.h> 62 #include <sys/mutex_impl.h> 63 64 uint_t root_phys_addr_lo_mask = 0xffffffffU; 65 #if defined(NIAGARA2_IMPL) 66 char cpu_module_name[] = "SUNW,UltraSPARC-T2"; 67 #elif defined(VFALLS_IMPL) 68 char cpu_module_name[] = "SUNW,UltraSPARC-T2+"; 69 #endif 70 71 /* 72 * Hypervisor services information for the NIAGARA2 and Victoria Falls 73 * CPU module 74 */ 75 static boolean_t cpu_hsvc_available = B_TRUE; 76 static uint64_t cpu_sup_minor; /* Supported minor number */ 77 #if defined(NIAGARA2_IMPL) 78 static hsvc_info_t cpu_hsvc = { 79 HSVC_REV_1, NULL, HSVC_GROUP_NIAGARA2_CPU, NIAGARA2_HSVC_MAJOR, 80 NIAGARA2_HSVC_MINOR, cpu_module_name 81 }; 82 #elif defined(VFALLS_IMPL) 83 static hsvc_info_t cpu_hsvc = { 84 HSVC_REV_1, NULL, HSVC_GROUP_VFALLS_CPU, VFALLS_HSVC_MAJOR, 85 VFALLS_HSVC_MINOR, cpu_module_name 86 }; 87 #endif 88 89 void 90 cpu_setup(void) 91 { 92 extern int mmu_exported_pagesize_mask; 93 extern int cpc_has_overflow_intr; 94 extern size_t contig_mem_prealloc_base_size; 95 int status; 96 97 /* 98 * Negotiate the API version for Niagara2 specific hypervisor 99 * services. 100 */ 101 status = hsvc_register(&cpu_hsvc, &cpu_sup_minor); 102 if (status != 0) { 103 cmn_err(CE_WARN, "%s: cannot negotiate hypervisor services " 104 "group: 0x%lx major: 0x%lx minor: 0x%lx errno: %d", 105 cpu_hsvc.hsvc_modname, cpu_hsvc.hsvc_group, 106 cpu_hsvc.hsvc_major, cpu_hsvc.hsvc_minor, status); 107 cpu_hsvc_available = B_FALSE; 108 } 109 110 /* 111 * The setup common to all CPU modules is done in cpu_setup_common 112 * routine. 113 */ 114 cpu_setup_common(NULL); 115 116 cache |= (CACHE_PTAG | CACHE_IOCOHERENT); 117 118 if ((mmu_exported_pagesize_mask & 119 DEFAULT_SUN4V_MMU_PAGESIZE_MASK) != 120 DEFAULT_SUN4V_MMU_PAGESIZE_MASK) 121 cmn_err(CE_PANIC, "machine description" 122 " does not have required sun4v page sizes" 123 " 8K, 64K and 4M: MD mask is 0x%x", 124 mmu_exported_pagesize_mask); 125 126 cpu_hwcap_flags = AV_SPARC_VIS | AV_SPARC_VIS2 | 127 AV_SPARC_ASI_BLK_INIT | AV_SPARC_POPC; 128 129 /* 130 * Niagara2 supports a 48-bit subset of the full 64-bit virtual 131 * address space. Virtual addresses between 0x0000800000000000 132 * and 0xffff.7fff.ffff.ffff inclusive lie within a "VA Hole" 133 * and must never be mapped. In addition, software must not use 134 * pages within 4GB of the VA hole as instruction pages to 135 * avoid problems with prefetching into the VA hole. 136 */ 137 hole_start = (caddr_t)((1ull << (va_bits - 1)) - (1ull << 32)); 138 hole_end = (caddr_t)((0ull - (1ull << (va_bits - 1))) + (1ull << 32)); 139 140 /* 141 * Niagara2 has a performance counter overflow interrupt 142 */ 143 cpc_has_overflow_intr = 1; 144 145 /* 146 * Enable 4M pages for OOB. 147 */ 148 max_uheap_lpsize = MMU_PAGESIZE4M; 149 max_ustack_lpsize = MMU_PAGESIZE4M; 150 max_privmap_lpsize = MMU_PAGESIZE4M; 151 152 #ifdef SUN4V_CONTIG_MEM_PREALLOC_SIZE_MB 153 /* 154 * Use CPU Makefile specific compile time define (if exists) 155 * to add to the contig preallocation size. 156 */ 157 contig_mem_prealloc_base_size = MB(SUN4V_CONTIG_MEM_PREALLOC_SIZE_MB); 158 #endif 159 } 160 161 /* 162 * Set the magic constants of the implementation. 163 */ 164 void 165 cpu_fiximp(struct cpu_node *cpunode) 166 { 167 /* 168 * The Cache node is optional in MD. Therefore in case "Cache" 169 * node does not exists in MD, set the default L2 cache associativity, 170 * size, linesize. 171 */ 172 if (cpunode->ecache_size == 0) 173 cpunode->ecache_size = L2CACHE_SIZE; 174 if (cpunode->ecache_linesize == 0) 175 cpunode->ecache_linesize = L2CACHE_LINESIZE; 176 if (cpunode->ecache_associativity == 0) 177 cpunode->ecache_associativity = L2CACHE_ASSOCIATIVITY; 178 } 179 180 void 181 cpu_map_exec_units(struct cpu *cp) 182 { 183 ASSERT(MUTEX_HELD(&cpu_lock)); 184 185 /* 186 * The cpu_ipipe and cpu_fpu fields are initialized based on 187 * the execution unit sharing information from the MD. They 188 * default to the CPU id in the absence of such information. 189 */ 190 cp->cpu_m.cpu_ipipe = cpunodes[cp->cpu_id].exec_unit_mapping; 191 if (cp->cpu_m.cpu_ipipe == NO_EU_MAPPING_FOUND) 192 cp->cpu_m.cpu_ipipe = (id_t)(cp->cpu_id); 193 194 cp->cpu_m.cpu_fpu = cpunodes[cp->cpu_id].fpu_mapping; 195 if (cp->cpu_m.cpu_fpu == NO_EU_MAPPING_FOUND) 196 cp->cpu_m.cpu_fpu = (id_t)(cp->cpu_id); 197 198 /* 199 * Niagara 2 defines the core to be at the FPU level 200 */ 201 cp->cpu_m.cpu_core = cp->cpu_m.cpu_fpu; 202 203 /* 204 * The cpu_chip field is initialized based on the information 205 * in the MD and assume that all cpus within a chip 206 * share the same L2 cache. If no such info is available, we 207 * set the cpu to belong to the defacto chip 0. 208 */ 209 cp->cpu_m.cpu_mpipe = cpunodes[cp->cpu_id].l2_cache_mapping; 210 if (cp->cpu_m.cpu_mpipe == NO_L2_CACHE_MAPPING_FOUND) 211 cp->cpu_m.cpu_mpipe = CPU_L2_CACHEID_INVALID; 212 213 cp->cpu_m.cpu_chip = cpunodes[cp->cpu_id].l2_cache_mapping; 214 if (cp->cpu_m.cpu_chip == NO_L2_CACHE_MAPPING_FOUND) 215 cp->cpu_m.cpu_chip = CPU_CHIPID_INVALID; 216 } 217 218 static int cpucnt; 219 220 void 221 cpu_init_private(struct cpu *cp) 222 { 223 extern void niagara_kstat_init(void); 224 225 ASSERT(MUTEX_HELD(&cpu_lock)); 226 227 cpu_map_exec_units(cp); 228 229 if ((cpucnt++ == 0) && (cpu_hsvc_available == B_TRUE)) 230 (void) niagara_kstat_init(); 231 232 mutex_delay = rdccr_delay; 233 } 234 235 /*ARGSUSED*/ 236 void 237 cpu_uninit_private(struct cpu *cp) 238 { 239 extern void niagara_kstat_fini(void); 240 241 ASSERT(MUTEX_HELD(&cpu_lock)); 242 if ((--cpucnt == 0) && (cpu_hsvc_available == B_TRUE)) 243 (void) niagara_kstat_fini(); 244 } 245 246 /* 247 * On Niagara2, any flush will cause all preceding stores to be 248 * synchronized wrt the i$, regardless of address or ASI. In fact, 249 * the address is ignored, so we always flush address 0. 250 */ 251 /*ARGSUSED*/ 252 void 253 dtrace_flush_sec(uintptr_t addr) 254 { 255 doflush(0); 256 } 257 258 /* 259 * Trapstat support for Niagara2 processor 260 * The Niagara2 provides HWTW support for TSB lookup and with HWTW 261 * enabled no TSB hit information will be available. Therefore setting 262 * the time spent in TLB miss handler for TSB hits to 0. 263 */ 264 int 265 cpu_trapstat_conf(int cmd) 266 { 267 int status = 0; 268 269 switch (cmd) { 270 case CPU_TSTATCONF_INIT: 271 case CPU_TSTATCONF_FINI: 272 case CPU_TSTATCONF_ENABLE: 273 case CPU_TSTATCONF_DISABLE: 274 break; 275 default: 276 status = EINVAL; 277 break; 278 } 279 return (status); 280 } 281 282 void 283 cpu_trapstat_data(void *buf, uint_t tstat_pgszs) 284 { 285 tstat_pgszdata_t *tstatp = (tstat_pgszdata_t *)buf; 286 int i; 287 288 for (i = 0; i < tstat_pgszs; i++, tstatp++) { 289 tstatp->tpgsz_kernel.tmode_itlb.ttlb_tlb.tmiss_count = 0; 290 tstatp->tpgsz_kernel.tmode_itlb.ttlb_tlb.tmiss_time = 0; 291 tstatp->tpgsz_user.tmode_itlb.ttlb_tlb.tmiss_count = 0; 292 tstatp->tpgsz_user.tmode_itlb.ttlb_tlb.tmiss_time = 0; 293 tstatp->tpgsz_kernel.tmode_dtlb.ttlb_tlb.tmiss_count = 0; 294 tstatp->tpgsz_kernel.tmode_dtlb.ttlb_tlb.tmiss_time = 0; 295 tstatp->tpgsz_user.tmode_dtlb.ttlb_tlb.tmiss_count = 0; 296 tstatp->tpgsz_user.tmode_dtlb.ttlb_tlb.tmiss_time = 0; 297 } 298 } 299 300 /* 301 * Page coloring support for hashed cache index mode 302 */ 303 304 /* 305 * Node id bits from machine description (MD). Node id distinguishes 306 * local versus remote memory. Because of MPO, page allocation does 307 * not cross node boundaries. Therefore, remove the node id bits from 308 * the color, since they are fixed. Either bit 30, or 31:30 in 309 * Victoria Falls processors. 310 * The number of node id bits is always 0 in Niagara2. 311 */ 312 typedef struct n2color { 313 uchar_t nnbits; /* number of node id bits */ 314 uchar_t nnmask; /* mask for node id bits */ 315 uchar_t lomask; /* mask for bits below node id */ 316 uchar_t lobits; /* number of bits below node id */ 317 } n2color_t; 318 319 n2color_t n2color[MMU_PAGE_SIZES]; 320 static uchar_t nhbits[] = {7, 7, 6, 5, 5, 5}; 321 322 /* 323 * Remove node id bits from color bits 32:28. 324 * This will reduce the number of colors. 325 * No change if number of node bits is zero. 326 */ 327 static inline uint_t 328 n2_hash2color(uint_t color, uchar_t szc) 329 { 330 n2color_t m = n2color[szc]; 331 332 if (m.nnbits > 0) { 333 color = ((color >> m.nnbits) & ~m.lomask) | (color & m.lomask); 334 ASSERT((color & ~(hw_page_array[szc].hp_colors - 1)) == 0); 335 } 336 337 return (color); 338 } 339 340 /* 341 * Restore node id bits into page color. 342 * This will increase the number of colors to match N2. 343 * No change if number of node bits is zero. 344 */ 345 static inline uint_t 346 n2_color2hash(uint_t color, uchar_t szc, uint_t node) 347 { 348 n2color_t m = n2color[szc]; 349 350 if (m.nnbits > 0) { 351 color = ((color & ~m.lomask) << m.nnbits) | (color & m.lomask); 352 color |= (node & m.nnmask) << m.lobits; 353 } 354 355 return (color); 356 } 357 358 /* NI2 L2$ index is pa[32:28]^pa[17:13].pa[19:18]^pa[12:11].pa[10:6] */ 359 360 /* 361 * iterator NULL means pfn is VA, do not adjust ra_to_pa 362 * iterator (-1) means pfn is RA, need to convert to PA 363 * iterator non-null means pfn is RA, use ra_to_pa 364 */ 365 uint_t 366 page_pfn_2_color_cpu(pfn_t pfn, uchar_t szc, void *cookie) 367 { 368 mem_node_iterator_t *it = cookie; 369 uint_t color; 370 371 ASSERT(szc <= TTE256M); 372 373 if (it == ((mem_node_iterator_t *)(-1))) { 374 pfn = plat_rapfn_to_papfn(pfn); 375 } else if (it != NULL) { 376 ASSERT(pfn >= it->mi_mblock_base && pfn <= it->mi_mblock_end); 377 pfn = pfn + it->mi_ra_to_pa; 378 } 379 pfn = PFN_BASE(pfn, szc); 380 color = ((pfn >> 15) ^ pfn) & 0x1f; 381 if (szc < TTE4M) { 382 /* 19:18 */ 383 color = (color << 2) | ((pfn >> 5) & 0x3); 384 if (szc > TTE64K) 385 color >>= 1; /* 19 */ 386 } 387 return (n2_hash2color(color, szc)); 388 } 389 390 static uint_t 391 page_papfn_2_color_cpu(pfn_t papfn, uchar_t szc) 392 { 393 uint_t color; 394 395 ASSERT(szc <= TTE256M); 396 397 papfn = PFN_BASE(papfn, szc); 398 color = ((papfn >> 15) ^ papfn) & 0x1f; 399 if (szc < TTE4M) { 400 /* 19:18 */ 401 color = (color << 2) | ((papfn >> 5) & 0x3); 402 if (szc > TTE64K) 403 color >>= 1; /* 19 */ 404 } 405 return (color); 406 } 407 408 #if TTE256M != 5 409 #error TTE256M is not 5 410 #endif 411 412 uint_t 413 page_get_nsz_color_mask_cpu(uchar_t szc, uint_t mask) 414 { 415 static uint_t ni2_color_masks[5] = {0x63, 0x1e, 0x3e, 0x1f, 0x1f}; 416 ASSERT(szc < TTE256M); 417 mask = n2_color2hash(mask, szc, 0); 418 mask &= ni2_color_masks[szc]; 419 if (szc == TTE64K || szc == TTE512K) 420 mask >>= 1; 421 return (n2_hash2color(mask, szc + 1)); 422 } 423 424 uint_t 425 page_get_nsz_color_cpu(uchar_t szc, uint_t color) 426 { 427 ASSERT(szc < TTE256M); 428 color = n2_color2hash(color, szc, 0); 429 if (szc == TTE64K || szc == TTE512K) 430 color >>= 1; 431 return (n2_hash2color(color, szc + 1)); 432 } 433 434 uint_t 435 page_get_color_shift_cpu(uchar_t szc, uchar_t nszc) 436 { 437 uint_t s; 438 ASSERT(nszc >= szc); 439 ASSERT(nszc <= TTE256M); 440 441 s = nhbits[szc] - n2color[szc].nnbits; 442 s -= nhbits[nszc] - n2color[nszc].nnbits; 443 444 return (s); 445 } 446 447 uint_t 448 page_convert_color_cpu(uint_t ncolor, uchar_t szc, uchar_t nszc) 449 { 450 uint_t color; 451 452 ASSERT(nszc > szc); 453 ASSERT(nszc <= TTE256M); 454 ncolor = n2_color2hash(ncolor, nszc, 0); 455 color = ncolor << (nhbits[szc] - nhbits[nszc]); 456 color = n2_hash2color(color, szc); 457 return (color); 458 } 459 460 #define PAPFN_2_MNODE(pfn) \ 461 (((pfn) & it->mi_mnode_pfn_mask) >> it->mi_mnode_pfn_shift) 462 463 /*ARGSUSED*/ 464 pfn_t 465 page_next_pfn_for_color_cpu(pfn_t pfn, uchar_t szc, uint_t color, 466 uint_t ceq_mask, uint_t color_mask, void *cookie) 467 { 468 mem_node_iterator_t *it = cookie; 469 pfn_t pstep = PNUM_SIZE(szc); 470 pfn_t npfn, pfn_ceq_mask, pfn_color; 471 pfn_t tmpmask, mask = (pfn_t)-1; 472 uint_t pfnmn; 473 474 ASSERT((color & ~ceq_mask) == 0); 475 ASSERT(pfn >= it->mi_mblock_base && pfn <= it->mi_mblock_end); 476 477 /* convert RA to PA for accurate color calculation */ 478 if (it->mi_init) { 479 /* first call after it, so cache these values */ 480 it->mi_hash_ceq_mask = 481 n2_color2hash(ceq_mask, szc, it->mi_mnode_mask); 482 it->mi_hash_color = 483 n2_color2hash(color, szc, it->mi_mnode); 484 it->mi_init = 0; 485 } else { 486 ASSERT(it->mi_hash_ceq_mask == 487 n2_color2hash(ceq_mask, szc, it->mi_mnode_mask)); 488 ASSERT(it->mi_hash_color == 489 n2_color2hash(color, szc, it->mi_mnode)); 490 } 491 ceq_mask = it->mi_hash_ceq_mask; 492 color = it->mi_hash_color; 493 pfn += it->mi_ra_to_pa; 494 495 /* restart here when we switch memblocks */ 496 next_mem_block: 497 if (szc <= TTE64K) { 498 pfnmn = PAPFN_2_MNODE(pfn); 499 } 500 if (((page_papfn_2_color_cpu(pfn, szc) ^ color) & ceq_mask) == 0 && 501 (szc > TTE64K || pfnmn == it->mi_mnode)) { 502 503 /* we start from the page with correct color */ 504 if (szc >= TTE512K) { 505 if (szc >= TTE4M) { 506 /* page color is PA[32:28] */ 507 pfn_ceq_mask = ceq_mask << 15; 508 } else { 509 /* page color is PA[32:28].PA[19:19] */ 510 pfn_ceq_mask = ((ceq_mask & 1) << 6) | 511 ((ceq_mask >> 1) << 15); 512 } 513 npfn = ADD_MASKED(pfn, pstep, pfn_ceq_mask, mask); 514 goto done; 515 } else { 516 /* 517 * We deal 64K or 8K page. Check if we could the 518 * satisfy the request without changing PA[32:28] 519 */ 520 pfn_ceq_mask = ((ceq_mask & 3) << 5) | (ceq_mask >> 2); 521 pfn_ceq_mask |= it->mi_mnode_pfn_mask; 522 npfn = ADD_MASKED(pfn, pstep, pfn_ceq_mask, mask); 523 524 if ((((npfn ^ pfn) >> 15) & 0x1f) == 0) 525 goto done; 526 527 /* 528 * for next pfn we have to change bits PA[32:28] 529 * set PA[63:28] and PA[19:18] of the next pfn 530 */ 531 npfn = (pfn >> 15) << 15; 532 npfn |= (ceq_mask & color & 3) << 5; 533 pfn_ceq_mask = (szc == TTE8K) ? 0 : 534 (ceq_mask & 0x1c) << 13; 535 pfn_ceq_mask |= it->mi_mnode_pfn_mask; 536 npfn = ADD_MASKED(npfn, (1 << 15), pfn_ceq_mask, mask); 537 538 /* 539 * set bits PA[17:13] to match the color 540 */ 541 npfn |= ((npfn >> 15) ^ (color >> 2)) & (ceq_mask >> 2); 542 goto done; 543 } 544 } 545 546 /* 547 * we start from the page with incorrect color - rare case 548 */ 549 if (szc >= TTE512K) { 550 if (szc >= TTE4M) { 551 /* page color is in bits PA[32:28] */ 552 npfn = ((pfn >> 20) << 20) | (color << 15); 553 pfn_ceq_mask = (ceq_mask << 15) | 0x7fff; 554 } else { 555 /* try get the right color by changing bit PA[19:19] */ 556 npfn = pfn + pstep; 557 if (((page_papfn_2_color_cpu(npfn, szc) ^ color) & 558 ceq_mask) == 0) 559 goto done; 560 561 /* page color is PA[32:28].PA[19:19] */ 562 pfn_ceq_mask = ((ceq_mask & 1) << 6) | 563 ((ceq_mask >> 1) << 15) | (0xff << 7); 564 pfn_color = ((color & 1) << 6) | ((color >> 1) << 15); 565 npfn = ((pfn >> 20) << 20) | pfn_color; 566 } 567 568 while (npfn <= pfn) { 569 npfn = ADD_MASKED(npfn, pstep, pfn_ceq_mask, mask); 570 } 571 goto done; 572 } 573 574 /* 575 * We deal 64K or 8K page of incorrect color. 576 * Try correcting color without changing PA[32:28] 577 */ 578 pfn_ceq_mask = ((ceq_mask & 3) << 5) | (ceq_mask >> 2); 579 pfn_color = ((color & 3) << 5) | (color >> 2); 580 if (pfnmn == it->mi_mnode) { 581 npfn = (pfn & ~(pfn_t)0x7f); 582 npfn |= (((pfn >> 15) & 0x1f) ^ pfn_color) & pfn_ceq_mask; 583 npfn = (szc == TTE64K) ? (npfn & ~(pfn_t)0x7) : npfn; 584 585 if (((page_papfn_2_color_cpu(npfn, szc) ^ color) & 586 ceq_mask) == 0) { 587 /* the color is fixed - find the next page */ 588 pfn_ceq_mask |= it->mi_mnode_pfn_mask; 589 while (npfn <= pfn) { 590 npfn = ADD_MASKED(npfn, pstep, pfn_ceq_mask, 591 mask); 592 } 593 if ((((npfn ^ pfn) >> 15) & 0x1f) == 0) 594 goto done; 595 } 596 } 597 598 /* to fix the color need to touch PA[32:28] */ 599 npfn = (szc == TTE8K) ? ((pfn >> 15) << 15) : 600 (((pfn >> 18) << 18) | ((color & 0x1c) << 13)); 601 602 /* fix mnode if input pfn is in the wrong mnode. */ 603 if ((pfnmn = PAPFN_2_MNODE(npfn)) != it->mi_mnode) { 604 npfn += ((it->mi_mnode - pfnmn) & it->mi_mnode_mask) << 605 it->mi_mnode_pfn_shift; 606 } 607 608 tmpmask = (szc == TTE8K) ? 0 : (ceq_mask & 0x1c) << 13; 609 tmpmask |= it->mi_mnode_pfn_mask; 610 611 while (npfn <= pfn) { 612 npfn = ADD_MASKED(npfn, (1 << 15), tmpmask, mask); 613 } 614 615 /* set bits PA[19:13] to match the color */ 616 npfn |= (((npfn >> 15) & 0x1f) ^ pfn_color) & pfn_ceq_mask; 617 npfn = (szc == TTE64K) ? (npfn & ~(pfn_t)0x7) : npfn; 618 619 done: 620 ASSERT(((page_papfn_2_color_cpu(npfn, szc) ^ color) & ceq_mask) == 0); 621 ASSERT(PAPFN_2_MNODE(npfn) == it->mi_mnode); 622 623 /* PA to RA */ 624 npfn -= it->mi_ra_to_pa; 625 626 /* check for possible memblock switch */ 627 if (npfn > it->mi_mblock_end) { 628 pfn = plat_mem_node_iterator_init(npfn, it->mi_mnode, szc, it, 629 0); 630 if (pfn == (pfn_t)-1) 631 return (pfn); 632 ASSERT(pfn >= it->mi_mblock_base && pfn <= it->mi_mblock_end); 633 pfn += it->mi_ra_to_pa; 634 goto next_mem_block; 635 } 636 637 return (npfn); 638 } 639 640 /* 641 * init page coloring 642 * VF encodes node_id for an L-group in either bit 30 or 31:30, 643 * which effectively reduces the number of colors available per mnode. 644 */ 645 void 646 page_coloring_init_cpu() 647 { 648 int i; 649 uchar_t id; 650 uchar_t lo; 651 uchar_t hi; 652 n2color_t m; 653 mem_node_iterator_t it; 654 static uchar_t idmask[] = {0, 0x7, 0x1f, 0x1f, 0x1f, 0x1f}; 655 656 for (i = 0; i < max_mem_nodes; i++) { 657 memset(&it, 0, sizeof (it)); 658 if (plat_mem_node_iterator_init(0, i, 0, &it, 1) != (pfn_t)-1) 659 break; 660 } 661 ASSERT(i < max_mem_nodes); 662 for (i = 0; i < mmu_page_sizes; i++) { 663 (void) memset(&m, 0, sizeof (m)); 664 id = it.mi_mnode_pfn_mask >> 15; /* node id mask */ 665 id &= idmask[i]; 666 lo = lowbit(id); 667 if (lo > 0) { 668 hi = highbit(id); 669 m.nnbits = hi - lo + 1; 670 m.nnmask = (1 << m.nnbits) - 1; 671 lo += nhbits[i] - 5; 672 m.lomask = (1 << (lo - 1)) - 1; 673 m.lobits = lo - 1; 674 } 675 hw_page_array[i].hp_colors = 1 << (nhbits[i] - m.nnbits); 676 n2color[i] = m; 677 } 678 } 679 680 /* 681 * group colorequiv colors on N2 by low order bits of the color first 682 */ 683 void 684 page_set_colorequiv_arr_cpu(void) 685 { 686 static uint_t nequiv_shades_log2[MMU_PAGE_SIZES] = {2, 5, 0, 0, 0, 0}; 687 688 nequiv_shades_log2[1] -= n2color[1].nnbits; 689 if (colorequiv > 1) { 690 int i; 691 uint_t sv_a = lowbit(colorequiv) - 1; 692 693 if (sv_a > 15) 694 sv_a = 15; 695 696 for (i = 0; i < MMU_PAGE_SIZES; i++) { 697 uint_t colors; 698 uint_t a = sv_a; 699 700 if ((colors = hw_page_array[i].hp_colors) <= 1) 701 continue; 702 while ((colors >> a) == 0) 703 a--; 704 if (a > (colorequivszc[i] & 0xf) + 705 (colorequivszc[i] >> 4)) { 706 if (a <= nequiv_shades_log2[i]) { 707 colorequivszc[i] = (uchar_t)a; 708 } else { 709 colorequivszc[i] = 710 ((a - nequiv_shades_log2[i]) << 4) | 711 nequiv_shades_log2[i]; 712 } 713 } 714 } 715 } 716 } 717