]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
powerpc/mm: Move book3s32 specifics in subdirectory mm/book3s64
authorChristophe Leroy <christophe.leroy@c-s.fr>
Fri, 29 Mar 2019 10:00:01 +0000 (10:00 +0000)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 2 May 2019 15:20:22 +0000 (01:20 +1000)
Several files in arch/powerpc/mm are only for book3S32. This patch
creates a subdirectory for them.

Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
[mpe: Shorten new filenames]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/mm/Makefile
arch/powerpc/mm/book3s32/Makefile [new file with mode: 0644]
arch/powerpc/mm/book3s32/hash_low.S [new file with mode: 0644]
arch/powerpc/mm/book3s32/mmu.c [new file with mode: 0644]
arch/powerpc/mm/book3s32/mmu_context.c [new file with mode: 0644]
arch/powerpc/mm/book3s32/tlb.c [new file with mode: 0644]
arch/powerpc/mm/hash_low_32.S [deleted file]
arch/powerpc/mm/mmu_context_hash32.c [deleted file]
arch/powerpc/mm/ppc_mmu_32.c [deleted file]
arch/powerpc/mm/tlb_hash32.c [deleted file]

index a137fdf775e25adc5ac9383bee7ec09ea4e7e2d8..68cb1e840b5e97de49b8e8ea6f560732f795e211 100644 (file)
@@ -12,11 +12,10 @@ obj-$(CONFIG_PPC_MMU_NOHASH)        += mmu_context_nohash.o tlb_nohash.o \
                                   tlb_nohash_low.o
 obj-$(CONFIG_PPC_BOOK3E)       += tlb_low_$(BITS)e.o
 obj-$(CONFIG_PPC_BOOK3E_64)   += pgtable-book3e.o
+obj-$(CONFIG_PPC_BOOK3S_32)    += book3s32/
 obj-$(CONFIG_PPC_BOOK3S_64)    += book3s64/
 obj-$(CONFIG_PPC_BOOK3S_64)    += pgtable-frag.o
 obj-$(CONFIG_PPC32)            += pgtable-frag.o
-obj-$(CONFIG_PPC_BOOK3S_32)    += ppc_mmu_32.o hash_low_32.o mmu_context_hash32.o
-obj-$(CONFIG_PPC_BOOK3S_32)    += tlb_hash32.o
 obj-$(CONFIG_40x)              += 40x_mmu.o
 obj-$(CONFIG_44x)              += 44x_mmu.o
 obj-$(CONFIG_PPC_8xx)          += 8xx_mmu.o
