]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - include/asm-ppc64/mmu.h
powerpc: fix iSeries build
[karo-tx-linux.git] / include / asm-ppc64 / mmu.h
index 70348a85131396773e8b1a115325246211f53e7d..1a7e0afa2dc6175a79d62f0db40101eb99ba8f0c 100644 (file)
@@ -14,6 +14,7 @@
 #define _PPC64_MMU_H_
 
 #include <linux/config.h>
+#include <asm/asm-compat.h>
 #include <asm/page.h>
 
 /*
 #define STE_VSID_SHIFT 12
 
 /* Location of cpu0's segment table */
-#define STAB0_PAGE     0x9
-#define STAB0_PHYS_ADDR        (STAB0_PAGE<<PAGE_SHIFT)
-#define STAB0_VIRT_ADDR        (KERNELBASE+STAB0_PHYS_ADDR)
+#define STAB0_PAGE     0x6
+#define STAB0_PHYS_ADDR        (STAB0_PAGE<<12)
+
+#ifndef __ASSEMBLY__
+extern char initial_stab[];
+#endif /* ! __ASSEMBLY */
 
 /*
  * SLB
 
 /* Bits in the SLB VSID word */
 #define SLB_VSID_SHIFT         12
+#define SLB_VSID_B             ASM_CONST(0xc000000000000000)
+#define SLB_VSID_B_256M                ASM_CONST(0x0000000000000000)
+#define SLB_VSID_B_1T          ASM_CONST(0x4000000000000000)
 #define SLB_VSID_KS            ASM_CONST(0x0000000000000800)
 #define SLB_VSID_KP            ASM_CONST(0x0000000000000400)
 #define SLB_VSID_N             ASM_CONST(0x0000000000000200) /* no-execute */
-#define SLB_VSID_L             ASM_CONST(0x0000000000000100) /* largepage */
+#define SLB_VSID_L             ASM_CONST(0x0000000000000100)
 #define SLB_VSID_C             ASM_CONST(0x0000000000000080) /* class */
-#define SLB_VSID_LS            ASM_CONST(0x0000000000000070) /* size of largepage */
-#define SLB_VSID_KERNEL                (SLB_VSID_KP|SLB_VSID_C)
-#define SLB_VSID_USER          (SLB_VSID_KP|SLB_VSID_KS)
+#define SLB_VSID_LP            ASM_CONST(0x0000000000000030)
+#define SLB_VSID_LP_00         ASM_CONST(0x0000000000000000)
+#define SLB_VSID_LP_01         ASM_CONST(0x0000000000000010)
+#define SLB_VSID_LP_10         ASM_CONST(0x0000000000000020)
+#define SLB_VSID_LP_11         ASM_CONST(0x0000000000000030)
+#define SLB_VSID_LLP           (SLB_VSID_L|SLB_VSID_LP)
+
+#define SLB_VSID_KERNEL                (SLB_VSID_KP)
+#define SLB_VSID_USER          (SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C)
+
+#define SLBIE_C                        (0x08000000)
 
 /*
  * Hash table
@@ -63,6 +77,7 @@
 #define HPTE_V_AVPN_SHIFT      7
 #define HPTE_V_AVPN            ASM_CONST(0xffffffffffffff80)
 #define HPTE_V_AVPN_VAL(x)     (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
+#define HPTE_V_COMPARE(x,y)    (!(((x) ^ (y)) & HPTE_V_AVPN))
 #define HPTE_V_BOLTED          ASM_CONST(0x0000000000000010)
 #define HPTE_V_LOCK            ASM_CONST(0x0000000000000008)
 #define HPTE_V_LARGE           ASM_CONST(0x0000000000000004)
@@ -75,6 +90,7 @@
 #define HPTE_R_RPN             ASM_CONST(0x3ffffffffffff000)
 #define HPTE_R_FLAGS           ASM_CONST(0x00000000000003ff)
 #define HPTE_R_PP              ASM_CONST(0x0000000000000003)
+#define HPTE_R_N               ASM_CONST(0x0000000000000004)
 
 /* Values for PP (assumes Ks=0, Kp=1) */
 /* pp0 will always be 0 for linux     */
