1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND 4-Clause-BSD 3 * 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas <matt@3am-software.com> of Allegro Networks, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /*- 32 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 33 * Copyright (C) 1995, 1996 TooLs GmbH. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by TooLs GmbH. 47 * 4. The name of TooLs GmbH may not be used to endorse or promote products 48 * derived from this software without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 51 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 52 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 53 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 55 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 56 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 57 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 58 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 59 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 * 61 * $NetBSD: pmap.c,v 1.28 2000/03/26 20:42:36 kleink Exp $ 62 */ 63 /*- 64 * Copyright (C) 2001 Benno Rice. 65 * All rights reserved. 66 * 67 * Redistribution and use in source and binary forms, with or without 68 * modification, are permitted provided that the following conditions 69 * are met: 70 * 1. Redistributions of source code must retain the above copyright 71 * notice, this list of conditions and the following disclaimer. 72 * 2. Redistributions in binary form must reproduce the above copyright 73 * notice, this list of conditions and the following disclaimer in the 74 * documentation and/or other materials provided with the distribution. 75 * 76 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 77 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 78 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 79 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 80 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 81 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 82 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 83 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 84 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 85 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 86 */ 87 88 #include <sys/cdefs.h> 89 __FBSDID("$FreeBSD$"); 90 91 /* 92 * Native 64-bit page table operations for running without a hypervisor. 93 */ 94 95 #include <sys/param.h> 96 #include <sys/kernel.h> 97 #include <sys/ktr.h> 98 #include <sys/lock.h> 99 #include <sys/mutex.h> 100 #include <sys/proc.h> 101 #include <sys/sched.h> 102 #include <sys/sysctl.h> 103 #include <sys/systm.h> 104 #include <sys/rwlock.h> 105 #include <sys/endian.h> 106 107 #include <sys/kdb.h> 108 109 #include <vm/vm.h> 110 #include <vm/vm_param.h> 111 #include <vm/vm_kern.h> 112 #include <vm/vm_page.h> 113 #include <vm/vm_map.h> 114 #include <vm/vm_object.h> 115 #include <vm/vm_extern.h> 116 #include <vm/vm_pageout.h> 117 118 #include <machine/cpu.h> 119 #include <machine/hid.h> 120 #include <machine/md_var.h> 121 #include <machine/mmuvar.h> 122 123 #include "mmu_oea64.h" 124 #include "mmu_if.h" 125 #include "moea64_if.h" 126 127 #define PTESYNC() __asm __volatile("ptesync"); 128 #define TLBSYNC() __asm __volatile("tlbsync; ptesync"); 129 #define SYNC() __asm __volatile("sync"); 130 #define EIEIO() __asm __volatile("eieio"); 131 132 #define VSID_HASH_MASK 0x0000007fffffffffULL 133 134 /* POWER9 only permits a 64k partition table size. */ 135 #define PART_SIZE 0x10000 136 137 static int moea64_crop_tlbie; 138 139 static __inline void 140 TLBIE(uint64_t vpn) { 141 #ifndef __powerpc64__ 142 register_t vpn_hi, vpn_lo; 143 register_t msr; 144 register_t scratch, intr; 145 #endif 146 147 static volatile u_int tlbie_lock = 0; 148 149 vpn <<= ADDR_PIDX_SHFT; 150 151 /* Hobo spinlock: we need stronger guarantees than mutexes provide */ 152 while (!atomic_cmpset_int(&tlbie_lock, 0, 1)); 153 isync(); /* Flush instruction queue once lock acquired */ 154 155 if (moea64_crop_tlbie) 156 vpn &= ~(0xffffULL << 48); 157 158 #ifdef __powerpc64__ 159 __asm __volatile("tlbie %0" :: "r"(vpn) : "memory"); 160 __asm __volatile("eieio; tlbsync; ptesync" ::: "memory"); 161 #else 162 vpn_hi = (uint32_t)(vpn >> 32); 163 vpn_lo = (uint32_t)vpn; 164 165 intr = intr_disable(); 166 __asm __volatile("\ 167 mfmsr %0; \ 168 mr %1, %0; \ 169 insrdi %1,%5,1,0; \ 170 mtmsrd %1; isync; \ 171 \ 172 sld %1,%2,%4; \ 173 or %1,%1,%3; \ 174 tlbie %1; \ 175 \ 176 mtmsrd %0; isync; \ 177 eieio; \ 178 tlbsync; \ 179 ptesync;" 180 : "=r"(msr), "=r"(scratch) : "r"(vpn_hi), "r"(vpn_lo), "r"(32), "r"(1) 181 : "memory"); 182 intr_restore(intr); 183 #endif 184 185 /* No barriers or special ops -- taken care of by ptesync above */ 186 tlbie_lock = 0; 187 } 188 189 #define DISABLE_TRANS(msr) msr = mfmsr(); mtmsr(msr & ~PSL_DR) 190 #define ENABLE_TRANS(msr) mtmsr(msr) 191 192 /* 193 * PTEG data. 194 */ 195 static volatile struct pate *moea64_part_table; 196 static volatile struct lpte *moea64_pteg_table; 197 static struct rwlock moea64_eviction_lock; 198 199 /* 200 * PTE calls. 201 */ 202 static int moea64_pte_insert_native(mmu_t, struct pvo_entry *); 203 static int64_t moea64_pte_synch_native(mmu_t, struct pvo_entry *); 204 static int64_t moea64_pte_clear_native(mmu_t, struct pvo_entry *, uint64_t); 205 static int64_t moea64_pte_replace_native(mmu_t, struct pvo_entry *, int); 206 static int64_t moea64_pte_unset_native(mmu_t mmu, struct pvo_entry *); 207 208 /* 209 * Utility routines. 210 */ 211 static void moea64_bootstrap_native(mmu_t mmup, 212 vm_offset_t kernelstart, vm_offset_t kernelend); 213 static void moea64_cpu_bootstrap_native(mmu_t, int ap); 214 static void tlbia(void); 215 216 static mmu_method_t moea64_native_methods[] = { 217 /* Internal interfaces */ 218 MMUMETHOD(mmu_bootstrap, moea64_bootstrap_native), 219 MMUMETHOD(mmu_cpu_bootstrap, moea64_cpu_bootstrap_native), 220 221 MMUMETHOD(moea64_pte_synch, moea64_pte_synch_native), 222 MMUMETHOD(moea64_pte_clear, moea64_pte_clear_native), 223 MMUMETHOD(moea64_pte_unset, moea64_pte_unset_native), 224 MMUMETHOD(moea64_pte_replace, moea64_pte_replace_native), 225 MMUMETHOD(moea64_pte_insert, moea64_pte_insert_native), 226 227 { 0, 0 } 228 }; 229 230 MMU_DEF_INHERIT(oea64_mmu_native, MMU_TYPE_G5, moea64_native_methods, 231 0, oea64_mmu); 232 233 static int64_t 234 moea64_pte_synch_native(mmu_t mmu, struct pvo_entry *pvo) 235 { 236 volatile struct lpte *pt = moea64_pteg_table + pvo->pvo_pte.slot; 237 struct lpte properpt; 238 uint64_t ptelo; 239 240 PMAP_LOCK_ASSERT(pvo->pvo_pmap, MA_OWNED); 241 242 moea64_pte_from_pvo(pvo, &properpt); 243 244 rw_rlock(&moea64_eviction_lock); 245 if ((be64toh(pt->pte_hi) & LPTE_AVPN_MASK) != 246 (properpt.pte_hi & LPTE_AVPN_MASK)) { 247 /* Evicted */ 248 rw_runlock(&moea64_eviction_lock); 249 return (-1); 250 } 251 252 PTESYNC(); 253 ptelo = be64toh(pt->pte_lo); 254 255 rw_runlock(&moea64_eviction_lock); 256 257 return (ptelo & (LPTE_REF | LPTE_CHG)); 258 } 259 260 static int64_t 261 moea64_pte_clear_native(mmu_t mmu, struct pvo_entry *pvo, uint64_t ptebit) 262 { 263 volatile struct lpte *pt = moea64_pteg_table + pvo->pvo_pte.slot; 264 struct lpte properpt; 265 uint64_t ptelo; 266 267 PMAP_LOCK_ASSERT(pvo->pvo_pmap, MA_OWNED); 268 269 moea64_pte_from_pvo(pvo, &properpt); 270 271 rw_rlock(&moea64_eviction_lock); 272 if ((be64toh(pt->pte_hi) & LPTE_AVPN_MASK) != 273 (properpt.pte_hi & LPTE_AVPN_MASK)) { 274 /* Evicted */ 275 rw_runlock(&moea64_eviction_lock); 276 return (-1); 277 } 278 279 if (ptebit == LPTE_REF) { 280 /* See "Resetting the Reference Bit" in arch manual */ 281 PTESYNC(); 282 /* 2-step here safe: precision is not guaranteed */ 283 ptelo = be64toh(pt->pte_lo); 284 285 /* One-byte store to avoid touching the C bit */ 286 ((volatile uint8_t *)(&pt->pte_lo))[6] = 287 #if BYTE_ORDER == BIG_ENDIAN 288 ((uint8_t *)(&properpt.pte_lo))[6]; 289 #else 290 ((uint8_t *)(&properpt.pte_lo))[1]; 291 #endif 292 rw_runlock(&moea64_eviction_lock); 293 294 critical_enter(); 295 TLBIE(pvo->pvo_vpn); 296 critical_exit(); 297 } else { 298 rw_runlock(&moea64_eviction_lock); 299 ptelo = moea64_pte_unset_native(mmu, pvo); 300 moea64_pte_insert_native(mmu, pvo); 301 } 302 303 return (ptelo & (LPTE_REF | LPTE_CHG)); 304 } 305 306 static int64_t 307 moea64_pte_unset_native(mmu_t mmu, struct pvo_entry *pvo) 308 { 309 volatile struct lpte *pt = moea64_pteg_table + pvo->pvo_pte.slot; 310 struct lpte properpt; 311 uint64_t ptelo; 312 313 moea64_pte_from_pvo(pvo, &properpt); 314 315 rw_rlock(&moea64_eviction_lock); 316 if ((be64toh(pt->pte_hi & LPTE_AVPN_MASK)) != 317 (properpt.pte_hi & LPTE_AVPN_MASK)) { 318 /* Evicted */ 319 moea64_pte_overflow--; 320 rw_runlock(&moea64_eviction_lock); 321 return (-1); 322 } 323 324 /* 325 * Invalidate the pte, briefly locking it to collect RC bits. No 326 * atomics needed since this is protected against eviction by the lock. 327 */ 328 isync(); 329 critical_enter(); 330 pt->pte_hi = be64toh((pt->pte_hi & ~LPTE_VALID) | LPTE_LOCKED); 331 PTESYNC(); 332 TLBIE(pvo->pvo_vpn); 333 ptelo = be64toh(pt->pte_lo); 334 *((volatile int32_t *)(&pt->pte_hi) + 1) = 0; /* Release lock */ 335 critical_exit(); 336 rw_runlock(&moea64_eviction_lock); 337 338 /* Keep statistics */ 339 moea64_pte_valid--; 340 341 return (ptelo & (LPTE_CHG | LPTE_REF)); 342 } 343 344 static int64_t 345 moea64_pte_replace_native(mmu_t mmu, struct pvo_entry *pvo, int flags) 346 { 347 volatile struct lpte *pt = moea64_pteg_table + pvo->pvo_pte.slot; 348 struct lpte properpt; 349 int64_t ptelo; 350 351 if (flags == 0) { 352 /* Just some software bits changing. */ 353 moea64_pte_from_pvo(pvo, &properpt); 354 355 rw_rlock(&moea64_eviction_lock); 356 if ((be64toh(pt->pte_hi) & LPTE_AVPN_MASK) != 357 (properpt.pte_hi & LPTE_AVPN_MASK)) { 358 rw_runlock(&moea64_eviction_lock); 359 return (-1); 360 } 361 pt->pte_hi = htobe64(properpt.pte_hi); 362 ptelo = be64toh(pt->pte_lo); 363 rw_runlock(&moea64_eviction_lock); 364 } else { 365 /* Otherwise, need reinsertion and deletion */ 366 ptelo = moea64_pte_unset_native(mmu, pvo); 367 moea64_pte_insert_native(mmu, pvo); 368 } 369 370 return (ptelo); 371 } 372 373 static void 374 moea64_cpu_bootstrap_native(mmu_t mmup, int ap) 375 { 376 int i = 0; 377 #ifdef __powerpc64__ 378 struct slb *slb = PCPU_GET(aim.slb); 379 register_t seg0; 380 #endif 381 382 /* 383 * Initialize segment registers and MMU 384 */ 385 386 mtmsr(mfmsr() & ~PSL_DR & ~PSL_IR); 387 388 switch (mfpvr() >> 16) { 389 case IBMPOWER9: 390 mtspr(SPR_HID0, mfspr(SPR_HID0) & ~HID0_RADIX); 391 break; 392 } 393 394 /* 395 * Install kernel SLB entries 396 */ 397 398 #ifdef __powerpc64__ 399 __asm __volatile ("slbia"); 400 __asm __volatile ("slbmfee %0,%1; slbie %0;" : "=r"(seg0) : 401 "r"(0)); 402 403 for (i = 0; i < n_slbs; i++) { 404 if (!(slb[i].slbe & SLBE_VALID)) 405 continue; 406 407 __asm __volatile ("slbmte %0, %1" :: 408 "r"(slb[i].slbv), "r"(slb[i].slbe)); 409 } 410 #else 411 for (i = 0; i < 16; i++) 412 mtsrin(i << ADDR_SR_SHFT, kernel_pmap->pm_sr[i]); 413 #endif 414 415 /* 416 * Install page table 417 */ 418 419 if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) { 420 mtspr(SPR_PTCR, 421 ((uintptr_t)moea64_part_table & ~DMAP_BASE_ADDRESS) | 422 flsl((PART_SIZE >> 12) - 1)); 423 } else { 424 __asm __volatile ("ptesync; mtsdr1 %0; isync" 425 :: "r"(((uintptr_t)moea64_pteg_table & ~DMAP_BASE_ADDRESS) 426 | (uintptr_t)(flsl(moea64_pteg_mask >> 11)))); 427 } 428 tlbia(); 429 } 430 431 static void 432 moea64_bootstrap_native(mmu_t mmup, vm_offset_t kernelstart, 433 vm_offset_t kernelend) 434 { 435 vm_size_t size; 436 vm_offset_t off; 437 vm_paddr_t pa; 438 register_t msr; 439 440 moea64_early_bootstrap(mmup, kernelstart, kernelend); 441 442 switch (mfpvr() >> 16) { 443 case IBMPOWER4: 444 case IBMPOWER4PLUS: 445 case IBM970: 446 case IBM970FX: 447 case IBM970GX: 448 case IBM970MP: 449 moea64_crop_tlbie = true; 450 } 451 /* 452 * Allocate PTEG table. 453 */ 454 455 size = moea64_pteg_count * sizeof(struct lpteg); 456 CTR2(KTR_PMAP, "moea64_bootstrap: %d PTEGs, %d bytes", 457 moea64_pteg_count, size); 458 rw_init(&moea64_eviction_lock, "pte eviction"); 459 460 /* 461 * We now need to allocate memory. This memory, to be allocated, 462 * has to reside in a page table. The page table we are about to 463 * allocate. We don't have BAT. So drop to data real mode for a minute 464 * as a measure of last resort. We do this a couple times. 465 */ 466 467 if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) { 468 moea64_part_table = 469 (struct pate *)moea64_bootstrap_alloc(PART_SIZE, PART_SIZE); 470 if (hw_direct_map) 471 moea64_part_table = (struct pate *)PHYS_TO_DMAP( 472 (vm_offset_t)moea64_part_table); 473 } 474 /* 475 * PTEG table must be aligned on a 256k boundary, but can be placed 476 * anywhere with that alignment on POWER ISA 3+ systems. On earlier 477 * systems, offset addition is done by the CPU with bitwise OR rather 478 * than addition, so the table must also be aligned on a boundary of 479 * its own size. Pick the larger of the two, which works on all 480 * systems. 481 */ 482 moea64_pteg_table = (struct lpte *)moea64_bootstrap_alloc(size, 483 MAX(256*1024, size)); 484 if (hw_direct_map) 485 moea64_pteg_table = 486 (struct lpte *)PHYS_TO_DMAP((vm_offset_t)moea64_pteg_table); 487 DISABLE_TRANS(msr); 488 if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) { 489 bzero(__DEVOLATILE(void *, moea64_part_table), PART_SIZE); 490 moea64_part_table[0].pagetab = 491 ((uintptr_t)moea64_pteg_table & ~DMAP_BASE_ADDRESS) | 492 (uintptr_t)(flsl((moea64_pteg_count - 1) >> 11)); 493 } 494 bzero(__DEVOLATILE(void *, moea64_pteg_table), moea64_pteg_count * 495 sizeof(struct lpteg)); 496 ENABLE_TRANS(msr); 497 498 CTR1(KTR_PMAP, "moea64_bootstrap: PTEG table at %p", moea64_pteg_table); 499 500 moea64_mid_bootstrap(mmup, kernelstart, kernelend); 501 502 /* 503 * Add a mapping for the page table itself if there is no direct map. 504 */ 505 if (!hw_direct_map) { 506 size = moea64_pteg_count * sizeof(struct lpteg); 507 off = (vm_offset_t)(moea64_pteg_table); 508 DISABLE_TRANS(msr); 509 for (pa = off; pa < off + size; pa += PAGE_SIZE) 510 pmap_kenter(pa, pa); 511 ENABLE_TRANS(msr); 512 } 513 514 /* Bring up virtual memory */ 515 moea64_late_bootstrap(mmup, kernelstart, kernelend); 516 } 517 518 static void 519 tlbia(void) 520 { 521 vm_offset_t i; 522 #ifndef __powerpc64__ 523 register_t msr, scratch; 524 #endif 525 526 i = 0xc00; /* IS = 11 */ 527 switch (mfpvr() >> 16) { 528 case IBM970: 529 case IBM970FX: 530 case IBM970MP: 531 case IBM970GX: 532 case IBMPOWER4: 533 case IBMPOWER4PLUS: 534 case IBMPOWER5: 535 case IBMPOWER5PLUS: 536 i = 0; /* IS not supported */ 537 break; 538 } 539 540 TLBSYNC(); 541 542 for (; i < 0x200000; i += 0x00001000) { 543 #ifdef __powerpc64__ 544 __asm __volatile("tlbiel %0" :: "r"(i)); 545 #else 546 __asm __volatile("\ 547 mfmsr %0; \ 548 mr %1, %0; \ 549 insrdi %1,%3,1,0; \ 550 mtmsrd %1; \ 551 isync; \ 552 \ 553 tlbiel %2; \ 554 \ 555 mtmsrd %0; \ 556 isync;" 557 : "=r"(msr), "=r"(scratch) : "r"(i), "r"(1)); 558 #endif 559 } 560 561 EIEIO(); 562 TLBSYNC(); 563 } 564 565 static int 566 atomic_pte_lock(volatile struct lpte *pte, uint64_t bitmask, uint64_t *oldhi) 567 { 568 int ret; 569 uint32_t oldhihalf; 570 571 /* 572 * Note: in principle, if just the locked bit were set here, we 573 * could avoid needing the eviction lock. However, eviction occurs 574 * so rarely that it isn't worth bothering about in practice. 575 */ 576 577 __asm __volatile ( 578 "1:\tlwarx %1, 0, %3\n\t" /* load old value */ 579 "and. %0,%1,%4\n\t" /* check if any bits set */ 580 "bne 2f\n\t" /* exit if any set */ 581 "stwcx. %5, 0, %3\n\t" /* attempt to store */ 582 "bne- 1b\n\t" /* spin if failed */ 583 "li %0, 1\n\t" /* success - retval = 1 */ 584 "b 3f\n\t" /* we've succeeded */ 585 "2:\n\t" 586 "stwcx. %1, 0, %3\n\t" /* clear reservation (74xx) */ 587 "li %0, 0\n\t" /* failure - retval = 0 */ 588 "3:\n\t" 589 : "=&r" (ret), "=&r"(oldhihalf), "=m" (pte->pte_hi) 590 : "r" ((volatile char *)&pte->pte_hi + 4), 591 "r" ((uint32_t)bitmask), "r" ((uint32_t)LPTE_LOCKED), 592 "m" (pte->pte_hi) 593 : "cr0", "cr1", "cr2", "memory"); 594 595 *oldhi = (pte->pte_hi & 0xffffffff00000000ULL) | oldhihalf; 596 597 return (ret); 598 } 599 600 static uintptr_t 601 moea64_insert_to_pteg_native(struct lpte *pvo_pt, uintptr_t slotbase, 602 uint64_t mask) 603 { 604 volatile struct lpte *pt; 605 uint64_t oldptehi, va; 606 uintptr_t k; 607 int i, j; 608 609 /* Start at a random slot */ 610 i = mftb() % 8; 611 for (j = 0; j < 8; j++) { 612 k = slotbase + (i + j) % 8; 613 pt = &moea64_pteg_table[k]; 614 /* Invalidate and seize lock only if no bits in mask set */ 615 if (atomic_pte_lock(pt, mask, &oldptehi)) /* Lock obtained */ 616 break; 617 } 618 619 if (j == 8) 620 return (-1); 621 622 if (oldptehi & LPTE_VALID) { 623 KASSERT(!(oldptehi & LPTE_WIRED), ("Unmapped wired entry")); 624 /* 625 * Need to invalidate old entry completely: see 626 * "Modifying a Page Table Entry". Need to reconstruct 627 * the virtual address for the outgoing entry to do that. 628 */ 629 if (oldptehi & LPTE_BIG) 630 va = oldptehi >> moea64_large_page_shift; 631 else 632 va = oldptehi >> ADDR_PIDX_SHFT; 633 if (oldptehi & LPTE_HID) 634 va = (((k >> 3) ^ moea64_pteg_mask) ^ va) & 635 VSID_HASH_MASK; 636 else 637 va = ((k >> 3) ^ va) & VSID_HASH_MASK; 638 va |= (oldptehi & LPTE_AVPN_MASK) << 639 (ADDR_API_SHFT64 - ADDR_PIDX_SHFT); 640 PTESYNC(); 641 TLBIE(va); 642 moea64_pte_valid--; 643 moea64_pte_overflow++; 644 } 645 646 /* 647 * Update the PTE as per "Adding a Page Table Entry". Lock is released 648 * by setting the high doubleworld. 649 */ 650 pt->pte_lo = htobe64(pvo_pt->pte_lo); 651 EIEIO(); 652 pt->pte_hi = htobe64(pvo_pt->pte_hi); 653 PTESYNC(); 654 655 /* Keep statistics */ 656 moea64_pte_valid++; 657 658 return (k); 659 } 660 661 static int 662 moea64_pte_insert_native(mmu_t mmu, struct pvo_entry *pvo) 663 { 664 struct lpte insertpt; 665 uintptr_t slot; 666 667 /* Initialize PTE */ 668 moea64_pte_from_pvo(pvo, &insertpt); 669 670 /* Make sure further insertion is locked out during evictions */ 671 rw_rlock(&moea64_eviction_lock); 672 673 /* 674 * First try primary hash. 675 */ 676 pvo->pvo_pte.slot &= ~7ULL; /* Base slot address */ 677 slot = moea64_insert_to_pteg_native(&insertpt, pvo->pvo_pte.slot, 678 LPTE_VALID | LPTE_WIRED | LPTE_LOCKED); 679 if (slot != -1) { 680 rw_runlock(&moea64_eviction_lock); 681 pvo->pvo_pte.slot = slot; 682 return (0); 683 } 684 685 /* 686 * Now try secondary hash. 687 */ 688 pvo->pvo_vaddr ^= PVO_HID; 689 insertpt.pte_hi ^= LPTE_HID; 690 pvo->pvo_pte.slot ^= (moea64_pteg_mask << 3); 691 slot = moea64_insert_to_pteg_native(&insertpt, pvo->pvo_pte.slot, 692 LPTE_VALID | LPTE_WIRED | LPTE_LOCKED); 693 if (slot != -1) { 694 rw_runlock(&moea64_eviction_lock); 695 pvo->pvo_pte.slot = slot; 696 return (0); 697 } 698 699 /* 700 * Out of luck. Find a PTE to sacrifice. 701 */ 702 703 /* Lock out all insertions for a bit */ 704 if (!rw_try_upgrade(&moea64_eviction_lock)) { 705 rw_runlock(&moea64_eviction_lock); 706 rw_wlock(&moea64_eviction_lock); 707 } 708 709 slot = moea64_insert_to_pteg_native(&insertpt, pvo->pvo_pte.slot, 710 LPTE_WIRED | LPTE_LOCKED); 711 if (slot != -1) { 712 rw_wunlock(&moea64_eviction_lock); 713 pvo->pvo_pte.slot = slot; 714 return (0); 715 } 716 717 /* Try other hash table. Now we're getting desperate... */ 718 pvo->pvo_vaddr ^= PVO_HID; 719 insertpt.pte_hi ^= LPTE_HID; 720 pvo->pvo_pte.slot ^= (moea64_pteg_mask << 3); 721 slot = moea64_insert_to_pteg_native(&insertpt, pvo->pvo_pte.slot, 722 LPTE_WIRED | LPTE_LOCKED); 723 if (slot != -1) { 724 rw_wunlock(&moea64_eviction_lock); 725 pvo->pvo_pte.slot = slot; 726 return (0); 727 } 728 729 /* No freeable slots in either PTEG? We're hosed. */ 730 rw_wunlock(&moea64_eviction_lock); 731 panic("moea64_pte_insert: overflow"); 732 return (-1); 733 } 734 735