diff --git a/arch/powerpc/mm/book3s32/Makefile b/arch/powerpc/mm/book3s32/Makefile
new file mode 100644 (file)
index 0000000..a4e217d
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += mmu.o hash_low.o mmu_context.o tlb.o
diff --git a/arch/powerpc/mm/book3s32/hash_low.S b/arch/powerpc/mm/book3s32/hash_low.S
new file mode 100644 (file)
index 0000000..e27792d
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *  Adapted for Power Macintosh by Paul Mackerras.
+ *  Low-level exception handlers and MMU support
+ *  rewritten by Paul Mackerras.
+ *    Copyright (C) 1996 Paul Mackerras.
+ *
+ *  This file contains low-level assembler routines for managing
+ *  the PowerPC MMU hash table.  (PPC 8xx processors don't use a
+ *  hash table, so this file is not used on them.)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/export.h>
+#include <asm/feature-fixups.h>
+#include <asm/code-patching-asm.h>
+
+#ifdef CONFIG_SMP
+       .section .bss
+       .align  2
+mmu_hash_lock:
+       .space  4
+#endif /* CONFIG_SMP */
+
+/*
+ * Load a PTE into the hash table, if possible.
+ * The address is in r4, and r3 contains an access flag:
+ * _PAGE_RW (0x400) if a write.
+ * r9 contains the SRR1 value, from which we use the MSR_PR bit.
+ * SPRG_THREAD contains the physical address of the current task's thread.
+ *
+ * Returns to the caller if the access is illegal or there is no
+ * mapping for the address.  Otherwise it places an appropriate PTE
+ * in the hash table and returns from the exception.
+ * Uses r0, r3 - r6, r8, r10, ctr, lr.
+ */
+       .text
+_GLOBAL(hash_page)
+#ifdef CONFIG_SMP
+       lis     r8, (mmu_hash_lock - PAGE_OFFSET)@h
+       ori     r8, r8, (mmu_hash_lock - PAGE_OFFSET)@l
+       lis     r0,0x0fff
+       b       10f
+11:    lwz     r6,0(r8)
+       cmpwi   0,r6,0
+       bne     11b
+10:    lwarx   r6,0,r8
+       cmpwi   0,r6,0
+       bne-    11b
+       stwcx.  r0,0,r8
+       bne-    10b
+       isync
+#endif
+       /* Get PTE (linux-style) and check access */
+       lis     r0,KERNELBASE@h         /* check if kernel address */
+       cmplw   0,r4,r0
+       ori     r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
+       mfspr   r5, SPRN_SPRG_PGDIR     /* phys page-table root */
+       blt+    112f                    /* assume user more likely */
+       lis     r5, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
+       addi    r5 ,r5 ,(swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
+       rlwimi  r3,r9,32-12,29,29       /* MSR_PR -> _PAGE_USER */
+112:
+#ifndef CONFIG_PTE_64BIT
+       rlwimi  r5,r4,12,20,29          /* insert top 10 bits of address */
+       lwz     r8,0(r5)                /* get pmd entry */
+       rlwinm. r8,r8,0,0,19            /* extract address of pte page */
+#else
+       rlwinm  r8,r4,13,19,29          /* Compute pgdir/pmd offset */
+       lwzx    r8,r8,r5                /* Get L1 entry */
+       rlwinm. r8,r8,0,0,20            /* extract pt base address */
+#endif
+#ifdef CONFIG_SMP
+       beq-    hash_page_out           /* return if no mapping */
+#else
+       /* XXX it seems like the 601 will give a machine fault on the
+          rfi if its alignment is wrong (bottom 4 bits of address are
+          8 or 0xc) and we have had a not-taken conditional branch
+          to the address following the rfi. */
+       beqlr-
+#endif
+#ifndef CONFIG_PTE_64BIT
+       rlwimi  r8,r4,22,20,29          /* insert next 10 bits of address */
+#else
+       rlwimi  r8,r4,23,20,28          /* compute pte address */
+#endif
+       rlwinm  r0,r3,32-3,24,24        /* _PAGE_RW access -> _PAGE_DIRTY */
+       ori     r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
+
+       /*
+        * Update the linux PTE atomically.  We do the lwarx up-front
+        * because almost always, there won't be a permission violation
+        * and there won't already be an HPTE, and thus we will have
+        * to update the PTE to set _PAGE_HASHPTE.  -- paulus.
+        *
+        * If PTE_64BIT is set, the low word is the flags word; use that
+        * word for locking since it contains all the interesting bits.
+        */
+#if (PTE_FLAGS_OFFSET != 0)
+       addi    r8,r8,PTE_FLAGS_OFFSET
+#endif
+retry:
+       lwarx   r6,0,r8                 /* get linux-style pte, flag word */
+       andc.   r5,r3,r6                /* check access & ~permission */
+#ifdef CONFIG_SMP
+       bne-    hash_page_out           /* return if access not permitted */
+#else
+       bnelr-
+#endif
+       or      r5,r0,r6                /* set accessed/dirty bits */
+#ifdef CONFIG_PTE_64BIT
+#ifdef CONFIG_SMP
+       subf    r10,r6,r8               /* create false data dependency */
+       subi    r10,r10,PTE_FLAGS_OFFSET
+       lwzx    r10,r6,r10              /* Get upper PTE word */
+#else
+       lwz     r10,-PTE_FLAGS_OFFSET(r8)
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_PTE_64BIT */
+       stwcx.  r5,0,r8                 /* attempt to update PTE */
+       bne-    retry                   /* retry if someone got there first */
+
+       mfsrin  r3,r4                   /* get segment reg for segment */
+       mfctr   r0
+       stw     r0,_CTR(r11)
+       bl      create_hpte             /* add the hash table entry */
+
+#ifdef CONFIG_SMP
+       eieio
+       lis     r8, (mmu_hash_lock - PAGE_OFFSET)@ha
+       li      r0,0
+       stw     r0, (mmu_hash_lock - PAGE_OFFSET)@l(r8)
+#endif
+
+       /* Return from the exception */
+       lwz     r5,_CTR(r11)
+       mtctr   r5
+       lwz     r0,GPR0(r11)
+       lwz     r8,GPR8(r11)
+       b       fast_exception_return
+
+#ifdef CONFIG_SMP
+hash_page_out:
+       eieio
+       lis     r8, (mmu_hash_lock - PAGE_OFFSET)@ha
+       li      r0,0
+       stw     r0, (mmu_hash_lock - PAGE_OFFSET)@l(r8)
+       blr
+#endif /* CONFIG_SMP */
+
+/*
+ * Add an entry for a particular page to the hash table.
+ *
+ * add_hash_page(unsigned context, unsigned long va, unsigned long pmdval)
+ *
+ * We assume any necessary modifications to the pte (e.g. setting
+ * the accessed bit) have already been done and that there is actually
+ * a hash table in use (i.e. we're not on a 603).
+ */
+_GLOBAL(add_hash_page)
+       mflr    r0
+       stw     r0,4(r1)
+
+       /* Convert context and va to VSID */
+       mulli   r3,r3,897*16            /* multiply context by context skew */
+       rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
+       mulli   r0,r0,0x111             /* multiply by ESID skew */
+       add     r3,r3,r0                /* note create_hpte trims to 24 bits */
+
+#ifdef CONFIG_SMP
+       lwz     r8,TASK_CPU(r2)         /* to go in mmu_hash_lock */
+       oris    r8,r8,12
+#endif /* CONFIG_SMP */
+
+       /*
+        * We disable interrupts here, even on UP, because we don't
+        * want to race with hash_page, and because we want the
+        * _PAGE_HASHPTE bit to be a reliable indication of whether
+        * the HPTE exists (or at least whether one did once).
+        * We also turn off the MMU for data accesses so that we
+        * we can't take a hash table miss (assuming the code is
+        * covered by a BAT).  -- paulus
+        */
+       mfmsr   r9
+       SYNC
+       rlwinm  r0,r9,0,17,15           /* clear bit 16 (MSR_EE) */
+       rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
+       mtmsr   r0
+       SYNC_601
+       isync
+
+#ifdef CONFIG_SMP
+       lis     r6, (mmu_hash_lock - PAGE_OFFSET)@ha
+       addi    r6, r6, (mmu_hash_lock - PAGE_OFFSET)@l
+10:    lwarx   r0,0,r6                 /* take the mmu_hash_lock */
+       cmpi    0,r0,0
+       bne-    11f
+       stwcx.  r8,0,r6
+       beq+    12f
+11:    lwz     r0,0(r6)
+       cmpi    0,r0,0
+       beq     10b
+       b       11b
+12:    isync
+#endif
+
+       /*
+        * Fetch the linux pte and test and set _PAGE_HASHPTE atomically.
+        * If _PAGE_HASHPTE was already set, we don't replace the existing
+        * HPTE, so we just unlock and return.
+        */
+       mr      r8,r5
+#ifndef CONFIG_PTE_64BIT
+       rlwimi  r8,r4,22,20,29
+#else
+       rlwimi  r8,r4,23,20,28
+       addi    r8,r8,PTE_FLAGS_OFFSET
+#endif
+1:     lwarx   r6,0,r8
+       andi.   r0,r6,_PAGE_HASHPTE
+       bne     9f                      /* if HASHPTE already set, done */
+#ifdef CONFIG_PTE_64BIT
+#ifdef CONFIG_SMP
+       subf    r10,r6,r8               /* create false data dependency */
+       subi    r10,r10,PTE_FLAGS_OFFSET
+       lwzx    r10,r6,r10              /* Get upper PTE word */
+#else
+       lwz     r10,-PTE_FLAGS_OFFSET(r8)
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_PTE_64BIT */
+       ori     r5,r6,_PAGE_HASHPTE
+       stwcx.  r5,0,r8
+       bne-    1b
+
+       bl      create_hpte
+
+9:
+#ifdef CONFIG_SMP
+       lis     r6, (mmu_hash_lock - PAGE_OFFSET)@ha
+       addi    r6, r6, (mmu_hash_lock - PAGE_OFFSET)@l
+       eieio
+       li      r0,0
+       stw     r0,0(r6)                /* clear mmu_hash_lock */
+#endif
+
+       /* reenable interrupts and DR */
+       mtmsr   r9
+       SYNC_601
+       isync
+
+       lwz     r0,4(r1)
+       mtlr    r0
+       blr
+
+/*
+ * This routine adds a hardware PTE to the hash table.
+ * It is designed to be called with the MMU either on or off.
+ * r3 contains the VSID, r4 contains the virtual address,
+ * r5 contains the linux PTE, r6 contains the old value of the
+ * linux PTE (before setting _PAGE_HASHPTE). r10 contains the
+ * upper half of the PTE if CONFIG_PTE_64BIT.
+ * On SMP, the caller should have the mmu_hash_lock held.
+ * We assume that the caller has (or will) set the _PAGE_HASHPTE
+ * bit in the linux PTE in memory.  The value passed in r6 should
+ * be the old linux PTE value; if it doesn't have _PAGE_HASHPTE set
+ * this routine will skip the search for an existing HPTE.
+ * This procedure modifies r0, r3 - r6, r8, cr0.
+ *  -- paulus.
+ *
+ * For speed, 4 of the instructions get patched once the size and
+ * physical address of the hash table are known.  These definitions
+ * of Hash_base and Hash_bits below are just an example.
+ */
+Hash_base = 0xc0180000
+Hash_bits = 12                         /* e.g. 256kB hash table */
+Hash_msk = (((1 << Hash_bits) - 1) * 64)
+
+/* defines for the PTE format for 32-bit PPCs */
+#define HPTE_SIZE      8
+#define PTEG_SIZE      64
+#define LG_PTEG_SIZE   6
+#define LDPTEu         lwzu
+#define LDPTE          lwz
+#define STPTE          stw
+#define CMPPTE         cmpw
+#define PTE_H          0x40
+#define PTE_V          0x80000000
+#define TST_V(r)       rlwinm. r,r,0,0,0
+#define SET_V(r)       oris r,r,PTE_V@h
+#define CLR_V(r,t)     rlwinm r,r,0,1,31
+
+#define HASH_LEFT      31-(LG_PTEG_SIZE+Hash_bits-1)
+#define HASH_RIGHT     31-LG_PTEG_SIZE
+
+_GLOBAL(create_hpte)
+       /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */
+       rlwinm  r8,r5,32-9,30,30        /* _PAGE_RW -> PP msb */
+       rlwinm  r0,r5,32-6,30,30        /* _PAGE_DIRTY -> PP msb */
+       and     r8,r8,r0                /* writable if _RW & _DIRTY */
+       rlwimi  r5,r5,32-1,30,30        /* _PAGE_USER -> PP msb */
+       rlwimi  r5,r5,32-2,31,31        /* _PAGE_USER -> PP lsb */
+       ori     r8,r8,0xe04             /* clear out reserved bits */
+       andc    r8,r5,r8                /* PP = user? (rw&dirty? 1: 3): 0 */
+BEGIN_FTR_SECTION
+       rlwinm  r8,r8,0,~_PAGE_COHERENT /* clear M (coherence not required) */
+END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
+#ifdef CONFIG_PTE_64BIT
+       /* Put the XPN bits into the PTE */
+       rlwimi  r8,r10,8,20,22
+       rlwimi  r8,r10,2,29,29
+#endif
+
+       /* Construct the high word of the PPC-style PTE (r5) */
+       rlwinm  r5,r3,7,1,24            /* put VSID in 0x7fffff80 bits */
+       rlwimi  r5,r4,10,26,31          /* put in API (abbrev page index) */
+       SET_V(r5)                       /* set V (valid) bit */
+
+       patch_site      0f, patch__hash_page_A0
+       patch_site      1f, patch__hash_page_A1
+       patch_site      2f, patch__hash_page_A2
+       /* Get the address of the primary PTE group in the hash table (r3) */
+0:     lis     r0, (Hash_base - PAGE_OFFSET)@h /* base address of hash table */
+1:     rlwimi  r0,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
+2:     rlwinm  r3,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
+       xor     r3,r3,r0                /* make primary hash */
+       li      r0,8                    /* PTEs/group */
+
+       /*
+        * Test the _PAGE_HASHPTE bit in the old linux PTE, and skip the search
+        * if it is clear, meaning that the HPTE isn't there already...
+        */
+       andi.   r6,r6,_PAGE_HASHPTE
+       beq+    10f                     /* no PTE: go look for an empty slot */
+       tlbie   r4
+
+       lis     r4, (htab_hash_searches - PAGE_OFFSET)@ha
+       lwz     r6, (htab_hash_searches - PAGE_OFFSET)@l(r4)
+       addi    r6,r6,1                 /* count how many searches we do */
+       stw     r6, (htab_hash_searches - PAGE_OFFSET)@l(r4)
+
+       /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
+       mtctr   r0
+       addi    r4,r3,-HPTE_SIZE
+1:     LDPTEu  r6,HPTE_SIZE(r4)        /* get next PTE */
+       CMPPTE  0,r6,r5
+       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
+       beq+    found_slot
+
+       patch_site      0f, patch__hash_page_B
+       /* Search the secondary PTEG for a matching PTE */
+       ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
+0:     xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
+       xori    r4,r4,(-PTEG_SIZE & 0xffff)
+       addi    r4,r4,-HPTE_SIZE
+       mtctr   r0
+2:     LDPTEu  r6,HPTE_SIZE(r4)
+       CMPPTE  0,r6,r5
+       bdnzf   2,2b
+       beq+    found_slot
+       xori    r5,r5,PTE_H             /* clear H bit again */
+
+       /* Search the primary PTEG for an empty slot */
+10:    mtctr   r0
+       addi    r4,r3,-HPTE_SIZE        /* search primary PTEG */
+1:     LDPTEu  r6,HPTE_SIZE(r4)        /* get next PTE */
+       TST_V(r6)                       /* test valid bit */
+       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
+       beq+    found_empty
+
+       /* update counter of times that the primary PTEG is full */
+       lis     r4, (primary_pteg_full - PAGE_OFFSET)@ha
+       lwz     r6, (primary_pteg_full - PAGE_OFFSET)@l(r4)
+       addi    r6,r6,1
+       stw     r6, (primary_pteg_full - PAGE_OFFSET)@l(r4)
+
+       patch_site      0f, patch__hash_page_C
+       /* Search the secondary PTEG for an empty slot */
+       ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
+0:     xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
+       xori    r4,r4,(-PTEG_SIZE & 0xffff)
+       addi    r4,r4,-HPTE_SIZE
+       mtctr   r0
+2:     LDPTEu  r6,HPTE_SIZE(r4)
+       TST_V(r6)
+       bdnzf   2,2b
+       beq+    found_empty
+       xori    r5,r5,PTE_H             /* clear H bit again */
+
+       /*
+        * Choose an arbitrary slot in the primary PTEG to overwrite.
+        * Since both the primary and secondary PTEGs are full, and we
+        * have no information that the PTEs in the primary PTEG are
+        * more important or useful than those in the secondary PTEG,
+        * and we know there is a definite (although small) speed
+        * advantage to putting the PTE in the primary PTEG, we always
+        * put the PTE in the primary PTEG.
+        *
+        * In addition, we skip any slot that is mapping kernel text in
+        * order to avoid a deadlock when not using BAT mappings if
+        * trying to hash in the kernel hash code itself after it has
+        * already taken the hash table lock. This works in conjunction
+        * with pre-faulting of the kernel text.
+        *
+        * If the hash table bucket is full of kernel text entries, we'll
+        * lockup here but that shouldn't happen
+        */
+
+1:     lis     r4, (next_slot - PAGE_OFFSET)@ha        /* get next evict slot */
+       lwz     r6, (next_slot - PAGE_OFFSET)@l(r4)
+       addi    r6,r6,HPTE_SIZE                 /* search for candidate */
+       andi.   r6,r6,7*HPTE_SIZE
+       stw     r6,next_slot@l(r4)
+       add     r4,r3,r6
+       LDPTE   r0,HPTE_SIZE/2(r4)              /* get PTE second word */
+       clrrwi  r0,r0,12
+       lis     r6,etext@h
+       ori     r6,r6,etext@l                   /* get etext */
+       tophys(r6,r6)
+       cmpl    cr0,r0,r6                       /* compare and try again */
+       blt     1b
+
+#ifndef CONFIG_SMP
+       /* Store PTE in PTEG */
+found_empty:
+       STPTE   r5,0(r4)
+found_slot:
+       STPTE   r8,HPTE_SIZE/2(r4)
+
+#else /* CONFIG_SMP */
+/*
+ * Between the tlbie above and updating the hash table entry below,
+ * another CPU could read the hash table entry and put it in its TLB.
+ * There are 3 cases:
+ * 1. using an empty slot
+ * 2. updating an earlier entry to change permissions (i.e. enable write)
+ * 3. taking over the PTE for an unrelated address
+ *
+ * In each case it doesn't really matter if the other CPUs have the old
+ * PTE in their TLB.  So we don't need to bother with another tlbie here,
+ * which is convenient as we've overwritten the register that had the
+ * address. :-)  The tlbie above is mainly to make sure that this CPU comes
+ * and gets the new PTE from the hash table.
+ *
+ * We do however have to make sure that the PTE is never in an invalid
+ * state with the V bit set.
+ */
+found_empty:
+found_slot:
+       CLR_V(r5,r0)            /* clear V (valid) bit in PTE */
+       STPTE   r5,0(r4)
+       sync
+       TLBSYNC
+       STPTE   r8,HPTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */
+       sync
+       SET_V(r5)
+       STPTE   r5,0(r4)        /* finally set V bit in PTE */
+#endif /* CONFIG_SMP */
+
+       sync            /* make sure pte updates get to memory */
+       blr
+
+       .section .bss
+       .align  2
+next_slot:
+       .space  4
+primary_pteg_full:
+       .space  4
+htab_hash_searches:
+       .space  4
+       .previous
+
+/*
+ * Flush the entry for a particular page from the hash table.
+ *
+ * flush_hash_pages(unsigned context, unsigned long va, unsigned long pmdval,
+ *                 int count)
+ *
+ * We assume that there is a hash table in use (Hash != 0).
+ */
+_GLOBAL(flush_hash_pages)
+       /*
+        * We disable interrupts here, even on UP, because we want
+        * the _PAGE_HASHPTE bit to be a reliable indication of
+        * whether the HPTE exists (or at least whether one did once).
+        * We also turn off the MMU for data accesses so that we
+        * we can't take a hash table miss (assuming the code is
+        * covered by a BAT).  -- paulus
+        */
+       mfmsr   r10
+       SYNC
+       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
+       rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
+       mtmsr   r0
+       SYNC_601
+       isync
+
+       /* First find a PTE in the range that has _PAGE_HASHPTE set */
+#ifndef CONFIG_PTE_64BIT
+       rlwimi  r5,r4,22,20,29
+#else
+       rlwimi  r5,r4,23,20,28
+#endif
+1:     lwz     r0,PTE_FLAGS_OFFSET(r5)
+       cmpwi   cr1,r6,1
+       andi.   r0,r0,_PAGE_HASHPTE
+       bne     2f
+       ble     cr1,19f
+       addi    r4,r4,0x1000
+       addi    r5,r5,PTE_SIZE
+       addi    r6,r6,-1
+       b       1b
+
+       /* Convert context and va to VSID */
+2:     mulli   r3,r3,897*16            /* multiply context by context skew */
+       rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
+       mulli   r0,r0,0x111             /* multiply by ESID skew */
+       add     r3,r3,r0                /* note code below trims to 24 bits */
+
+       /* Construct the high word of the PPC-style PTE (r11) */
+       rlwinm  r11,r3,7,1,24           /* put VSID in 0x7fffff80 bits */
+       rlwimi  r11,r4,10,26,31         /* put in API (abbrev page index) */
+       SET_V(r11)                      /* set V (valid) bit */
+
+#ifdef CONFIG_SMP
+       lis     r9, (mmu_hash_lock - PAGE_OFFSET)@ha
+       addi    r9, r9, (mmu_hash_lock - PAGE_OFFSET)@l
+       lwz     r8,TASK_CPU(r2)
+       oris    r8,r8,9
+10:    lwarx   r0,0,r9
+       cmpi    0,r0,0
+       bne-    11f
+       stwcx.  r8,0,r9
+       beq+    12f
+11:    lwz     r0,0(r9)
+       cmpi    0,r0,0
+       beq     10b
+       b       11b
+12:    isync
+#endif
+
+       /*
+        * Check the _PAGE_HASHPTE bit in the linux PTE.  If it is
+        * already clear, we're done (for this pte).  If not,
+        * clear it (atomically) and proceed.  -- paulus.
+        */
+#if (PTE_FLAGS_OFFSET != 0)
+       addi    r5,r5,PTE_FLAGS_OFFSET
+#endif
+33:    lwarx   r8,0,r5                 /* fetch the pte flags word */
+       andi.   r0,r8,_PAGE_HASHPTE
+       beq     8f                      /* done if HASHPTE is already clear */
+       rlwinm  r8,r8,0,31,29           /* clear HASHPTE bit */
+       stwcx.  r8,0,r5                 /* update the pte */
+       bne-    33b
+
+       patch_site      0f, patch__flush_hash_A0
+       patch_site      1f, patch__flush_hash_A1
+       patch_site      2f, patch__flush_hash_A2
+       /* Get the address of the primary PTE group in the hash table (r3) */
+0:     lis     r8, (Hash_base - PAGE_OFFSET)@h /* base address of hash table */
+1:     rlwimi  r8,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
+2:     rlwinm  r0,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
+       xor     r8,r0,r8                /* make primary hash */
+
+       /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
+       li      r0,8                    /* PTEs/group */
+       mtctr   r0
+       addi    r12,r8,-HPTE_SIZE
+1:     LDPTEu  r0,HPTE_SIZE(r12)       /* get next PTE */
+       CMPPTE  0,r0,r11
+       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
+       beq+    3f
+
+       patch_site      0f, patch__flush_hash_B
+       /* Search the secondary PTEG for a matching PTE */
+       ori     r11,r11,PTE_H           /* set H (secondary hash) bit */
+       li      r0,8                    /* PTEs/group */
+0:     xoris   r12,r8,Hash_msk>>16     /* compute secondary hash */
+       xori    r12,r12,(-PTEG_SIZE & 0xffff)
+       addi    r12,r12,-HPTE_SIZE
+       mtctr   r0
+2:     LDPTEu  r0,HPTE_SIZE(r12)
+       CMPPTE  0,r0,r11
+       bdnzf   2,2b
+       xori    r11,r11,PTE_H           /* clear H again */
+       bne-    4f                      /* should rarely fail to find it */
+
+3:     li      r0,0
+       STPTE   r0,0(r12)               /* invalidate entry */
+4:     sync
+       tlbie   r4                      /* in hw tlb too */
+       sync
+
+8:     ble     cr1,9f                  /* if all ptes checked */
+81:    addi    r6,r6,-1
+       addi    r5,r5,PTE_SIZE
+       addi    r4,r4,0x1000
+       lwz     r0,0(r5)                /* check next pte */
+       cmpwi   cr1,r6,1
+       andi.   r0,r0,_PAGE_HASHPTE
+       bne     33b
+       bgt     cr1,81b
+
+9:
+#ifdef CONFIG_SMP
+       TLBSYNC
+       li      r0,0
+       stw     r0,0(r9)                /* clear mmu_hash_lock */
+#endif
+
+19:    mtmsr   r10
+       SYNC_601
+       isync
+       blr
+EXPORT_SYMBOL(flush_hash_pages)
+
+/*
+ * Flush an entry from the TLB
+ */
+_GLOBAL(_tlbie)
+#ifdef CONFIG_SMP
+       lwz     r8,TASK_CPU(r2)
+       oris    r8,r8,11
+       mfmsr   r10
+       SYNC
+       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
+       rlwinm  r0,r0,0,28,26           /* clear DR */
+       mtmsr   r0
+       SYNC_601
+       isync
+       lis     r9,mmu_hash_lock@h
+       ori     r9,r9,mmu_hash_lock@l
+       tophys(r9,r9)
+10:    lwarx   r7,0,r9
+       cmpwi   0,r7,0
+       bne-    10b
+       stwcx.  r8,0,r9
+       bne-    10b
+       eieio
+       tlbie   r3
+       sync
+       TLBSYNC
+       li      r0,0
+       stw     r0,0(r9)                /* clear mmu_hash_lock */
+       mtmsr   r10
+       SYNC_601
+       isync
+#else /* CONFIG_SMP */
+       tlbie   r3
+       sync
+#endif /* CONFIG_SMP */
+       blr
+
+/*
+ * Flush the entire TLB. 603/603e only
+ */
+_GLOBAL(_tlbia)
+#if defined(CONFIG_SMP)
+       lwz     r8,TASK_CPU(r2)
+       oris    r8,r8,10
+       mfmsr   r10
+       SYNC
+       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
+       rlwinm  r0,r0,0,28,26           /* clear DR */
+       mtmsr   r0
+       SYNC_601
+       isync
+       lis     r9,mmu_hash_lock@h
+       ori     r9,r9,mmu_hash_lock@l
+       tophys(r9,r9)
+10:    lwarx   r7,0,r9
+       cmpwi   0,r7,0
+       bne-    10b
+       stwcx.  r8,0,r9
+       bne-    10b
+       sync
+       tlbia
+       sync
+       TLBSYNC
+       li      r0,0
+       stw     r0,0(r9)                /* clear mmu_hash_lock */
+       mtmsr   r10
+       SYNC_601
+       isync
+#else /* CONFIG_SMP */
+       sync
+       tlbia
+       sync
+#endif /* CONFIG_SMP */
+       blr
diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c
new file mode 100644 (file)
index 0000000..1db5515
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * This file contains the routines for handling the MMU on those
+ * PowerPC implementations where the MMU substantially follows the
+ * architecture specification.  This includes the 6xx, 7xx, 7xxx,
+ * and 8260 implementations but excludes the 8xx and 4xx.
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/memblock.h>
+
+#include <asm/prom.h>
+#include <asm/mmu.h>
+#include <asm/machdep.h>
+#include <asm/code-patching.h>
+#include <asm/sections.h>
+
+#include <mm/mmu_decl.h>
+
+struct hash_pte *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
+unsigned long _SDR1;
+
+struct ppc_bat BATS[8][2];     /* 8 pairs of IBAT, DBAT */
+
+struct batrange {              /* stores address ranges mapped by BATs */
+       unsigned long start;
+       unsigned long limit;
+       phys_addr_t phys;
+} bat_addrs[8];
+
+/*
+ * Return PA for this VA if it is mapped by a BAT, or 0
+ */
+phys_addr_t v_block_mapped(unsigned long va)
+{
+       int b;
+       for (b = 0; b < ARRAY_SIZE(bat_addrs); ++b)
+               if (va >= bat_addrs[b].start && va < bat_addrs[b].limit)
+                       return bat_addrs[b].phys + (va - bat_addrs[b].start);
+       return 0;
+}
+
+/*
+ * Return VA for a given PA or 0 if not mapped
+ */
+unsigned long p_block_mapped(phys_addr_t pa)
+{
+       int b;
+       for (b = 0; b < ARRAY_SIZE(bat_addrs); ++b)
+               if (pa >= bat_addrs[b].phys
+                   && pa < (bat_addrs[b].limit-bat_addrs[b].start)
+                             +bat_addrs[b].phys)
+                       return bat_addrs[b].start+(pa-bat_addrs[b].phys);
+       return 0;
+}
+
+static int find_free_bat(void)
+{
+       int b;
+
+       if (cpu_has_feature(CPU_FTR_601)) {
+               for (b = 0; b < 4; b++) {
+                       struct ppc_bat *bat = BATS[b];
+
+                       if (!(bat[0].batl & 0x40))
+                               return b;
+               }
+       } else {
+               int n = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
+
+               for (b = 0; b < n; b++) {
+                       struct ppc_bat *bat = BATS[b];
+
+                       if (!(bat[1].batu & 3))
+                               return b;
+               }
+       }
+       return -1;
+}
+
+static unsigned int block_size(unsigned long base, unsigned long top)
+{
+       unsigned int max_size = (cpu_has_feature(CPU_FTR_601) ? 8 : 256) << 20;
+       unsigned int base_shift = (fls(base) - 1) & 31;
+       unsigned int block_shift = (fls(top - base) - 1) & 31;
+
+       return min3(max_size, 1U << base_shift, 1U << block_shift);
+}
+
+/*
+ * Set up one of the IBAT (block address translation) register pairs.
+ * The parameters are not checked; in particular size must be a power
+ * of 2 between 128k and 256M.
+ * Only for 603+ ...
+ */
+static void setibat(int index, unsigned long virt, phys_addr_t phys,
+                   unsigned int size, pgprot_t prot)
+{
+       unsigned int bl = (size >> 17) - 1;
+       int wimgxpp;
+       struct ppc_bat *bat = BATS[index];
+       unsigned long flags = pgprot_val(prot);
+
+       if (!cpu_has_feature(CPU_FTR_NEED_COHERENT))
+               flags &= ~_PAGE_COHERENT;
+
+       wimgxpp = (flags & _PAGE_COHERENT) | (_PAGE_EXEC ? BPP_RX : BPP_XX);
+       bat[0].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
+       bat[0].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
+       if (flags & _PAGE_USER)
+               bat[0].batu |= 1;       /* Vp = 1 */
+}
+
+static void clearibat(int index)
+{
+       struct ppc_bat *bat = BATS[index];
+
+       bat[0].batu = 0;
+       bat[0].batl = 0;
+}
+
+static unsigned long __init __mmu_mapin_ram(unsigned long base, unsigned long top)
+{
+       int idx;
+
+       while ((idx = find_free_bat()) != -1 && base != top) {
+               unsigned int size = block_size(base, top);
+
+               if (size < 128 << 10)
+                       break;
+               setbat(idx, PAGE_OFFSET + base, base, size, PAGE_KERNEL_X);
+               base += size;
+       }
+
+       return base;
+}
+
+unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
+{
+       int done;
+       unsigned long border = (unsigned long)__init_begin - PAGE_OFFSET;
+
+       if (__map_without_bats) {
+               pr_debug("RAM mapped without BATs\n");
+               return base;
+       }
+
+       if (!strict_kernel_rwx_enabled() || base >= border || top <= border)
+               return __mmu_mapin_ram(base, top);
+
+       done = __mmu_mapin_ram(base, border);
+       if (done != border - base)
+               return done;
+
+       return done + __mmu_mapin_ram(border, top);
+}
+
+void mmu_mark_initmem_nx(void)
+{
+       int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
+       int i;
+       unsigned long base = (unsigned long)_stext - PAGE_OFFSET;
+       unsigned long top = (unsigned long)_etext - PAGE_OFFSET;
+       unsigned long size;
+
+       if (cpu_has_feature(CPU_FTR_601))
+               return;
+
+       for (i = 0; i < nb - 1 && base < top && top - base > (128 << 10);) {
+               size = block_size(base, top);
+               setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
+               base += size;
+       }
+       if (base < top) {
+               size = block_size(base, top);
+               size = max(size, 128UL << 10);
+               if ((top - base) > size) {
+                       if (strict_kernel_rwx_enabled())
+                               pr_warn("Kernel _etext not properly aligned\n");
+                       size <<= 1;
+               }
+               setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
+               base += size;
+       }
+       for (; i < nb; i++)
+               clearibat(i);
+
+       update_bats();
+
+       for (i = TASK_SIZE >> 28; i < 16; i++) {
+               /* Do not set NX on VM space for modules */
+               if (IS_ENABLED(CONFIG_MODULES) &&
+                   (VMALLOC_START & 0xf0000000) == i << 28)
+                       break;
+               mtsrin(mfsrin(i << 28) | 0x10000000, i << 28);
+       }
+}
+
+void mmu_mark_rodata_ro(void)
+{
+       int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
+       int i;
+
+       if (cpu_has_feature(CPU_FTR_601))
+               return;
+
+       for (i = 0; i < nb; i++) {
+               struct ppc_bat *bat = BATS[i];
+
+               if (bat_addrs[i].start < (unsigned long)__init_begin)
+                       bat[1].batl = (bat[1].batl & ~BPP_RW) | BPP_RX;
+       }
+
+       update_bats();
+}
+
+/*
+ * Set up one of the I/D BAT (block address translation) register pairs.
+ * The parameters are not checked; in particular size must be a power
+ * of 2 between 128k and 256M.
+ * On 603+, only set IBAT when _PAGE_EXEC is set
+ */
+void __init setbat(int index, unsigned long virt, phys_addr_t phys,
+                  unsigned int size, pgprot_t prot)
+{
+       unsigned int bl;
+       int wimgxpp;
+       struct ppc_bat *bat = BATS[index];
+       unsigned long flags = pgprot_val(prot);
+
+       if ((flags & _PAGE_NO_CACHE) ||
+           (cpu_has_feature(CPU_FTR_NEED_COHERENT) == 0))
+               flags &= ~_PAGE_COHERENT;
+
+       bl = (size >> 17) - 1;
+       if (PVR_VER(mfspr(SPRN_PVR)) != 1) {
+               /* 603, 604, etc. */
+               /* Do DBAT first */
+               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
+                                  | _PAGE_COHERENT | _PAGE_GUARDED);
+               wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
+               bat[1].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
+               bat[1].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
+               if (flags & _PAGE_USER)
+                       bat[1].batu |= 1;       /* Vp = 1 */
+               if (flags & _PAGE_GUARDED) {
+                       /* G bit must be zero in IBATs */
+                       flags &= ~_PAGE_EXEC;
+               }
+               if (flags & _PAGE_EXEC)
+                       bat[0] = bat[1];
+               else
+                       bat[0].batu = bat[0].batl = 0;
+       } else {
+               /* 601 cpu */
+               if (bl > BL_8M)
+                       bl = BL_8M;
+               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
+                                  | _PAGE_COHERENT);
+               wimgxpp |= (flags & _PAGE_RW)?
+                       ((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX;
+               bat->batu = virt | wimgxpp | 4; /* Ks=0, Ku=1 */
+               bat->batl = phys | bl | 0x40;   /* V=1 */
+       }
+
+       bat_addrs[index].start = virt;
+       bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1;
+       bat_addrs[index].phys = phys;
+}
+
+/*
+ * Preload a translation in the hash table
+ */
+void hash_preload(struct mm_struct *mm, unsigned long ea,
+                 bool is_exec, unsigned long trap)
+{
+       pmd_t *pmd;
+
+       if (!Hash)
+               return;
+       pmd = pmd_offset(pud_offset(pgd_offset(mm, ea), ea), ea);
+       if (!pmd_none(*pmd))
+               add_hash_page(mm->context.id, ea, pmd_val(*pmd));
+}
+
+/*
+ * Initialize the hash table and patch the instructions in hashtable.S.
+ */
+void __init MMU_init_hw(void)
+{
+       unsigned int hmask, mb, mb2;
+       unsigned int n_hpteg, lg_n_hpteg;
+
+       if (!mmu_has_feature(MMU_FTR_HPTE_TABLE))
+               return;
+
+       if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
+
+#define LG_HPTEG_SIZE  6               /* 64 bytes per HPTEG */
+#define SDR1_LOW_BITS  ((n_hpteg - 1) >> 10)
+#define MIN_N_HPTEG    1024            /* min 64kB hash table */
+
+       /*
+        * Allow 1 HPTE (1/8 HPTEG) for each page of memory.
+        * This is less than the recommended amount, but then
+        * Linux ain't AIX.
+        */
+       n_hpteg = total_memory / (PAGE_SIZE * 8);
+       if (n_hpteg < MIN_N_HPTEG)
+               n_hpteg = MIN_N_HPTEG;
+       lg_n_hpteg = __ilog2(n_hpteg);
+       if (n_hpteg & (n_hpteg - 1)) {
+               ++lg_n_hpteg;           /* round up if not power of 2 */
+               n_hpteg = 1 << lg_n_hpteg;
+       }
+       Hash_size = n_hpteg << LG_HPTEG_SIZE;
+
+       /*
+        * Find some memory for the hash table.
+        */
+       if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
+       Hash = memblock_alloc(Hash_size, Hash_size);
+       if (!Hash)
+               panic("%s: Failed to allocate %lu bytes align=0x%lx\n",
+                     __func__, Hash_size, Hash_size);
+       _SDR1 = __pa(Hash) | SDR1_LOW_BITS;
+
+       Hash_end = (struct hash_pte *) ((unsigned long)Hash + Hash_size);
+
+       printk("Total memory = %lldMB; using %ldkB for hash table (at %p)\n",
+              (unsigned long long)(total_memory >> 20), Hash_size >> 10, Hash);
+
+
+       /*
+        * Patch up the instructions in hashtable.S:create_hpte
+        */
+       if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
+       Hash_mask = n_hpteg - 1;
+       hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
+       mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
+       if (lg_n_hpteg > 16)
+               mb2 = 16 - LG_HPTEG_SIZE;
+
+       modify_instruction_site(&patch__hash_page_A0, 0xffff,
+                               ((unsigned int)Hash - PAGE_OFFSET) >> 16);
+       modify_instruction_site(&patch__hash_page_A1, 0x7c0, mb << 6);
+       modify_instruction_site(&patch__hash_page_A2, 0x7c0, mb2 << 6);
+       modify_instruction_site(&patch__hash_page_B, 0xffff, hmask);
+       modify_instruction_site(&patch__hash_page_C, 0xffff, hmask);
+
+       /*
+        * Patch up the instructions in hashtable.S:flush_hash_page
+        */
+       modify_instruction_site(&patch__flush_hash_A0, 0xffff,
+                               ((unsigned int)Hash - PAGE_OFFSET) >> 16);
+       modify_instruction_site(&patch__flush_hash_A1, 0x7c0, mb << 6);
+       modify_instruction_site(&patch__flush_hash_A2, 0x7c0, mb2 << 6);
+       modify_instruction_site(&patch__flush_hash_B, 0xffff, hmask);
+
+       if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
+}
+
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+                               phys_addr_t first_memblock_size)
+{
+       /* We don't currently support the first MEMBLOCK not mapping 0
+        * physical on those processors
+        */
+       BUG_ON(first_memblock_base != 0);
+
+       /* 601 can only access 16MB at the moment */
+       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
+               memblock_set_current_limit(min_t(u64, first_memblock_size, 0x01000000));
+       else /* Anything else has 256M mapped */
+               memblock_set_current_limit(min_t(u64, first_memblock_size, 0x10000000));
+}
+
+#ifdef CONFIG_PPC_KUEP
+void __init setup_kuep(bool disabled)
+{
+       pr_info("Activating Kernel Userspace Execution Prevention\n");
+
+       if (cpu_has_feature(CPU_FTR_601))
+               pr_warn("KUEP is not working on powerpc 601 (No NX bit in Seg Regs)\n");
+
+       if (disabled)
+               pr_warn("KUEP cannot be disabled yet on 6xx when compiled in\n");
+}
+#endif
+
+#ifdef CONFIG_PPC_KUAP
+void __init setup_kuap(bool disabled)
+{
+       pr_info("Activating Kernel Userspace Access Protection\n");
+
+       if (disabled)
+               pr_warn("KUAP cannot be disabled yet on 6xx when compiled in\n");
+}
+#endif
diff --git a/arch/powerpc/mm/book3s32/mmu_context.c b/arch/powerpc/mm/book3s32/mmu_context.c
new file mode 100644 (file)
index 0000000..921c1e3
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * This file contains the routines for handling the MMU on those
+ * PowerPC implementations where the MMU substantially follows the
+ * architecture specification.  This includes the 6xx, 7xx, 7xxx,
+ * and 8260 implementations but excludes the 8xx and 4xx.
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/export.h>
+
+#include <asm/mmu_context.h>
+
+/*
+ * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
+ * (virtual segment identifiers) for each context.  Although the
+ * hardware supports 24-bit VSIDs, and thus >1 million contexts,
+ * we only use 32,768 of them.  That is ample, since there can be
+ * at most around 30,000 tasks in the system anyway, and it means
+ * that we can use a bitmap to indicate which contexts are in use.
+ * Using a bitmap means that we entirely avoid all of the problems
+ * that we used to have when the context number overflowed,
+ * particularly on SMP systems.
+ *  -- paulus.
+ */
+#define NO_CONTEXT             ((unsigned long) -1)
+#define LAST_CONTEXT           32767
+#define FIRST_CONTEXT          1
+
+/*
+ * This function defines the mapping from contexts to VSIDs (virtual
+ * segment IDs).  We use a skew on both the context and the high 4 bits
+ * of the 32-bit virtual address (the "effective segment ID") in order
+ * to spread out the entries in the MMU hash table.  Note, if this
+ * function is changed then arch/ppc/mm/hashtable.S will have to be
+ * changed to correspond.
+ *
+ *
+ * CTX_TO_VSID(ctx, va)        (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \
+ *                              & 0xffffff)
+ */
+
+static unsigned long next_mmu_context;
+static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
+
+unsigned long __init_new_context(void)
+{
+       unsigned long ctx = next_mmu_context;
+
+       while (test_and_set_bit(ctx, context_map)) {
+               ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx);
+               if (ctx > LAST_CONTEXT)
+                       ctx = 0;
+       }
+       next_mmu_context = (ctx + 1) & LAST_CONTEXT;
+
+       return ctx;
+}
+EXPORT_SYMBOL_GPL(__init_new_context);
+
+/*
+ * Set up the context for a new address space.
+ */
+int init_new_context(struct task_struct *t, struct mm_struct *mm)
+{
+       mm->context.id = __init_new_context();
+
+       return 0;
+}
+
+/*
+ * Free a context ID. Make sure to call this with preempt disabled!
+ */
+void __destroy_context(unsigned long ctx)
+{
+       clear_bit(ctx, context_map);
+}
+EXPORT_SYMBOL_GPL(__destroy_context);
+
+/*
+ * We're finished using the context for an address space.
+ */
+void destroy_context(struct mm_struct *mm)
+{
+       preempt_disable();
+       if (mm->context.id != NO_CONTEXT) {
+               __destroy_context(mm->context.id);
+               mm->context.id = NO_CONTEXT;
+       }
+       preempt_enable();
+}
+
+/*
+ * Initialize the context management stuff.
+ */
+void __init mmu_context_init(void)
+{
+       /* Reserve context 0 for kernel use */
+       context_map[0] = (1 << FIRST_CONTEXT) - 1;
+       next_mmu_context = FIRST_CONTEXT;
+}
diff --git a/arch/powerpc/mm/book3s32/tlb.c b/arch/powerpc/mm/book3s32/tlb.c
new file mode 100644 (file)
index 0000000..8d56f04
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * This file contains the routines for TLB flushing.
+ * On machines where the MMU uses a hash table to store virtual to
+ * physical translations, these routines flush entries from the
+ * hash table also.
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/export.h>
+
+#include <asm/tlbflush.h>
+#include <asm/tlb.h>
+
+#include <mm/mmu_decl.h>
+
+/*
+ * Called when unmapping pages to flush entries from the TLB/hash table.
+ */
+void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
+{
+       unsigned long ptephys;
+
+       if (Hash) {
+               ptephys = __pa(ptep) & PAGE_MASK;
+               flush_hash_pages(mm->context.id, addr, ptephys, 1);
+       }
+}
+EXPORT_SYMBOL(flush_hash_entry);
+
+/*
+ * Called at the end of a mmu_gather operation to make sure the
+ * TLB flush is completely done.
+ */
+void tlb_flush(struct mmu_gather *tlb)
+{
+       if (!Hash) {
+               /*
+                * 603 needs to flush the whole TLB here since
+                * it doesn't use a hash table.
+                */
+               _tlbia();
+       }
+}
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_kernel_range(start, end) flushes kernel pages
+ *
+ * since the hardware hash table functions as an extension of the
+ * tlb as far as the linux tables are concerned, flush it too.
+ *    -- Cort
+ */
+
+static void flush_range(struct mm_struct *mm, unsigned long start,
+                       unsigned long end)
+{
+       pmd_t *pmd;
+       unsigned long pmd_end;
+       int count;
+       unsigned int ctx = mm->context.id;
+
+       if (!Hash) {
+               _tlbia();
+               return;
+       }
+       start &= PAGE_MASK;
+       if (start >= end)
+               return;
+       end = (end - 1) | ~PAGE_MASK;
+       pmd = pmd_offset(pud_offset(pgd_offset(mm, start), start), start);
+       for (;;) {
+               pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
+               if (pmd_end > end)
+                       pmd_end = end;
+               if (!pmd_none(*pmd)) {
+                       count = ((pmd_end - start) >> PAGE_SHIFT) + 1;
+                       flush_hash_pages(ctx, start, pmd_val(*pmd), count);
+               }
+               if (pmd_end == end)
+                       break;
+               start = pmd_end + 1;
+               ++pmd;
+       }
+}
+
+/*
+ * Flush kernel TLB entries in the given range
+ */
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+       flush_range(&init_mm, start, end);
+}
+EXPORT_SYMBOL(flush_tlb_kernel_range);
+
+/*
+ * Flush all the (user) entries for the address space described by mm.
+ */
+void flush_tlb_mm(struct mm_struct *mm)
+{
+       struct vm_area_struct *mp;
+
+       if (!Hash) {
+               _tlbia();
+               return;
+       }
+
+       /*
+        * It is safe to go down the mm's list of vmas when called
+        * from dup_mmap, holding mmap_sem.  It would also be safe from
+        * unmap_region or exit_mmap, but not from vmtruncate on SMP -
+        * but it seems dup_mmap is the only SMP case which gets here.
+        */
+       for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
+               flush_range(mp->vm_mm, mp->vm_start, mp->vm_end);
+}
+EXPORT_SYMBOL(flush_tlb_mm);
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+       struct mm_struct *mm;
+       pmd_t *pmd;
+
+       if (!Hash) {
+               _tlbie(vmaddr);
+               return;
+       }
+       mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
+       pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr);
+       if (!pmd_none(*pmd))
+               flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
+}
+EXPORT_SYMBOL(flush_tlb_page);
+
+/*
+ * For each address in the range, find the pte for the address
+ * and check _PAGE_HASHPTE bit; if it is set, find and destroy
+ * the corresponding HPTE.
+ */
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+                    unsigned long end)
+{
+       flush_range(vma->vm_mm, start, end);
+}
+EXPORT_SYMBOL(flush_tlb_range);
+
+void __init early_init_mmu(void)
+{
+}
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
deleted file mode 100644 (file)
index e27792d..0000000
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- *  Adapted for Power Macintosh by Paul Mackerras.
- *  Low-level exception handlers and MMU support
- *  rewritten by Paul Mackerras.
- *    Copyright (C) 1996 Paul Mackerras.
- *
- *  This file contains low-level assembler routines for managing
- *  the PowerPC MMU hash table.  (PPC 8xx processors don't use a
- *  hash table, so this file is not used on them.)
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <asm/reg.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/cputable.h>
-#include <asm/ppc_asm.h>
-#include <asm/thread_info.h>
-#include <asm/asm-offsets.h>
-#include <asm/export.h>
-#include <asm/feature-fixups.h>
-#include <asm/code-patching-asm.h>
-
-#ifdef CONFIG_SMP
-       .section .bss
-       .align  2
-mmu_hash_lock:
-       .space  4
-#endif /* CONFIG_SMP */
-
-/*
- * Load a PTE into the hash table, if possible.
- * The address is in r4, and r3 contains an access flag:
- * _PAGE_RW (0x400) if a write.
- * r9 contains the SRR1 value, from which we use the MSR_PR bit.
- * SPRG_THREAD contains the physical address of the current task's thread.
- *
- * Returns to the caller if the access is illegal or there is no
- * mapping for the address.  Otherwise it places an appropriate PTE
- * in the hash table and returns from the exception.
- * Uses r0, r3 - r6, r8, r10, ctr, lr.
- */
-       .text
-_GLOBAL(hash_page)
-#ifdef CONFIG_SMP
-       lis     r8, (mmu_hash_lock - PAGE_OFFSET)@h
-       ori     r8, r8, (mmu_hash_lock - PAGE_OFFSET)@l
-       lis     r0,0x0fff
-       b       10f
-11:    lwz     r6,0(r8)
-       cmpwi   0,r6,0
-       bne     11b
-10:    lwarx   r6,0,r8
-       cmpwi   0,r6,0
-       bne-    11b
-       stwcx.  r0,0,r8
-       bne-    10b
-       isync
-#endif
-       /* Get PTE (linux-style) and check access */
-       lis     r0,KERNELBASE@h         /* check if kernel address */
-       cmplw   0,r4,r0
-       ori     r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
-       mfspr   r5, SPRN_SPRG_PGDIR     /* phys page-table root */
-       blt+    112f                    /* assume user more likely */
-       lis     r5, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
-       addi    r5 ,r5 ,(swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
-       rlwimi  r3,r9,32-12,29,29       /* MSR_PR -> _PAGE_USER */
-112:
-#ifndef CONFIG_PTE_64BIT
-       rlwimi  r5,r4,12,20,29          /* insert top 10 bits of address */
-       lwz     r8,0(r5)                /* get pmd entry */
-       rlwinm. r8,r8,0,0,19            /* extract address of pte page */
-#else
-       rlwinm  r8,r4,13,19,29          /* Compute pgdir/pmd offset */
-       lwzx    r8,r8,r5                /* Get L1 entry */
-       rlwinm. r8,r8,0,0,20            /* extract pt base address */
-#endif
-#ifdef CONFIG_SMP
-       beq-    hash_page_out           /* return if no mapping */
-#else
-       /* XXX it seems like the 601 will give a machine fault on the
-          rfi if its alignment is wrong (bottom 4 bits of address are
-          8 or 0xc) and we have had a not-taken conditional branch
-          to the address following the rfi. */
-       beqlr-
-#endif
-#ifndef CONFIG_PTE_64BIT
-       rlwimi  r8,r4,22,20,29          /* insert next 10 bits of address */
-#else
-       rlwimi  r8,r4,23,20,28          /* compute pte address */
-#endif
-       rlwinm  r0,r3,32-3,24,24        /* _PAGE_RW access -> _PAGE_DIRTY */
-       ori     r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
-
-       /*
-        * Update the linux PTE atomically.  We do the lwarx up-front
-        * because almost always, there won't be a permission violation
-        * and there won't already be an HPTE, and thus we will have
-        * to update the PTE to set _PAGE_HASHPTE.  -- paulus.
-        *
-        * If PTE_64BIT is set, the low word is the flags word; use that
-        * word for locking since it contains all the interesting bits.
-        */
-#if (PTE_FLAGS_OFFSET != 0)
-       addi    r8,r8,PTE_FLAGS_OFFSET
-#endif
-retry:
-       lwarx   r6,0,r8                 /* get linux-style pte, flag word */
-       andc.   r5,r3,r6                /* check access & ~permission */
-#ifdef CONFIG_SMP
-       bne-    hash_page_out           /* return if access not permitted */
-#else
-       bnelr-
-#endif
-       or      r5,r0,r6                /* set accessed/dirty bits */
-#ifdef CONFIG_PTE_64BIT
-#ifdef CONFIG_SMP
-       subf    r10,r6,r8               /* create false data dependency */
-       subi    r10,r10,PTE_FLAGS_OFFSET
-       lwzx    r10,r6,r10              /* Get upper PTE word */
-#else
-       lwz     r10,-PTE_FLAGS_OFFSET(r8)
-#endif /* CONFIG_SMP */
-#endif /* CONFIG_PTE_64BIT */
-       stwcx.  r5,0,r8                 /* attempt to update PTE */
-       bne-    retry                   /* retry if someone got there first */
-
-       mfsrin  r3,r4                   /* get segment reg for segment */
-       mfctr   r0
-       stw     r0,_CTR(r11)
-       bl      create_hpte             /* add the hash table entry */
-
-#ifdef CONFIG_SMP
-       eieio
-       lis     r8, (mmu_hash_lock - PAGE_OFFSET)@ha
-       li      r0,0
-       stw     r0, (mmu_hash_lock - PAGE_OFFSET)@l(r8)
-#endif
-
-       /* Return from the exception */
-       lwz     r5,_CTR(r11)
-       mtctr   r5
-       lwz     r0,GPR0(r11)
-       lwz     r8,GPR8(r11)
-       b       fast_exception_return
-
-#ifdef CONFIG_SMP
-hash_page_out:
-       eieio
-       lis     r8, (mmu_hash_lock - PAGE_OFFSET)@ha
-       li      r0,0
-       stw     r0, (mmu_hash_lock - PAGE_OFFSET)@l(r8)
-       blr
-#endif /* CONFIG_SMP */
-
-/*
- * Add an entry for a particular page to the hash table.
- *
- * add_hash_page(unsigned context, unsigned long va, unsigned long pmdval)
- *
- * We assume any necessary modifications to the pte (e.g. setting
- * the accessed bit) have already been done and that there is actually
- * a hash table in use (i.e. we're not on a 603).
- */
-_GLOBAL(add_hash_page)
-       mflr    r0
-       stw     r0,4(r1)
-
-       /* Convert context and va to VSID */
-       mulli   r3,r3,897*16            /* multiply context by context skew */
-       rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
-       mulli   r0,r0,0x111             /* multiply by ESID skew */
-       add     r3,r3,r0                /* note create_hpte trims to 24 bits */
-
-#ifdef CONFIG_SMP
-       lwz     r8,TASK_CPU(r2)         /* to go in mmu_hash_lock */
-       oris    r8,r8,12
-#endif /* CONFIG_SMP */
-
-       /*
-        * We disable interrupts here, even on UP, because we don't
-        * want to race with hash_page, and because we want the
-        * _PAGE_HASHPTE bit to be a reliable indication of whether
-        * the HPTE exists (or at least whether one did once).
-        * We also turn off the MMU for data accesses so that we
-        * we can't take a hash table miss (assuming the code is
-        * covered by a BAT).  -- paulus
-        */
-       mfmsr   r9
-       SYNC
-       rlwinm  r0,r9,0,17,15           /* clear bit 16 (MSR_EE) */
-       rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
-       mtmsr   r0
-       SYNC_601
-       isync
-
-#ifdef CONFIG_SMP
-       lis     r6, (mmu_hash_lock - PAGE_OFFSET)@ha
-       addi    r6, r6, (mmu_hash_lock - PAGE_OFFSET)@l
-10:    lwarx   r0,0,r6                 /* take the mmu_hash_lock */
-       cmpi    0,r0,0
-       bne-    11f
-       stwcx.  r8,0,r6
-       beq+    12f
-11:    lwz     r0,0(r6)
-       cmpi    0,r0,0
-       beq     10b
-       b       11b
-12:    isync
-#endif
-
-       /*
-        * Fetch the linux pte and test and set _PAGE_HASHPTE atomically.
-        * If _PAGE_HASHPTE was already set, we don't replace the existing
-        * HPTE, so we just unlock and return.
-        */
-       mr      r8,r5
-#ifndef CONFIG_PTE_64BIT
-       rlwimi  r8,r4,22,20,29
-#else
-       rlwimi  r8,r4,23,20,28
-       addi    r8,r8,PTE_FLAGS_OFFSET
-#endif
-1:     lwarx   r6,0,r8
-       andi.   r0,r6,_PAGE_HASHPTE
-       bne     9f                      /* if HASHPTE already set, done */
-#ifdef CONFIG_PTE_64BIT
-#ifdef CONFIG_SMP
-       subf    r10,r6,r8               /* create false data dependency */
-       subi    r10,r10,PTE_FLAGS_OFFSET
-       lwzx    r10,r6,r10              /* Get upper PTE word */
-#else
-       lwz     r10,-PTE_FLAGS_OFFSET(r8)
-#endif /* CONFIG_SMP */
-#endif /* CONFIG_PTE_64BIT */
-       ori     r5,r6,_PAGE_HASHPTE
-       stwcx.  r5,0,r8
-       bne-    1b
-
-       bl      create_hpte
-
-9:
-#ifdef CONFIG_SMP
-       lis     r6, (mmu_hash_lock - PAGE_OFFSET)@ha
-       addi    r6, r6, (mmu_hash_lock - PAGE_OFFSET)@l
-       eieio
-       li      r0,0
-       stw     r0,0(r6)                /* clear mmu_hash_lock */
-#endif
-
-       /* reenable interrupts and DR */
-       mtmsr   r9
-       SYNC_601
-       isync
-
-       lwz     r0,4(r1)
-       mtlr    r0
-       blr
-
-/*
- * This routine adds a hardware PTE to the hash table.
- * It is designed to be called with the MMU either on or off.
- * r3 contains the VSID, r4 contains the virtual address,
- * r5 contains the linux PTE, r6 contains the old value of the
- * linux PTE (before setting _PAGE_HASHPTE). r10 contains the
- * upper half of the PTE if CONFIG_PTE_64BIT.
- * On SMP, the caller should have the mmu_hash_lock held.
- * We assume that the caller has (or will) set the _PAGE_HASHPTE
- * bit in the linux PTE in memory.  The value passed in r6 should
- * be the old linux PTE value; if it doesn't have _PAGE_HASHPTE set
- * this routine will skip the search for an existing HPTE.
- * This procedure modifies r0, r3 - r6, r8, cr0.
- *  -- paulus.
- *
- * For speed, 4 of the instructions get patched once the size and
- * physical address of the hash table are known.  These definitions
- * of Hash_base and Hash_bits below are just an example.
- */
-Hash_base = 0xc0180000
-Hash_bits = 12                         /* e.g. 256kB hash table */
-Hash_msk = (((1 << Hash_bits) - 1) * 64)
-
-/* defines for the PTE format for 32-bit PPCs */
-#define HPTE_SIZE      8
-#define PTEG_SIZE      64
-#define LG_PTEG_SIZE   6
-#define LDPTEu         lwzu
-#define LDPTE          lwz
-#define STPTE          stw
-#define CMPPTE         cmpw
-#define PTE_H          0x40
-#define PTE_V          0x80000000
-#define TST_V(r)       rlwinm. r,r,0,0,0
-#define SET_V(r)       oris r,r,PTE_V@h
-#define CLR_V(r,t)     rlwinm r,r,0,1,31
-
-#define HASH_LEFT      31-(LG_PTEG_SIZE+Hash_bits-1)
-#define HASH_RIGHT     31-LG_PTEG_SIZE
-
-_GLOBAL(create_hpte)
-       /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */
-       rlwinm  r8,r5,32-9,30,30        /* _PAGE_RW -> PP msb */
-       rlwinm  r0,r5,32-6,30,30        /* _PAGE_DIRTY -> PP msb */
-       and     r8,r8,r0                /* writable if _RW & _DIRTY */
-       rlwimi  r5,r5,32-1,30,30        /* _PAGE_USER -> PP msb */
-       rlwimi  r5,r5,32-2,31,31        /* _PAGE_USER -> PP lsb */
-       ori     r8,r8,0xe04             /* clear out reserved bits */
-       andc    r8,r5,r8                /* PP = user? (rw&dirty? 1: 3): 0 */
-BEGIN_FTR_SECTION
-       rlwinm  r8,r8,0,~_PAGE_COHERENT /* clear M (coherence not required) */
-END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
-#ifdef CONFIG_PTE_64BIT
-       /* Put the XPN bits into the PTE */
-       rlwimi  r8,r10,8,20,22
-       rlwimi  r8,r10,2,29,29
-#endif
-
-       /* Construct the high word of the PPC-style PTE (r5) */
-       rlwinm  r5,r3,7,1,24            /* put VSID in 0x7fffff80 bits */
-       rlwimi  r5,r4,10,26,31          /* put in API (abbrev page index) */
-       SET_V(r5)                       /* set V (valid) bit */
-
-       patch_site      0f, patch__hash_page_A0
-       patch_site      1f, patch__hash_page_A1
-       patch_site      2f, patch__hash_page_A2
-       /* Get the address of the primary PTE group in the hash table (r3) */
-0:     lis     r0, (Hash_base - PAGE_OFFSET)@h /* base address of hash table */
-1:     rlwimi  r0,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
-2:     rlwinm  r3,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
-       xor     r3,r3,r0                /* make primary hash */
-       li      r0,8                    /* PTEs/group */
-
-       /*
-        * Test the _PAGE_HASHPTE bit in the old linux PTE, and skip the search
-        * if it is clear, meaning that the HPTE isn't there already...
-        */
-       andi.   r6,r6,_PAGE_HASHPTE
-       beq+    10f                     /* no PTE: go look for an empty slot */
-       tlbie   r4
-
-       lis     r4, (htab_hash_searches - PAGE_OFFSET)@ha
-       lwz     r6, (htab_hash_searches - PAGE_OFFSET)@l(r4)
-       addi    r6,r6,1                 /* count how many searches we do */
-       stw     r6, (htab_hash_searches - PAGE_OFFSET)@l(r4)
-
-       /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
-       mtctr   r0
-       addi    r4,r3,-HPTE_SIZE
-1:     LDPTEu  r6,HPTE_SIZE(r4)        /* get next PTE */
-       CMPPTE  0,r6,r5
-       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
-       beq+    found_slot
-
-       patch_site      0f, patch__hash_page_B
-       /* Search the secondary PTEG for a matching PTE */
-       ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
-0:     xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
-       xori    r4,r4,(-PTEG_SIZE & 0xffff)
-       addi    r4,r4,-HPTE_SIZE
-       mtctr   r0
-2:     LDPTEu  r6,HPTE_SIZE(r4)
-       CMPPTE  0,r6,r5
-       bdnzf   2,2b
-       beq+    found_slot
-       xori    r5,r5,PTE_H             /* clear H bit again */
-
-       /* Search the primary PTEG for an empty slot */
-10:    mtctr   r0
-       addi    r4,r3,-HPTE_SIZE        /* search primary PTEG */
-1:     LDPTEu  r6,HPTE_SIZE(r4)        /* get next PTE */
-       TST_V(r6)                       /* test valid bit */
-       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
-       beq+    found_empty
-
-       /* update counter of times that the primary PTEG is full */
-       lis     r4, (primary_pteg_full - PAGE_OFFSET)@ha
-       lwz     r6, (primary_pteg_full - PAGE_OFFSET)@l(r4)
-       addi    r6,r6,1
-       stw     r6, (primary_pteg_full - PAGE_OFFSET)@l(r4)
-
-       patch_site      0f, patch__hash_page_C
-       /* Search the secondary PTEG for an empty slot */
-       ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
-0:     xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
-       xori    r4,r4,(-PTEG_SIZE & 0xffff)
-       addi    r4,r4,-HPTE_SIZE
-       mtctr   r0
-2:     LDPTEu  r6,HPTE_SIZE(r4)
-       TST_V(r6)
-       bdnzf   2,2b
-       beq+    found_empty
-       xori    r5,r5,PTE_H             /* clear H bit again */
-
-       /*
-        * Choose an arbitrary slot in the primary PTEG to overwrite.
-        * Since both the primary and secondary PTEGs are full, and we
-        * have no information that the PTEs in the primary PTEG are
-        * more important or useful than those in the secondary PTEG,
-        * and we know there is a definite (although small) speed
-        * advantage to putting the PTE in the primary PTEG, we always
-        * put the PTE in the primary PTEG.
-        *
-        * In addition, we skip any slot that is mapping kernel text in
-        * order to avoid a deadlock when not using BAT mappings if
-        * trying to hash in the kernel hash code itself after it has
-        * already taken the hash table lock. This works in conjunction
-        * with pre-faulting of the kernel text.
-        *
-        * If the hash table bucket is full of kernel text entries, we'll
-        * lockup here but that shouldn't happen
-        */
-
-1:     lis     r4, (next_slot - PAGE_OFFSET)@ha        /* get next evict slot */
-       lwz     r6, (next_slot - PAGE_OFFSET)@l(r4)
-       addi    r6,r6,HPTE_SIZE                 /* search for candidate */
-       andi.   r6,r6,7*HPTE_SIZE
-       stw     r6,next_slot@l(r4)
-       add     r4,r3,r6
-       LDPTE   r0,HPTE_SIZE/2(r4)              /* get PTE second word */
-       clrrwi  r0,r0,12
-       lis     r6,etext@h
-       ori     r6,r6,etext@l                   /* get etext */
-       tophys(r6,r6)
-       cmpl    cr0,r0,r6                       /* compare and try again */
-       blt     1b
-
-#ifndef CONFIG_SMP
-       /* Store PTE in PTEG */
-found_empty:
-       STPTE   r5,0(r4)
-found_slot:
-       STPTE   r8,HPTE_SIZE/2(r4)
-
-#else /* CONFIG_SMP */
-/*
- * Between the tlbie above and updating the hash table entry below,
- * another CPU could read the hash table entry and put it in its TLB.
- * There are 3 cases:
- * 1. using an empty slot
- * 2. updating an earlier entry to change permissions (i.e. enable write)
- * 3. taking over the PTE for an unrelated address
- *
- * In each case it doesn't really matter if the other CPUs have the old
- * PTE in their TLB.  So we don't need to bother with another tlbie here,
- * which is convenient as we've overwritten the register that had the
- * address. :-)  The tlbie above is mainly to make sure that this CPU comes
- * and gets the new PTE from the hash table.
- *
- * We do however have to make sure that the PTE is never in an invalid
- * state with the V bit set.
- */
-found_empty:
-found_slot:
-       CLR_V(r5,r0)            /* clear V (valid) bit in PTE */
-       STPTE   r5,0(r4)
-       sync
-       TLBSYNC
-       STPTE   r8,HPTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */
-       sync
-       SET_V(r5)
-       STPTE   r5,0(r4)        /* finally set V bit in PTE */
-#endif /* CONFIG_SMP */
-
-       sync            /* make sure pte updates get to memory */
-       blr
-
-       .section .bss
-       .align  2
-next_slot:
-       .space  4
-primary_pteg_full:
-       .space  4
-htab_hash_searches:
-       .space  4
-       .previous
-
-/*
- * Flush the entry for a particular page from the hash table.
- *
- * flush_hash_pages(unsigned context, unsigned long va, unsigned long pmdval,
- *                 int count)
- *
- * We assume that there is a hash table in use (Hash != 0).
- */
-_GLOBAL(flush_hash_pages)
-       /*
-        * We disable interrupts here, even on UP, because we want
-        * the _PAGE_HASHPTE bit to be a reliable indication of
-        * whether the HPTE exists (or at least whether one did once).
-        * We also turn off the MMU for data accesses so that we
-        * we can't take a hash table miss (assuming the code is
-        * covered by a BAT).  -- paulus
-        */
-       mfmsr   r10
-       SYNC
-       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
-       rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
-       mtmsr   r0
-       SYNC_601
-       isync
-
-       /* First find a PTE in the range that has _PAGE_HASHPTE set */
-#ifndef CONFIG_PTE_64BIT
-       rlwimi  r5,r4,22,20,29
-#else
-       rlwimi  r5,r4,23,20,28
-#endif
-1:     lwz     r0,PTE_FLAGS_OFFSET(r5)
-       cmpwi   cr1,r6,1
-       andi.   r0,r0,_PAGE_HASHPTE
-       bne     2f
-       ble     cr1,19f
-       addi    r4,r4,0x1000
-       addi    r5,r5,PTE_SIZE
-       addi    r6,r6,-1
-       b       1b
-
-       /* Convert context and va to VSID */
-2:     mulli   r3,r3,897*16            /* multiply context by context skew */
-       rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
-       mulli   r0,r0,0x111             /* multiply by ESID skew */
-       add     r3,r3,r0                /* note code below trims to 24 bits */
-
-       /* Construct the high word of the PPC-style PTE (r11) */
-       rlwinm  r11,r3,7,1,24           /* put VSID in 0x7fffff80 bits */
-       rlwimi  r11,r4,10,26,31         /* put in API (abbrev page index) */
-       SET_V(r11)                      /* set V (valid) bit */
-
-#ifdef CONFIG_SMP
-       lis     r9, (mmu_hash_lock - PAGE_OFFSET)@ha
-       addi    r9, r9, (mmu_hash_lock - PAGE_OFFSET)@l
-       lwz     r8,TASK_CPU(r2)
-       oris    r8,r8,9
-10:    lwarx   r0,0,r9
-       cmpi    0,r0,0
-       bne-    11f
-       stwcx.  r8,0,r9
-       beq+    12f
-11:    lwz     r0,0(r9)
-       cmpi    0,r0,0
-       beq     10b
-       b       11b
-12:    isync
-#endif
-
-       /*
-        * Check the _PAGE_HASHPTE bit in the linux PTE.  If it is
-        * already clear, we're done (for this pte).  If not,
-        * clear it (atomically) and proceed.  -- paulus.
-        */
-#if (PTE_FLAGS_OFFSET != 0)
-       addi    r5,r5,PTE_FLAGS_OFFSET
-#endif
-33:    lwarx   r8,0,r5                 /* fetch the pte flags word */
-       andi.   r0,r8,_PAGE_HASHPTE
-       beq     8f                      /* done if HASHPTE is already clear */
-       rlwinm  r8,r8,0,31,29           /* clear HASHPTE bit */
-       stwcx.  r8,0,r5                 /* update the pte */
-       bne-    33b
-
-       patch_site      0f, patch__flush_hash_A0
-       patch_site      1f, patch__flush_hash_A1
-       patch_site      2f, patch__flush_hash_A2
-       /* Get the address of the primary PTE group in the hash table (r3) */
-0:     lis     r8, (Hash_base - PAGE_OFFSET)@h /* base address of hash table */
-1:     rlwimi  r8,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
-2:     rlwinm  r0,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
-       xor     r8,r0,r8                /* make primary hash */
-
-       /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
-       li      r0,8                    /* PTEs/group */
-       mtctr   r0
-       addi    r12,r8,-HPTE_SIZE
-1:     LDPTEu  r0,HPTE_SIZE(r12)       /* get next PTE */
-       CMPPTE  0,r0,r11
-       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
-       beq+    3f
-
-       patch_site      0f, patch__flush_hash_B
-       /* Search the secondary PTEG for a matching PTE */
-       ori     r11,r11,PTE_H           /* set H (secondary hash) bit */
-       li      r0,8                    /* PTEs/group */
-0:     xoris   r12,r8,Hash_msk>>16     /* compute secondary hash */
-       xori    r12,r12,(-PTEG_SIZE & 0xffff)
-       addi    r12,r12,-HPTE_SIZE
-       mtctr   r0
-2:     LDPTEu  r0,HPTE_SIZE(r12)
-       CMPPTE  0,r0,r11
-       bdnzf   2,2b
-       xori    r11,r11,PTE_H           /* clear H again */
-       bne-    4f                      /* should rarely fail to find it */
-
-3:     li      r0,0
-       STPTE   r0,0(r12)               /* invalidate entry */
-4:     sync
-       tlbie   r4                      /* in hw tlb too */
-       sync
-
-8:     ble     cr1,9f                  /* if all ptes checked */
-81:    addi    r6,r6,-1
-       addi    r5,r5,PTE_SIZE
-       addi    r4,r4,0x1000
-       lwz     r0,0(r5)                /* check next pte */
-       cmpwi   cr1,r6,1
-       andi.   r0,r0,_PAGE_HASHPTE
-       bne     33b
-       bgt     cr1,81b
-
-9:
-#ifdef CONFIG_SMP
-       TLBSYNC
-       li      r0,0
-       stw     r0,0(r9)                /* clear mmu_hash_lock */
-#endif
-
-19:    mtmsr   r10
-       SYNC_601
-       isync
-       blr
-EXPORT_SYMBOL(flush_hash_pages)
-
-/*
- * Flush an entry from the TLB
- */
-_GLOBAL(_tlbie)
-#ifdef CONFIG_SMP
-       lwz     r8,TASK_CPU(r2)
-       oris    r8,r8,11
-       mfmsr   r10
-       SYNC
-       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
-       rlwinm  r0,r0,0,28,26           /* clear DR */
-       mtmsr   r0
-       SYNC_601
-       isync
-       lis     r9,mmu_hash_lock@h
-       ori     r9,r9,mmu_hash_lock@l
-       tophys(r9,r9)
-10:    lwarx   r7,0,r9
-       cmpwi   0,r7,0
-       bne-    10b
-       stwcx.  r8,0,r9
-       bne-    10b
-       eieio
-       tlbie   r3
-       sync
-       TLBSYNC
-       li      r0,0
-       stw     r0,0(r9)                /* clear mmu_hash_lock */
-       mtmsr   r10
-       SYNC_601
-       isync
-#else /* CONFIG_SMP */
-       tlbie   r3
-       sync
-#endif /* CONFIG_SMP */
-       blr
-
-/*
- * Flush the entire TLB. 603/603e only
- */
-_GLOBAL(_tlbia)
-#if defined(CONFIG_SMP)
-       lwz     r8,TASK_CPU(r2)
-       oris    r8,r8,10
-       mfmsr   r10
-       SYNC
-       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
-       rlwinm  r0,r0,0,28,26           /* clear DR */
-       mtmsr   r0
-       SYNC_601
-       isync
-       lis     r9,mmu_hash_lock@h
-       ori     r9,r9,mmu_hash_lock@l
-       tophys(r9,r9)
-10:    lwarx   r7,0,r9
-       cmpwi   0,r7,0
-       bne-    10b
-       stwcx.  r8,0,r9
-       bne-    10b
-       sync
-       tlbia
-       sync
-       TLBSYNC
-       li      r0,0
-       stw     r0,0(r9)                /* clear mmu_hash_lock */
-       mtmsr   r10
-       SYNC_601
-       isync
-#else /* CONFIG_SMP */
-       sync
-       tlbia
-       sync
-#endif /* CONFIG_SMP */
-       blr
diff --git a/arch/powerpc/mm/mmu_context_hash32.c b/arch/powerpc/mm/mmu_context_hash32.c
deleted file mode 100644 (file)
index 921c1e3..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * This file contains the routines for handling the MMU on those
- * PowerPC implementations where the MMU substantially follows the
- * architecture specification.  This includes the 6xx, 7xx, 7xxx,
- * and 8260 implementations but excludes the 8xx and 4xx.
- *  -- paulus
- *
- *  Derived from arch/ppc/mm/init.c:
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/export.h>
-
-#include <asm/mmu_context.h>
-
-/*
- * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
- * (virtual segment identifiers) for each context.  Although the
- * hardware supports 24-bit VSIDs, and thus >1 million contexts,
- * we only use 32,768 of them.  That is ample, since there can be
- * at most around 30,000 tasks in the system anyway, and it means
- * that we can use a bitmap to indicate which contexts are in use.
- * Using a bitmap means that we entirely avoid all of the problems
- * that we used to have when the context number overflowed,
- * particularly on SMP systems.
- *  -- paulus.
- */
-#define NO_CONTEXT             ((unsigned long) -1)
-#define LAST_CONTEXT           32767
-#define FIRST_CONTEXT          1
-
-/*
- * This function defines the mapping from contexts to VSIDs (virtual
- * segment IDs).  We use a skew on both the context and the high 4 bits
- * of the 32-bit virtual address (the "effective segment ID") in order
- * to spread out the entries in the MMU hash table.  Note, if this
- * function is changed then arch/ppc/mm/hashtable.S will have to be
- * changed to correspond.
- *
- *
- * CTX_TO_VSID(ctx, va)        (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \
- *                              & 0xffffff)
- */
-
-static unsigned long next_mmu_context;
-static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
-
-unsigned long __init_new_context(void)
-{
-       unsigned long ctx = next_mmu_context;
-
-       while (test_and_set_bit(ctx, context_map)) {
-               ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx);
-               if (ctx > LAST_CONTEXT)
-                       ctx = 0;
-       }
-       next_mmu_context = (ctx + 1) & LAST_CONTEXT;
-
-       return ctx;
-}
-EXPORT_SYMBOL_GPL(__init_new_context);
-
-/*
- * Set up the context for a new address space.
- */
-int init_new_context(struct task_struct *t, struct mm_struct *mm)
-{
-       mm->context.id = __init_new_context();
-
-       return 0;
-}
-
-/*
- * Free a context ID. Make sure to call this with preempt disabled!
- */
-void __destroy_context(unsigned long ctx)
-{
-       clear_bit(ctx, context_map);
-}
-EXPORT_SYMBOL_GPL(__destroy_context);
-
-/*
- * We're finished using the context for an address space.
- */
-void destroy_context(struct mm_struct *mm)
-{
-       preempt_disable();
-       if (mm->context.id != NO_CONTEXT) {
-               __destroy_context(mm->context.id);
-               mm->context.id = NO_CONTEXT;
-       }
-       preempt_enable();
-}
-
-/*
- * Initialize the context management stuff.
- */
-void __init mmu_context_init(void)
-{
-       /* Reserve context 0 for kernel use */
-       context_map[0] = (1 << FIRST_CONTEXT) - 1;
-       next_mmu_context = FIRST_CONTEXT;
-}
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
deleted file mode 100644 (file)
index 1db5515..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * This file contains the routines for handling the MMU on those
- * PowerPC implementations where the MMU substantially follows the
- * architecture specification.  This includes the 6xx, 7xx, 7xxx,
- * and 8260 implementations but excludes the 8xx and 4xx.
- *  -- paulus
- *
- *  Derived from arch/ppc/mm/init.c:
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/highmem.h>
-#include <linux/memblock.h>
-
-#include <asm/prom.h>
-#include <asm/mmu.h>
-#include <asm/machdep.h>
-#include <asm/code-patching.h>
-#include <asm/sections.h>
-
-#include <mm/mmu_decl.h>
-
-struct hash_pte *Hash, *Hash_end;
-unsigned long Hash_size, Hash_mask;
-unsigned long _SDR1;
-
-struct ppc_bat BATS[8][2];     /* 8 pairs of IBAT, DBAT */
-
-struct batrange {              /* stores address ranges mapped by BATs */
-       unsigned long start;
-       unsigned long limit;
-       phys_addr_t phys;
-} bat_addrs[8];
-
-/*
- * Return PA for this VA if it is mapped by a BAT, or 0
- */
-phys_addr_t v_block_mapped(unsigned long va)
-{
-       int b;
-       for (b = 0; b < ARRAY_SIZE(bat_addrs); ++b)
-               if (va >= bat_addrs[b].start && va < bat_addrs[b].limit)
-                       return bat_addrs[b].phys + (va - bat_addrs[b].start);
-       return 0;
-}
-
-/*
- * Return VA for a given PA or 0 if not mapped
- */
-unsigned long p_block_mapped(phys_addr_t pa)
-{
-       int b;
-       for (b = 0; b < ARRAY_SIZE(bat_addrs); ++b)
-               if (pa >= bat_addrs[b].phys
-                   && pa < (bat_addrs[b].limit-bat_addrs[b].start)
-                             +bat_addrs[b].phys)
-                       return bat_addrs[b].start+(pa-bat_addrs[b].phys);
-       return 0;
-}
-
-static int find_free_bat(void)
-{
-       int b;
-
-       if (cpu_has_feature(CPU_FTR_601)) {
-               for (b = 0; b < 4; b++) {
-                       struct ppc_bat *bat = BATS[b];
-
-                       if (!(bat[0].batl & 0x40))
-                               return b;
-               }
-       } else {
-               int n = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
-
-               for (b = 0; b < n; b++) {
-                       struct ppc_bat *bat = BATS[b];
-
-                       if (!(bat[1].batu & 3))
-                               return b;
-               }
-       }
-       return -1;
-}
-
-static unsigned int block_size(unsigned long base, unsigned long top)
-{
-       unsigned int max_size = (cpu_has_feature(CPU_FTR_601) ? 8 : 256) << 20;
-       unsigned int base_shift = (fls(base) - 1) & 31;
-       unsigned int block_shift = (fls(top - base) - 1) & 31;
-
-       return min3(max_size, 1U << base_shift, 1U << block_shift);
-}
-
-/*
- * Set up one of the IBAT (block address translation) register pairs.
- * The parameters are not checked; in particular size must be a power
- * of 2 between 128k and 256M.
- * Only for 603+ ...
- */
-static void setibat(int index, unsigned long virt, phys_addr_t phys,
-                   unsigned int size, pgprot_t prot)
-{
-       unsigned int bl = (size >> 17) - 1;
-       int wimgxpp;
-       struct ppc_bat *bat = BATS[index];
-       unsigned long flags = pgprot_val(prot);
-
-       if (!cpu_has_feature(CPU_FTR_NEED_COHERENT))
-               flags &= ~_PAGE_COHERENT;
-
-       wimgxpp = (flags & _PAGE_COHERENT) | (_PAGE_EXEC ? BPP_RX : BPP_XX);
-       bat[0].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
-       bat[0].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
-       if (flags & _PAGE_USER)
-               bat[0].batu |= 1;       /* Vp = 1 */
-}
-
-static void clearibat(int index)
-{
-       struct ppc_bat *bat = BATS[index];
-
-       bat[0].batu = 0;
-       bat[0].batl = 0;
-}
-
-static unsigned long __init __mmu_mapin_ram(unsigned long base, unsigned long top)
-{
-       int idx;
-
-       while ((idx = find_free_bat()) != -1 && base != top) {
-               unsigned int size = block_size(base, top);
-
-               if (size < 128 << 10)
-                       break;
-               setbat(idx, PAGE_OFFSET + base, base, size, PAGE_KERNEL_X);
-               base += size;
-       }
-
-       return base;
-}
-
-unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
-{
-       int done;
-       unsigned long border = (unsigned long)__init_begin - PAGE_OFFSET;
-
-       if (__map_without_bats) {
-               pr_debug("RAM mapped without BATs\n");
-               return base;
-       }
-
-       if (!strict_kernel_rwx_enabled() || base >= border || top <= border)
-               return __mmu_mapin_ram(base, top);
-
-       done = __mmu_mapin_ram(base, border);
-       if (done != border - base)
-               return done;
-
-       return done + __mmu_mapin_ram(border, top);
-}
-
-void mmu_mark_initmem_nx(void)
-{
-       int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
-       int i;
-       unsigned long base = (unsigned long)_stext - PAGE_OFFSET;
-       unsigned long top = (unsigned long)_etext - PAGE_OFFSET;
-       unsigned long size;
-
-       if (cpu_has_feature(CPU_FTR_601))
-               return;
-
-       for (i = 0; i < nb - 1 && base < top && top - base > (128 << 10);) {
-               size = block_size(base, top);
-               setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
-               base += size;
-       }
-       if (base < top) {
-               size = block_size(base, top);
-               size = max(size, 128UL << 10);
-               if ((top - base) > size) {
-                       if (strict_kernel_rwx_enabled())
-                               pr_warn("Kernel _etext not properly aligned\n");
-                       size <<= 1;
-               }
-               setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
-               base += size;
-       }
-       for (; i < nb; i++)
-               clearibat(i);
-
-       update_bats();
-
-       for (i = TASK_SIZE >> 28; i < 16; i++) {
-               /* Do not set NX on VM space for modules */
-               if (IS_ENABLED(CONFIG_MODULES) &&
-                   (VMALLOC_START & 0xf0000000) == i << 28)
-                       break;
-               mtsrin(mfsrin(i << 28) | 0x10000000, i << 28);
-       }
-}
-
-void mmu_mark_rodata_ro(void)
-{
-       int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
-       int i;
-
-       if (cpu_has_feature(CPU_FTR_601))
-               return;
-
-       for (i = 0; i < nb; i++) {
-               struct ppc_bat *bat = BATS[i];
-
-               if (bat_addrs[i].start < (unsigned long)__init_begin)
-                       bat[1].batl = (bat[1].batl & ~BPP_RW) | BPP_RX;
-       }
-
-       update_bats();
-}
-
-/*
- * Set up one of the I/D BAT (block address translation) register pairs.
- * The parameters are not checked; in particular size must be a power
- * of 2 between 128k and 256M.
- * On 603+, only set IBAT when _PAGE_EXEC is set
- */
-void __init setbat(int index, unsigned long virt, phys_addr_t phys,
-                  unsigned int size, pgprot_t prot)
-{
-       unsigned int bl;
-       int wimgxpp;
-       struct ppc_bat *bat = BATS[index];
-       unsigned long flags = pgprot_val(prot);
-
-       if ((flags & _PAGE_NO_CACHE) ||
-           (cpu_has_feature(CPU_FTR_NEED_COHERENT) == 0))
-               flags &= ~_PAGE_COHERENT;
-
-       bl = (size >> 17) - 1;
-       if (PVR_VER(mfspr(SPRN_PVR)) != 1) {
-               /* 603, 604, etc. */
-               /* Do DBAT first */
-               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
-                                  | _PAGE_COHERENT | _PAGE_GUARDED);
-               wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
-               bat[1].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
-               bat[1].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
-               if (flags & _PAGE_USER)
-                       bat[1].batu |= 1;       /* Vp = 1 */
-               if (flags & _PAGE_GUARDED) {
-                       /* G bit must be zero in IBATs */
-                       flags &= ~_PAGE_EXEC;
-               }
-               if (flags & _PAGE_EXEC)
-                       bat[0] = bat[1];
-               else
-                       bat[0].batu = bat[0].batl = 0;
-       } else {
-               /* 601 cpu */
-               if (bl > BL_8M)
-                       bl = BL_8M;
-               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
-                                  | _PAGE_COHERENT);
-               wimgxpp |= (flags & _PAGE_RW)?
-                       ((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX;
-               bat->batu = virt | wimgxpp | 4; /* Ks=0, Ku=1 */
-               bat->batl = phys | bl | 0x40;   /* V=1 */
-       }
-
-       bat_addrs[index].start = virt;
-       bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1;
-       bat_addrs[index].phys = phys;
-}
-
-/*
- * Preload a translation in the hash table
- */
-void hash_preload(struct mm_struct *mm, unsigned long ea,
-                 bool is_exec, unsigned long trap)
-{
-       pmd_t *pmd;
-
-       if (!Hash)
-               return;
-       pmd = pmd_offset(pud_offset(pgd_offset(mm, ea), ea), ea);
-       if (!pmd_none(*pmd))
-               add_hash_page(mm->context.id, ea, pmd_val(*pmd));
-}
-
-/*
- * Initialize the hash table and patch the instructions in hashtable.S.
- */
-void __init MMU_init_hw(void)
-{
-       unsigned int hmask, mb, mb2;
-       unsigned int n_hpteg, lg_n_hpteg;
-
-       if (!mmu_has_feature(MMU_FTR_HPTE_TABLE))
-               return;
-
-       if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
-
-#define LG_HPTEG_SIZE  6               /* 64 bytes per HPTEG */
-#define SDR1_LOW_BITS  ((n_hpteg - 1) >> 10)
-#define MIN_N_HPTEG    1024            /* min 64kB hash table */
-
-       /*
-        * Allow 1 HPTE (1/8 HPTEG) for each page of memory.
-        * This is less than the recommended amount, but then
-        * Linux ain't AIX.
-        */
-       n_hpteg = total_memory / (PAGE_SIZE * 8);
-       if (n_hpteg < MIN_N_HPTEG)
-               n_hpteg = MIN_N_HPTEG;
-       lg_n_hpteg = __ilog2(n_hpteg);
-       if (n_hpteg & (n_hpteg - 1)) {
-               ++lg_n_hpteg;           /* round up if not power of 2 */
-               n_hpteg = 1 << lg_n_hpteg;
-       }
-       Hash_size = n_hpteg << LG_HPTEG_SIZE;
-
-       /*
-        * Find some memory for the hash table.
-        */
-       if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
-       Hash = memblock_alloc(Hash_size, Hash_size);
-       if (!Hash)
-               panic("%s: Failed to allocate %lu bytes align=0x%lx\n",
-                     __func__, Hash_size, Hash_size);
-       _SDR1 = __pa(Hash) | SDR1_LOW_BITS;
-
-       Hash_end = (struct hash_pte *) ((unsigned long)Hash + Hash_size);
-
-       printk("Total memory = %lldMB; using %ldkB for hash table (at %p)\n",
-              (unsigned long long)(total_memory >> 20), Hash_size >> 10, Hash);
-
-
-       /*
-        * Patch up the instructions in hashtable.S:create_hpte
-        */
-       if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
-       Hash_mask = n_hpteg - 1;
-       hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
-       mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
-       if (lg_n_hpteg > 16)
-               mb2 = 16 - LG_HPTEG_SIZE;
-
-       modify_instruction_site(&patch__hash_page_A0, 0xffff,
-                               ((unsigned int)Hash - PAGE_OFFSET) >> 16);
-       modify_instruction_site(&patch__hash_page_A1, 0x7c0, mb << 6);
-       modify_instruction_site(&patch__hash_page_A2, 0x7c0, mb2 << 6);
-       modify_instruction_site(&patch__hash_page_B, 0xffff, hmask);
-       modify_instruction_site(&patch__hash_page_C, 0xffff, hmask);
-
-       /*
-        * Patch up the instructions in hashtable.S:flush_hash_page
-        */
-       modify_instruction_site(&patch__flush_hash_A0, 0xffff,
-                               ((unsigned int)Hash - PAGE_OFFSET) >> 16);
-       modify_instruction_site(&patch__flush_hash_A1, 0x7c0, mb << 6);
-       modify_instruction_site(&patch__flush_hash_A2, 0x7c0, mb2 << 6);
-       modify_instruction_site(&patch__flush_hash_B, 0xffff, hmask);
-
-       if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
-}
-
-void setup_initial_memory_limit(phys_addr_t first_memblock_base,
-                               phys_addr_t first_memblock_size)
-{
-       /* We don't currently support the first MEMBLOCK not mapping 0
-        * physical on those processors
-        */
-       BUG_ON(first_memblock_base != 0);
-
-       /* 601 can only access 16MB at the moment */
-       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
-               memblock_set_current_limit(min_t(u64, first_memblock_size, 0x01000000));
-       else /* Anything else has 256M mapped */
-               memblock_set_current_limit(min_t(u64, first_memblock_size, 0x10000000));
-}
-
-#ifdef CONFIG_PPC_KUEP
-void __init setup_kuep(bool disabled)
-{
-       pr_info("Activating Kernel Userspace Execution Prevention\n");
-
-       if (cpu_has_feature(CPU_FTR_601))
-               pr_warn("KUEP is not working on powerpc 601 (No NX bit in Seg Regs)\n");
-
-       if (disabled)
-               pr_warn("KUEP cannot be disabled yet on 6xx when compiled in\n");
-}
-#endif
-
-#ifdef CONFIG_PPC_KUAP
-void __init setup_kuap(bool disabled)
-{
-       pr_info("Activating Kernel Userspace Access Protection\n");
-
-       if (disabled)
-               pr_warn("KUAP cannot be disabled yet on 6xx when compiled in\n");
-}
-#endif
diff --git a/arch/powerpc/mm/tlb_hash32.c b/arch/powerpc/mm/tlb_hash32.c
deleted file mode 100644 (file)
index 8d56f04..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * This file contains the routines for TLB flushing.
- * On machines where the MMU uses a hash table to store virtual to
- * physical translations, these routines flush entries from the
- * hash table also.
- *  -- paulus
- *
- *  Derived from arch/ppc/mm/init.c:
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <linux/export.h>
-
-#include <asm/tlbflush.h>
-#include <asm/tlb.h>
-
-#include <mm/mmu_decl.h>
-
-/*
- * Called when unmapping pages to flush entries from the TLB/hash table.
- */
-void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
-{
-       unsigned long ptephys;
-
-       if (Hash) {
-               ptephys = __pa(ptep) & PAGE_MASK;
-               flush_hash_pages(mm->context.id, addr, ptephys, 1);
-       }
-}
-EXPORT_SYMBOL(flush_hash_entry);
-
-/*
- * Called at the end of a mmu_gather operation to make sure the
- * TLB flush is completely done.
- */
-void tlb_flush(struct mmu_gather *tlb)
-{
-       if (!Hash) {
-               /*
-                * 603 needs to flush the whole TLB here since
-                * it doesn't use a hash table.
-                */
-               _tlbia();
-       }
-}
-
-/*
- * TLB flushing:
- *
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(vma, start, end) flushes a range of pages
- *  - flush_tlb_kernel_range(start, end) flushes kernel pages
- *
- * since the hardware hash table functions as an extension of the
- * tlb as far as the linux tables are concerned, flush it too.
- *    -- Cort
- */
-
-static void flush_range(struct mm_struct *mm, unsigned long start,
-                       unsigned long end)
-{
-       pmd_t *pmd;
-       unsigned long pmd_end;
-       int count;
-       unsigned int ctx = mm->context.id;
-
-       if (!Hash) {
-               _tlbia();
-               return;
-       }
-       start &= PAGE_MASK;
-       if (start >= end)
-               return;
-       end = (end - 1) | ~PAGE_MASK;
-       pmd = pmd_offset(pud_offset(pgd_offset(mm, start), start), start);
-       for (;;) {
-               pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
-               if (pmd_end > end)
-                       pmd_end = end;
-               if (!pmd_none(*pmd)) {
-                       count = ((pmd_end - start) >> PAGE_SHIFT) + 1;
-                       flush_hash_pages(ctx, start, pmd_val(*pmd), count);
-               }
-               if (pmd_end == end)
-                       break;
-               start = pmd_end + 1;
-               ++pmd;
-       }
-}
-
-/*
- * Flush kernel TLB entries in the given range
- */
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
-       flush_range(&init_mm, start, end);
-}
-EXPORT_SYMBOL(flush_tlb_kernel_range);
-
-/*
- * Flush all the (user) entries for the address space described by mm.
- */
-void flush_tlb_mm(struct mm_struct *mm)
-{
-       struct vm_area_struct *mp;
-
-       if (!Hash) {
-               _tlbia();
-               return;
-       }
-
-       /*
-        * It is safe to go down the mm's list of vmas when called
-        * from dup_mmap, holding mmap_sem.  It would also be safe from
-        * unmap_region or exit_mmap, but not from vmtruncate on SMP -
-        * but it seems dup_mmap is the only SMP case which gets here.
-        */
-       for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
-               flush_range(mp->vm_mm, mp->vm_start, mp->vm_end);
-}
-EXPORT_SYMBOL(flush_tlb_mm);
-
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
-       struct mm_struct *mm;
-       pmd_t *pmd;
-
-       if (!Hash) {
-               _tlbie(vmaddr);
-               return;
-       }
-       mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
-       pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr);
-       if (!pmd_none(*pmd))
-               flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
-}
-EXPORT_SYMBOL(flush_tlb_page);
-
-/*
- * For each address in the range, find the pte for the address
- * and check _PAGE_HASHPTE bit; if it is set, find and destroy
- * the corresponding HPTE.
- */
-void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-                    unsigned long end)
-{
-       flush_range(vma->vm_mm, start, end);
-}
-EXPORT_SYMBOL(flush_tlb_range);
-
-void __init early_init_mmu(void)
-{
-}