@@ -93,114 +109,146 @@ typedef struct {
 extern hpte_t *htab_address;
 extern unsigned long htab_hash_mask;
 
-static inline unsigned long hpt_hash(unsigned long vpn, int large)
+/*
+ * Page size definition
+ *
+ *    shift : is the "PAGE_SHIFT" value for that page size
+ *    sllp  : is a bit mask with the value of SLB L || LP to be or'ed
+ *            directly to a slbmte "vsid" value
+ *    penc  : is the HPTE encoding mask for the "LP" field:
+ *
+ */
+struct mmu_psize_def
 {
-       unsigned long vsid;
-       unsigned long page;
-
-       if (large) {
-               vsid = vpn >> 4;
-               page = vpn & 0xf;
-       } else {
-               vsid = vpn >> 16;
-               page = vpn & 0xffff;
-       }
-
-       return (vsid & 0x7fffffffffUL) ^ page;
-}
+       unsigned int    shift;  /* number of bits */
+       unsigned int    penc;   /* HPTE encoding */
+       unsigned int    tlbiel; /* tlbiel supported for that page size */
+       unsigned long   avpnm;  /* bits to mask out in AVPN in the HPTE */
+       unsigned long   sllp;   /* SLB L||LP (exact mask to use in slbmte) */
+};
 
-static inline void __tlbie(unsigned long va, int large)
-{
-       /* clear top 16 bits, non SLS segment */
-       va &= ~(0xffffULL << 48);
-
-       if (large) {
-               va &= HPAGE_MASK;
-               asm volatile("tlbie %0,1" : : "r"(va) : "memory");
-       } else {
-               va &= PAGE_MASK;
-               asm volatile("tlbie %0,0" : : "r"(va) : "memory");
-       }
-}
+#endif /* __ASSEMBLY__ */
 
-static inline void tlbie(unsigned long va, int large)
-{
-       asm volatile("ptesync": : :"memory");
-       __tlbie(va, large);
-       asm volatile("eieio; tlbsync; ptesync": : :"memory");
-}
+/*
+ * The kernel use the constants below to index in the page sizes array.
+ * The use of fixed constants for this purpose is better for performances
+ * of the low level hash refill handlers.
+ *
+ * A non supported page size has a "shift" field set to 0
+ *
+ * Any new page size being implemented can get a new entry in here. Whether
+ * the kernel will use it or not is a different matter though. The actual page
+ * size used by hugetlbfs is not defined here and may be made variable
+ */
 
-static inline void __tlbiel(unsigned long va)
-{
-       /* clear top 16 bits, non SLS segment */
-       va &= ~(0xffffULL << 48);
-       va &= PAGE_MASK;
-
-       /* 
-        * Thanks to Alan Modra we are now able to use machine specific 
-        * assembly instructions (like tlbiel) by using the gas -many flag.
-        * However we have to support older toolchains so for the moment 
-        * we hardwire it.
-        */
-#if 0
-       asm volatile("tlbiel %0" : : "r"(va) : "memory");
-#else
-       asm volatile(".long 0x7c000224 | (%0 << 11)" : : "r"(va) : "memory");
-#endif
-}
+#define MMU_PAGE_4K            0       /* 4K */
+#define MMU_PAGE_64K           1       /* 64K */
+#define MMU_PAGE_64K_AP                2       /* 64K Admixed (in a 4K segment) */
+#define MMU_PAGE_1M            3       /* 1M */
+#define MMU_PAGE_16M           4       /* 16M */
+#define MMU_PAGE_16G           5       /* 16G */
+#define MMU_PAGE_COUNT         6
 
-static inline void tlbiel(unsigned long va)
-{
-       asm volatile("ptesync": : :"memory");
-       __tlbiel(va);
-       asm volatile("ptesync": : :"memory");
-}
+#ifndef __ASSEMBLY__
 
