linux/arch/powerpc/mm/hash_low_32.S
<<
>>
Prefs
   1/*
   2 *  PowerPC version
   3 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
   4 *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
   5 *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
   6 *  Adapted for Power Macintosh by Paul Mackerras.
   7 *  Low-level exception handlers and MMU support
   8 *  rewritten by Paul Mackerras.
   9 *    Copyright (C) 1996 Paul Mackerras.
  10 *
  11 *  This file contains low-level assembler routines for managing
  12 *  the PowerPC MMU hash table.  (PPC 8xx processors don't use a
  13 *  hash table, so this file is not used on them.)
  14 *
  15 *  This program is free software; you can redistribute it and/or
  16 *  modify it under the terms of the GNU General Public License
  17 *  as published by the Free Software Foundation; either version
  18 *  2 of the License, or (at your option) any later version.
  19 *
  20 */
  21
  22#include <asm/reg.h>
  23#include <asm/page.h>
  24#include <asm/pgtable.h>
  25#include <asm/cputable.h>
  26#include <asm/ppc_asm.h>
  27#include <asm/thread_info.h>
  28#include <asm/asm-offsets.h>
  29
  30#ifdef CONFIG_SMP
  31        .section .bss
  32        .align  2
  33        .globl mmu_hash_lock
  34mmu_hash_lock:
  35        .space  4
  36#endif /* CONFIG_SMP */
  37
  38/*
  39 * Load a PTE into the hash table, if possible.
  40 * The address is in r4, and r3 contains an access flag:
  41 * _PAGE_RW (0x400) if a write.
  42 * r9 contains the SRR1 value, from which we use the MSR_PR bit.
  43 * SPRG_THREAD contains the physical address of the current task's thread.
  44 *
  45 * Returns to the caller if the access is illegal or there is no
  46 * mapping for the address.  Otherwise it places an appropriate PTE
  47 * in the hash table and returns from the exception.
  48 * Uses r0, r3 - r8, r10, ctr, lr.
  49 */
  50        .text
  51_GLOBAL(hash_page)
  52        tophys(r7,0)                    /* gets -KERNELBASE into r7 */
  53#ifdef CONFIG_SMP
  54        addis   r8,r7,mmu_hash_lock@h
  55        ori     r8,r8,mmu_hash_lock@l
  56        lis     r0,0x0fff
  57        b       10f
  5811:     lwz     r6,0(r8)
  59        cmpwi   0,r6,0
  60        bne     11b
  6110:     lwarx   r6,0,r8
  62        cmpwi   0,r6,0
  63        bne-    11b
  64        stwcx.  r0,0,r8
  65        bne-    10b
  66        isync
  67#endif
  68        /* Get PTE (linux-style) and check access */
  69        lis     r0,KERNELBASE@h         /* check if kernel address */
  70        cmplw   0,r4,r0
  71        mfspr   r8,SPRN_SPRG_THREAD     /* current task's THREAD (phys) */
  72        ori     r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
  73        lwz     r5,PGDIR(r8)            /* virt page-table root */
  74        blt+    112f                    /* assume user more likely */
  75        lis     r5,swapper_pg_dir@ha    /* if kernel address, use */
  76        addi    r5,r5,swapper_pg_dir@l  /* kernel page table */
  77        rlwimi  r3,r9,32-12,29,29       /* MSR_PR -> _PAGE_USER */
  78112:    add     r5,r5,r7                /* convert to phys addr */
  79#ifndef CONFIG_PTE_64BIT
  80        rlwimi  r5,r4,12,20,29          /* insert top 10 bits of address */
  81        lwz     r8,0(r5)                /* get pmd entry */
  82        rlwinm. r8,r8,0,0,19            /* extract address of pte page */
  83#else
  84        rlwinm  r8,r4,13,19,29          /* Compute pgdir/pmd offset */
  85        lwzx    r8,r8,r5                /* Get L1 entry */
  86        rlwinm. r8,r8,0,0,20            /* extract pt base address */
  87#endif
  88#ifdef CONFIG_SMP
  89        beq-    hash_page_out           /* return if no mapping */
  90#else
  91        /* XXX it seems like the 601 will give a machine fault on the
  92           rfi if its alignment is wrong (bottom 4 bits of address are
  93           8 or 0xc) and we have had a not-taken conditional branch
  94           to the address following the rfi. */
  95        beqlr-
  96#endif
  97#ifndef CONFIG_PTE_64BIT
  98        rlwimi  r8,r4,22,20,29          /* insert next 10 bits of address */
  99#else
 100        rlwimi  r8,r4,23,20,28          /* compute pte address */
 101#endif
 102        rlwinm  r0,r3,32-3,24,24        /* _PAGE_RW access -> _PAGE_DIRTY */
 103        ori     r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
 104
 105        /*
 106         * Update the linux PTE atomically.  We do the lwarx up-front
 107         * because almost always, there won't be a permission violation
 108         * and there won't already be an HPTE, and thus we will have
 109         * to update the PTE to set _PAGE_HASHPTE.  -- paulus.
 110         *
 111         * If PTE_64BIT is set, the low word is the flags word; use that
 112         * word for locking since it contains all the interesting bits.
 113         */
 114#if (PTE_FLAGS_OFFSET != 0)
 115        addi    r8,r8,PTE_FLAGS_OFFSET
 116#endif
 117retry:
 118        lwarx   r6,0,r8                 /* get linux-style pte, flag word */
 119        andc.   r5,r3,r6                /* check access & ~permission */
 120#ifdef CONFIG_SMP
 121        bne-    hash_page_out           /* return if access not permitted */
 122#else
 123        bnelr-
 124#endif
 125        or      r5,r0,r6                /* set accessed/dirty bits */
 126#ifdef CONFIG_PTE_64BIT
 127#ifdef CONFIG_SMP
 128        subf    r10,r6,r8               /* create false data dependency */
 129        subi    r10,r10,PTE_FLAGS_OFFSET
 130        lwzx    r10,r6,r10              /* Get upper PTE word */
 131#else
 132        lwz     r10,-PTE_FLAGS_OFFSET(r8)
 133#endif /* CONFIG_SMP */
 134#endif /* CONFIG_PTE_64BIT */
 135        stwcx.  r5,0,r8                 /* attempt to update PTE */
 136        bne-    retry                   /* retry if someone got there first */
 137
 138        mfsrin  r3,r4                   /* get segment reg for segment */
 139        mfctr   r0
 140        stw     r0,_CTR(r11)
 141        bl      create_hpte             /* add the hash table entry */
 142
 143#ifdef CONFIG_SMP
 144        eieio
 145        addis   r8,r7,mmu_hash_lock@ha
 146        li      r0,0
 147        stw     r0,mmu_hash_lock@l(r8)
 148#endif
 149
 150        /* Return from the exception */
 151        lwz     r5,_CTR(r11)
 152        mtctr   r5
 153        lwz     r0,GPR0(r11)
 154        lwz     r7,GPR7(r11)
 155        lwz     r8,GPR8(r11)
 156        b       fast_exception_return
 157
 158#ifdef CONFIG_SMP
 159hash_page_out:
 160        eieio
 161        addis   r8,r7,mmu_hash_lock@ha
 162        li      r0,0
 163        stw     r0,mmu_hash_lock@l(r8)
 164        blr
 165#endif /* CONFIG_SMP */
 166
 167/*
 168 * Add an entry for a particular page to the hash table.
 169 *
 170 * add_hash_page(unsigned context, unsigned long va, unsigned long pmdval)
 171 *
 172 * We assume any necessary modifications to the pte (e.g. setting
 173 * the accessed bit) have already been done and that there is actually
 174 * a hash table in use (i.e. we're not on a 603).
 175 */
 176_GLOBAL(add_hash_page)
 177        mflr    r0
 178        stw     r0,4(r1)
 179
 180        /* Convert context and va to VSID */
 181        mulli   r3,r3,897*16            /* multiply context by context skew */
 182        rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
 183        mulli   r0,r0,0x111             /* multiply by ESID skew */
 184        add     r3,r3,r0                /* note create_hpte trims to 24 bits */
 185
 186#ifdef CONFIG_SMP
 187        CURRENT_THREAD_INFO(r8, r1)     /* use cpu number to make tag */
 188        lwz     r8,TI_CPU(r8)           /* to go in mmu_hash_lock */
 189        oris    r8,r8,12
 190#endif /* CONFIG_SMP */
 191
 192        /*
 193         * We disable interrupts here, even on UP, because we don't
 194         * want to race with hash_page, and because we want the
 195         * _PAGE_HASHPTE bit to be a reliable indication of whether
 196         * the HPTE exists (or at least whether one did once).
 197         * We also turn off the MMU for data accesses so that we
 198         * we can't take a hash table miss (assuming the code is
 199         * covered by a BAT).  -- paulus
 200         */
 201        mfmsr   r9
 202        SYNC
 203        rlwinm  r0,r9,0,17,15           /* clear bit 16 (MSR_EE) */
 204        rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
 205        mtmsr   r0
 206        SYNC_601
 207        isync
 208
 209        tophys(r7,0)
 210
 211#ifdef CONFIG_SMP
 212        addis   r6,r7,mmu_hash_lock@ha
 213        addi    r6,r6,mmu_hash_lock@l
 21410:     lwarx   r0,0,r6                 /* take the mmu_hash_lock */
 215        cmpi    0,r0,0
 216        bne-    11f
 217        stwcx.  r8,0,r6
 218        beq+    12f
 21911:     lwz     r0,0(r6)
 220        cmpi    0,r0,0
 221        beq     10b
 222        b       11b
 22312:     isync
 224#endif
 225
 226        /*
 227         * Fetch the linux pte and test and set _PAGE_HASHPTE atomically.
 228         * If _PAGE_HASHPTE was already set, we don't replace the existing
 229         * HPTE, so we just unlock and return.
 230         */
 231        mr      r8,r5
 232#ifndef CONFIG_PTE_64BIT
 233        rlwimi  r8,r4,22,20,29
 234#else
 235        rlwimi  r8,r4,23,20,28
 236        addi    r8,r8,PTE_FLAGS_OFFSET
 237#endif
 2381:      lwarx   r6,0,r8
 239        andi.   r0,r6,_PAGE_HASHPTE
 240        bne     9f                      /* if HASHPTE already set, done */
 241#ifdef CONFIG_PTE_64BIT
 242#ifdef CONFIG_SMP
 243        subf    r10,r6,r8               /* create false data dependency */
 244        subi    r10,r10,PTE_FLAGS_OFFSET
 245        lwzx    r10,r6,r10              /* Get upper PTE word */
 246#else
 247        lwz     r10,-PTE_FLAGS_OFFSET(r8)
 248#endif /* CONFIG_SMP */
 249#endif /* CONFIG_PTE_64BIT */
 250        ori     r5,r6,_PAGE_HASHPTE
 251        stwcx.  r5,0,r8
 252        bne-    1b
 253
 254        bl      create_hpte
 255
 2569:
 257#ifdef CONFIG_SMP
 258        addis   r6,r7,mmu_hash_lock@ha
 259        addi    r6,r6,mmu_hash_lock@l
 260        eieio
 261        li      r0,0
 262        stw     r0,0(r6)                /* clear mmu_hash_lock */
 263#endif
 264
 265        /* reenable interrupts and DR */
 266        mtmsr   r9
 267        SYNC_601
 268        isync
 269
 270        lwz     r0,4(r1)
 271        mtlr    r0
 272        blr
 273
 274/*
 275 * This routine adds a hardware PTE to the hash table.
 276 * It is designed to be called with the MMU either on or off.
 277 * r3 contains the VSID, r4 contains the virtual address,
 278 * r5 contains the linux PTE, r6 contains the old value of the
 279 * linux PTE (before setting _PAGE_HASHPTE) and r7 contains the
 280 * offset to be added to addresses (0 if the MMU is on,
 281 * -KERNELBASE if it is off).  r10 contains the upper half of
 282 * the PTE if CONFIG_PTE_64BIT.
 283 * On SMP, the caller should have the mmu_hash_lock held.
 284 * We assume that the caller has (or will) set the _PAGE_HASHPTE
 285 * bit in the linux PTE in memory.  The value passed in r6 should
 286 * be the old linux PTE value; if it doesn't have _PAGE_HASHPTE set
 287 * this routine will skip the search for an existing HPTE.
 288 * This procedure modifies r0, r3 - r6, r8, cr0.
 289 *  -- paulus.
 290 *
 291 * For speed, 4 of the instructions get patched once the size and
 292 * physical address of the hash table are known.  These definitions
 293 * of Hash_base and Hash_bits below are just an example.
 294 */
 295Hash_base = 0xc0180000
 296Hash_bits = 12                          /* e.g. 256kB hash table */
 297Hash_msk = (((1 << Hash_bits) - 1) * 64)
 298
 299/* defines for the PTE format for 32-bit PPCs */
 300#define HPTE_SIZE       8
 301#define PTEG_SIZE       64
 302#define LG_PTEG_SIZE    6
 303#define LDPTEu          lwzu
 304#define LDPTE           lwz
 305#define STPTE           stw
 306#define CMPPTE          cmpw
 307#define PTE_H           0x40
 308#define PTE_V           0x80000000
 309#define TST_V(r)        rlwinm. r,r,0,0,0
 310#define SET_V(r)        oris r,r,PTE_V@h
 311#define CLR_V(r,t)      rlwinm r,r,0,1,31
 312
 313#define HASH_LEFT       31-(LG_PTEG_SIZE+Hash_bits-1)
 314#define HASH_RIGHT      31-LG_PTEG_SIZE
 315
 316_GLOBAL(create_hpte)
 317        /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */
 318        rlwinm  r8,r5,32-10,31,31       /* _PAGE_RW -> PP lsb */
 319        rlwinm  r0,r5,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
 320        and     r8,r8,r0                /* writable if _RW & _DIRTY */
 321        rlwimi  r5,r5,32-1,30,30        /* _PAGE_USER -> PP msb */
 322        rlwimi  r5,r5,32-2,31,31        /* _PAGE_USER -> PP lsb */
 323        ori     r8,r8,0xe04             /* clear out reserved bits */
 324        andc    r8,r5,r8                /* PP = user? (rw&dirty? 2: 3): 0 */
 325BEGIN_FTR_SECTION
 326        rlwinm  r8,r8,0,~_PAGE_COHERENT /* clear M (coherence not required) */
 327END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
 328#ifdef CONFIG_PTE_64BIT
 329        /* Put the XPN bits into the PTE */
 330        rlwimi  r8,r10,8,20,22
 331        rlwimi  r8,r10,2,29,29
 332#endif
 333
 334        /* Construct the high word of the PPC-style PTE (r5) */
 335        rlwinm  r5,r3,7,1,24            /* put VSID in 0x7fffff80 bits */
 336        rlwimi  r5,r4,10,26,31          /* put in API (abbrev page index) */
 337        SET_V(r5)                       /* set V (valid) bit */
 338
 339        /* Get the address of the primary PTE group in the hash table (r3) */
 340_GLOBAL(hash_page_patch_A)
 341        addis   r0,r7,Hash_base@h       /* base address of hash table */
 342        rlwimi  r0,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
 343        rlwinm  r3,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
 344        xor     r3,r3,r0                /* make primary hash */
 345        li      r0,8                    /* PTEs/group */
 346
 347        /*
 348         * Test the _PAGE_HASHPTE bit in the old linux PTE, and skip the search
 349         * if it is clear, meaning that the HPTE isn't there already...
 350         */
 351        andi.   r6,r6,_PAGE_HASHPTE
 352        beq+    10f                     /* no PTE: go look for an empty slot */
 353        tlbie   r4
 354
 355        addis   r4,r7,htab_hash_searches@ha
 356        lwz     r6,htab_hash_searches@l(r4)
 357        addi    r6,r6,1                 /* count how many searches we do */
 358        stw     r6,htab_hash_searches@l(r4)
 359
 360        /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
 361        mtctr   r0
 362        addi    r4,r3,-HPTE_SIZE
 3631:      LDPTEu  r6,HPTE_SIZE(r4)        /* get next PTE */
 364        CMPPTE  0,r6,r5
 365        bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
 366        beq+    found_slot
 367
 368        /* Search the secondary PTEG for a matching PTE */
 369        ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
 370_GLOBAL(hash_page_patch_B)
 371        xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
 372        xori    r4,r4,(-PTEG_SIZE & 0xffff)
 373        addi    r4,r4,-HPTE_SIZE
 374        mtctr   r0
 3752:      LDPTEu  r6,HPTE_SIZE(r4)
 376        CMPPTE  0,r6,r5
 377        bdnzf   2,2b
 378        beq+    found_slot
 379        xori    r5,r5,PTE_H             /* clear H bit again */
 380
 381        /* Search the primary PTEG for an empty slot */
 38210:     mtctr   r0
 383        addi    r4,r3,-HPTE_SIZE        /* search primary PTEG */
 3841:      LDPTEu  r6,HPTE_SIZE(r4)        /* get next PTE */
 385        TST_V(r6)                       /* test valid bit */
 386        bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
 387        beq+    found_empty
 388
 389        /* update counter of times that the primary PTEG is full */
 390        addis   r4,r7,primary_pteg_full@ha
 391        lwz     r6,primary_pteg_full@l(r4)
 392        addi    r6,r6,1
 393        stw     r6,primary_pteg_full@l(r4)
 394
 395        /* Search the secondary PTEG for an empty slot */
 396        ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
 397_GLOBAL(hash_page_patch_C)
 398        xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
 399        xori    r4,r4,(-PTEG_SIZE & 0xffff)
 400        addi    r4,r4,-HPTE_SIZE
 401        mtctr   r0
 4022:      LDPTEu  r6,HPTE_SIZE(r4)
 403        TST_V(r6)
 404        bdnzf   2,2b
 405        beq+    found_empty
 406        xori    r5,r5,PTE_H             /* clear H bit again */
 407
 408        /*
 409         * Choose an arbitrary slot in the primary PTEG to overwrite.
 410         * Since both the primary and secondary PTEGs are full, and we
 411         * have no information that the PTEs in the primary PTEG are
 412         * more important or useful than those in the secondary PTEG,
 413         * and we know there is a definite (although small) speed
 414         * advantage to putting the PTE in the primary PTEG, we always
 415         * put the PTE in the primary PTEG.
 416         *
 417         * In addition, we skip any slot that is mapping kernel text in
 418         * order to avoid a deadlock when not using BAT mappings if
 419         * trying to hash in the kernel hash code itself after it has
 420         * already taken the hash table lock. This works in conjunction
 421         * with pre-faulting of the kernel text.
 422         *
 423         * If the hash table bucket is full of kernel text entries, we'll
 424         * lockup here but that shouldn't happen
 425         */
 426
 4271:      addis   r4,r7,next_slot@ha              /* get next evict slot */
 428        lwz     r6,next_slot@l(r4)
 429        addi    r6,r6,HPTE_SIZE                 /* search for candidate */
 430        andi.   r6,r6,7*HPTE_SIZE
 431        stw     r6,next_slot@l(r4)
 432        add     r4,r3,r6
 433        LDPTE   r0,HPTE_SIZE/2(r4)              /* get PTE second word */
 434        clrrwi  r0,r0,12
 435        lis     r6,etext@h
 436        ori     r6,r6,etext@l                   /* get etext */
 437        tophys(r6,r6)
 438        cmpl    cr0,r0,r6                       /* compare and try again */
 439        blt     1b
 440
 441#ifndef CONFIG_SMP
 442        /* Store PTE in PTEG */
 443found_empty:
 444        STPTE   r5,0(r4)
 445found_slot:
 446        STPTE   r8,HPTE_SIZE/2(r4)
 447
 448#else /* CONFIG_SMP */
 449/*
 450 * Between the tlbie above and updating the hash table entry below,
 451 * another CPU could read the hash table entry and put it in its TLB.
 452 * There are 3 cases:
 453 * 1. using an empty slot
 454 * 2. updating an earlier entry to change permissions (i.e. enable write)
 455 * 3. taking over the PTE for an unrelated address
 456 *
 457 * In each case it doesn't really matter if the other CPUs have the old
 458 * PTE in their TLB.  So we don't need to bother with another tlbie here,
 459 * which is convenient as we've overwritten the register that had the
 460 * address. :-)  The tlbie above is mainly to make sure that this CPU comes
 461 * and gets the new PTE from the hash table.
 462 *
 463 * We do however have to make sure that the PTE is never in an invalid
 464 * state with the V bit set.
 465 */
 466found_empty:
 467found_slot:
 468        CLR_V(r5,r0)            /* clear V (valid) bit in PTE */
 469        STPTE   r5,0(r4)
 470        sync
 471        TLBSYNC
 472        STPTE   r8,HPTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */
 473        sync
 474        SET_V(r5)
 475        STPTE   r5,0(r4)        /* finally set V bit in PTE */
 476#endif /* CONFIG_SMP */
 477
 478        sync            /* make sure pte updates get to memory */
 479        blr
 480
 481        .section .bss
 482        .align  2
 483next_slot:
 484        .space  4
 485primary_pteg_full:
 486        .space  4
 487htab_hash_searches:
 488        .space  4
 489        .previous
 490
 491/*
 492 * Flush the entry for a particular page from the hash table.
 493 *
 494 * flush_hash_pages(unsigned context, unsigned long va, unsigned long pmdval,
 495 *                  int count)
 496 *
 497 * We assume that there is a hash table in use (Hash != 0).
 498 */
 499_GLOBAL(flush_hash_pages)
 500        tophys(r7,0)
 501
 502        /*
 503         * We disable interrupts here, even on UP, because we want
 504         * the _PAGE_HASHPTE bit to be a reliable indication of
 505         * whether the HPTE exists (or at least whether one did once).
 506         * We also turn off the MMU for data accesses so that we
 507         * we can't take a hash table miss (assuming the code is
 508         * covered by a BAT).  -- paulus
 509         */
 510        mfmsr   r10
 511        SYNC
 512        rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
 513        rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
 514        mtmsr   r0
 515        SYNC_601
 516        isync
 517
 518        /* First find a PTE in the range that has _PAGE_HASHPTE set */
 519#ifndef CONFIG_PTE_64BIT
 520        rlwimi  r5,r4,22,20,29
 521#else
 522        rlwimi  r5,r4,23,20,28
 523#endif
 5241:      lwz     r0,PTE_FLAGS_OFFSET(r5)
 525        cmpwi   cr1,r6,1
 526        andi.   r0,r0,_PAGE_HASHPTE
 527        bne     2f
 528        ble     cr1,19f
 529        addi    r4,r4,0x1000
 530        addi    r5,r5,PTE_SIZE
 531        addi    r6,r6,-1
 532        b       1b
 533
 534        /* Convert context and va to VSID */
 5352:      mulli   r3,r3,897*16            /* multiply context by context skew */
 536        rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
 537        mulli   r0,r0,0x111             /* multiply by ESID skew */
 538        add     r3,r3,r0                /* note code below trims to 24 bits */
 539
 540        /* Construct the high word of the PPC-style PTE (r11) */
 541        rlwinm  r11,r3,7,1,24           /* put VSID in 0x7fffff80 bits */
 542        rlwimi  r11,r4,10,26,31         /* put in API (abbrev page index) */
 543        SET_V(r11)                      /* set V (valid) bit */
 544
 545#ifdef CONFIG_SMP
 546        addis   r9,r7,mmu_hash_lock@ha
 547        addi    r9,r9,mmu_hash_lock@l
 548        CURRENT_THREAD_INFO(r8, r1)
 549        add     r8,r8,r7
 550        lwz     r8,TI_CPU(r8)
 551        oris    r8,r8,9
 55210:     lwarx   r0,0,r9
 553        cmpi    0,r0,0
 554        bne-    11f
 555        stwcx.  r8,0,r9
 556        beq+    12f
 55711:     lwz     r0,0(r9)
 558        cmpi    0,r0,0
 559        beq     10b
 560        b       11b
 56112:     isync
 562#endif
 563
 564        /*
 565         * Check the _PAGE_HASHPTE bit in the linux PTE.  If it is
 566         * already clear, we're done (for this pte).  If not,
 567         * clear it (atomically) and proceed.  -- paulus.
 568         */
 569#if (PTE_FLAGS_OFFSET != 0)
 570        addi    r5,r5,PTE_FLAGS_OFFSET
 571#endif
 57233:     lwarx   r8,0,r5                 /* fetch the pte flags word */
 573        andi.   r0,r8,_PAGE_HASHPTE
 574        beq     8f                      /* done if HASHPTE is already clear */
 575        rlwinm  r8,r8,0,31,29           /* clear HASHPTE bit */
 576        stwcx.  r8,0,r5                 /* update the pte */
 577        bne-    33b
 578
 579        /* Get the address of the primary PTE group in the hash table (r3) */
 580_GLOBAL(flush_hash_patch_A)
 581        addis   r8,r7,Hash_base@h       /* base address of hash table */
 582        rlwimi  r8,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
 583        rlwinm  r0,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
 584        xor     r8,r0,r8                /* make primary hash */
 585
 586        /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
 587        li      r0,8                    /* PTEs/group */
 588        mtctr   r0
 589        addi    r12,r8,-HPTE_SIZE
 5901:      LDPTEu  r0,HPTE_SIZE(r12)       /* get next PTE */
 591        CMPPTE  0,r0,r11
 592        bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
 593        beq+    3f
 594
 595        /* Search the secondary PTEG for a matching PTE */
 596        ori     r11,r11,PTE_H           /* set H (secondary hash) bit */
 597        li      r0,8                    /* PTEs/group */
 598_GLOBAL(flush_hash_patch_B)
 599        xoris   r12,r8,Hash_msk>>16     /* compute secondary hash */
 600        xori    r12,r12,(-PTEG_SIZE & 0xffff)
 601        addi    r12,r12,-HPTE_SIZE
 602        mtctr   r0
 6032:      LDPTEu  r0,HPTE_SIZE(r12)
 604        CMPPTE  0,r0,r11
 605        bdnzf   2,2b
 606        xori    r11,r11,PTE_H           /* clear H again */
 607        bne-    4f                      /* should rarely fail to find it */
 608
 6093:      li      r0,0
 610        STPTE   r0,0(r12)               /* invalidate entry */
 6114:      sync
 612        tlbie   r4                      /* in hw tlb too */
 613        sync
 614
 6158:      ble     cr1,9f                  /* if all ptes checked */
 61681:     addi    r6,r6,-1
 617        addi    r5,r5,PTE_SIZE
 618        addi    r4,r4,0x1000
 619        lwz     r0,0(r5)                /* check next pte */
 620        cmpwi   cr1,r6,1
 621        andi.   r0,r0,_PAGE_HASHPTE
 622        bne     33b
 623        bgt     cr1,81b
 624
 6259:
 626#ifdef CONFIG_SMP
 627        TLBSYNC
 628        li      r0,0
 629        stw     r0,0(r9)                /* clear mmu_hash_lock */
 630#endif
 631
 63219:     mtmsr   r10
 633        SYNC_601
 634        isync
 635        blr
 636
 637/*
 638 * Flush an entry from the TLB
 639 */
 640_GLOBAL(_tlbie)
 641#ifdef CONFIG_SMP
 642        CURRENT_THREAD_INFO(r8, r1)
 643        lwz     r8,TI_CPU(r8)
 644        oris    r8,r8,11
 645        mfmsr   r10
 646        SYNC
 647        rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
 648        rlwinm  r0,r0,0,28,26           /* clear DR */
 649        mtmsr   r0
 650        SYNC_601
 651        isync
 652        lis     r9,mmu_hash_lock@h
 653        ori     r9,r9,mmu_hash_lock@l
 654        tophys(r9,r9)
 65510:     lwarx   r7,0,r9
 656        cmpwi   0,r7,0
 657        bne-    10b
 658        stwcx.  r8,0,r9
 659        bne-    10b
 660        eieio
 661        tlbie   r3
 662        sync
 663        TLBSYNC
 664        li      r0,0
 665        stw     r0,0(r9)                /* clear mmu_hash_lock */
 666        mtmsr   r10
 667        SYNC_601
 668        isync
 669#else /* CONFIG_SMP */
 670        tlbie   r3
 671        sync
 672#endif /* CONFIG_SMP */
 673        blr
 674
 675/*
 676 * Flush the entire TLB. 603/603e only
 677 */
 678_GLOBAL(_tlbia)
 679#if defined(CONFIG_SMP)
 680        CURRENT_THREAD_INFO(r8, r1)
 681        lwz     r8,TI_CPU(r8)
 682        oris    r8,r8,10
 683        mfmsr   r10
 684        SYNC
 685        rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
 686        rlwinm  r0,r0,0,28,26           /* clear DR */
 687        mtmsr   r0
 688        SYNC_601
 689        isync
 690        lis     r9,mmu_hash_lock@h
 691        ori     r9,r9,mmu_hash_lock@l
 692        tophys(r9,r9)
 69310:     lwarx   r7,0,r9
 694        cmpwi   0,r7,0
 695        bne-    10b
 696        stwcx.  r8,0,r9
 697        bne-    10b
 698        sync
 699        tlbia
 700        sync
 701        TLBSYNC
 702        li      r0,0
 703        stw     r0,0(r9)                /* clear mmu_hash_lock */
 704        mtmsr   r10
 705        SYNC_601
 706        isync
 707#else /* CONFIG_SMP */
 708        sync
 709        tlbia
 710        sync
 711#endif /* CONFIG_SMP */
 712        blr
 713