-static inline unsigned long slot2va(unsigned long hpte_v, unsigned long slot)
-{
-       unsigned long avpn = HPTE_V_AVPN_VAL(hpte_v);
-       unsigned long va;
+/*
+ * The current system page sizes
+ */
+extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
+extern int mmu_linear_psize;
+extern int mmu_virtual_psize;
 
-       va = avpn << 23;
+#ifdef CONFIG_HUGETLB_PAGE
+/*
+ * The page size index of the huge pages for use by hugetlbfs
+ */
+extern int mmu_huge_psize;
 
-       if (! (hpte_v & HPTE_V_LARGE)) {
-               unsigned long vpi, pteg;
+#endif /* CONFIG_HUGETLB_PAGE */
 
-               pteg = slot / HPTES_PER_GROUP;
-               if (hpte_v & HPTE_V_SECONDARY)
-                       pteg = ~pteg;
+/*
+ * This function sets the AVPN and L fields of the HPTE  appropriately
+ * for the page size
+ */
+static inline unsigned long hpte_encode_v(unsigned long va, int psize)
+{
+       unsigned long v =
+       v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm);
+       v <<= HPTE_V_AVPN_SHIFT;
+       if (psize != MMU_PAGE_4K)
+               v |= HPTE_V_LARGE;
+       return v;
+}
 
-               vpi = ((va >> 28) ^ pteg) & htab_hash_mask;
+/*
+ * This function sets the ARPN, and LP fields of the HPTE appropriately
+ * for the page size. We assume the pa is already "clean" that is properly
+ * aligned for the requested page size
+ */
+static inline unsigned long hpte_encode_r(unsigned long pa, int psize)
+{
+       unsigned long r;
 
-               va |= vpi << PAGE_SHIFT;
+       /* A 4K page needs no special encoding */
+       if (psize == MMU_PAGE_4K)
+               return pa & HPTE_R_RPN;
+       else {
+               unsigned int penc = mmu_psize_defs[psize].penc;
+               unsigned int shift = mmu_psize_defs[psize].shift;
+               return (pa & ~((1ul << shift) - 1)) | (penc << 12);
        }
-
-       return va;
+       return r;
 }
 
 /*
- * Handle a fault by adding an HPTE. If the address can't be determined
- * to be valid via Linux page tables, return 1. If handled return 0
+ * This hashes a virtual address for a 256Mb segment only for now
  */
-extern int __hash_page(unsigned long ea, unsigned long access,
-                      unsigned long vsid, pte_t *ptep, unsigned long trap,
-                      int local);
+
+static inline unsigned long hpt_hash(unsigned long va, unsigned int shift)
+{
+       return ((va >> 28) & 0x7fffffffffUL) ^ ((va & 0x0fffffffUL) >> shift);
+}
+
+extern int __hash_page_4K(unsigned long ea, unsigned long access,
+                         unsigned long vsid, pte_t *ptep, unsigned long trap,
+                         unsigned int local);
+extern int __hash_page_64K(unsigned long ea, unsigned long access,
+                          unsigned long vsid, pte_t *ptep, unsigned long trap,
+                          unsigned int local);
+struct mm_struct;
+extern int hash_huge_page(struct mm_struct *mm, unsigned long access,
+                         unsigned long ea, unsigned long vsid, int local);
 
 extern void htab_finish_init(void);
+extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
+                            unsigned long pstart, unsigned long mode,
+                            int psize);
 
+extern void htab_initialize(void);
+extern void htab_initialize_secondary(void);
 extern void hpte_init_native(void);
 extern void hpte_init_lpar(void);
 extern void hpte_init_iSeries(void);
+extern void mm_init_ppc64(void);
 
 extern long pSeries_lpar_hpte_insert(unsigned long hpte_group,
                                     unsigned long va, unsigned long prpn,
-                                    unsigned long vflags,
-                                    unsigned long rflags);
-extern long native_hpte_insert(unsigned long hpte_group, unsigned long va,
-                              unsigned long prpn,
-                              unsigned long vflags, unsigned long rflags);
+                                    unsigned long rflags,
+                                    unsigned long vflags, int psize);
+
+extern long native_hpte_insert(unsigned long hpte_group,
+                              unsigned long va, unsigned long prpn,
+                              unsigned long rflags,
+                              unsigned long vflags, int psize);
+
+extern long iSeries_hpte_insert(unsigned long hpte_group,
+                               unsigned long va, unsigned long prpn,
+                               unsigned long rflags,
+                               unsigned long vflags, int psize);
 
 extern void stabs_alloc(void);
+extern void slb_initialize(void);
+extern void stab_initialize(unsigned long stab);
 
 #endif /* __ASSEMBLY__ */
 
@@ -259,8 +307,10 @@ extern void stabs_alloc(void);
 #define VSID_BITS      36
 #define VSID_MODULUS   ((1UL<<VSID_BITS)-1)
 
-#define CONTEXT_BITS   20
-#define USER_ESID_BITS 15
+#define CONTEXT_BITS   19
+#define USER_ESID_BITS 16
+
+#define USER_VSID_RANGE        (1UL << (USER_ESID_BITS + SID_SHIFT))
 
 /*
  * This macro generates asm code to compute the VSID scramble
@@ -302,8 +352,7 @@ typedef unsigned long mm_context_id_t;
 typedef struct {
        mm_context_id_t id;
 #ifdef CONFIG_HUGETLB_PAGE
-       pgd_t *huge_pgdir;
-       u16 htlb_segs; /* bitmask */
+       u16 low_htlb_areas, high_htlb_areas;
 #endif
 } mm_context_t;