vserver 1.9.5.x5
[linux-2.6.git] / include / asm-ppc64 / pgtable.h
index 6ca8b0c..0f6990a 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _PPC64_PGTABLE_H
 #define _PPC64_PGTABLE_H
 
+#include <asm-generic/4level-fixup.h>
+
 /*
  * This file contains the functions and defines necessary to modify and use
  * the ppc64 hashed page table.
 #define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
                     PGD_INDEX_SIZE + PAGE_SHIFT) 
 
+/*
+ * Size of EA range mapped by our pagetables.
+ */
+#define PGTABLE_EA_BITS        41
+#define PGTABLE_EA_MASK        ((1UL<<PGTABLE_EA_BITS)-1)
+
 /*
  * Define the address range of the vmalloc VM area.
  */
-#define VMALLOC_START (0xD000000000000000)
-#define VMALLOC_END   (VMALLOC_START + VALID_EA_BITS)
+#define VMALLOC_START (0xD000000000000000ul)
+#define VMALLOC_END   (VMALLOC_START + PGTABLE_EA_MASK)
 
 /*
  * Define the address range of the imalloc VM area.
  */
 #define IMALLOC_START     (ioremap_bot)
 #define IMALLOC_VMADDR(x) ((unsigned long)(x))
-#define PHBS_IO_BASE     (0xE000000000000000)  /* Reserve 2 gigs for PHBs */
-#define IMALLOC_BASE      (0xE000000080000000)  
-#define IMALLOC_END       (IMALLOC_BASE + VALID_EA_BITS)
-
-/*
- * Define the address range mapped virt <-> physical
- */
-#define KRANGE_START KERNELBASE
-#define KRANGE_END   (KRANGE_START + VALID_EA_BITS)
+#define PHBS_IO_BASE     (0xE000000000000000ul)        /* Reserve 2 gigs for PHBs */
+#define IMALLOC_BASE      (0xE000000080000000ul)  
+#define IMALLOC_END       (IMALLOC_BASE + PGTABLE_EA_MASK)
 
 /*
  * Define the user address range
  */
 #define USER_START (0UL)
-#define USER_END   (USER_START + VALID_EA_BITS)
+#define USER_END   (USER_START + PGTABLE_EA_MASK)
 
 
 /*
@@ -92,6 +94,7 @@
 #define _PAGE_BUSY     0x0800 /* software: PTE & hash are busy */ 
 #define _PAGE_SECONDARY 0x8000 /* software: HPTE is in secondary group */
 #define _PAGE_GROUP_IX  0x7000 /* software: HPTE index within group */
+#define _PAGE_HUGE     0x10000 /* 16MB page */
 /* Bits 0x7000 identify the index within an HPT Group */
 #define _PAGE_HPTEFLAGS (_PAGE_BUSY | _PAGE_HASHPTE | _PAGE_SECONDARY | _PAGE_GROUP_IX)
 /* PAGE_MASK gives the right answer below, but only by accident */
@@ -151,26 +154,27 @@ extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
 #endif /* __ASSEMBLY__ */
 
 /* shift to put page number into pte */
-#define PTE_SHIFT (16)
+#define PTE_SHIFT (17)
 
 /* We allow 2^41 bytes of real memory, so we need 29 bits in the PMD
  * to give the PTE page number.  The bottom two bits are for flags. */
 #define PMD_TO_PTEPAGE_SHIFT (2)
 
 #ifdef CONFIG_HUGETLB_PAGE
-#define _PMD_HUGEPAGE  0x00000001U
-#define HUGEPTE_BATCH_SIZE (1<<(HPAGE_SHIFT-PMD_SHIFT))
 
 #ifndef __ASSEMBLY__
 int hash_huge_page(struct mm_struct *mm, unsigned long access,
                   unsigned long ea, unsigned long vsid, int local);
+
+void hugetlb_mm_free_pgd(struct mm_struct *mm);
 #endif /* __ASSEMBLY__ */
 
 #define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
 #else
 
 #define hash_huge_page(mm,a,ea,vsid,local)     -1
-#define _PMD_HUGEPAGE  0
+#define hugetlb_mm_free_pgd(mm)                        do {} while (0)
 
 #endif
 
@@ -206,10 +210,8 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access,
 #define pmd_set(pmdp, ptep)    \
        (pmd_val(*(pmdp)) = (__ba_to_bpn(ptep) << PMD_TO_PTEPAGE_SHIFT))
 #define pmd_none(pmd)          (!pmd_val(pmd))
-#define        pmd_hugepage(pmd)       (!!(pmd_val(pmd) & _PMD_HUGEPAGE))
-#define        pmd_bad(pmd)            (((pmd_val(pmd)) == 0) || pmd_hugepage(pmd))
-#define        pmd_present(pmd)        ((!pmd_hugepage(pmd)) \
-                                && (pmd_val(pmd) & ~_PMD_HUGEPAGE) != 0)
+#define        pmd_bad(pmd)            (pmd_val(pmd) == 0)
+#define        pmd_present(pmd)        (pmd_val(pmd) != 0)
 #define        pmd_clear(pmdp)         (pmd_val(*(pmdp)) = 0)
 #define pmd_page_kernel(pmd)   \
        (__bpn_to_ba(pmd_val(pmd) >> PMD_TO_PTEPAGE_SHIFT))
@@ -262,6 +264,7 @@ static inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC;}
 static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
 static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
 static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
+static inline int pte_huge(pte_t pte) { return pte_val(pte) & _PAGE_HUGE;}
 
 static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
 static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -287,6 +290,8 @@ static inline pte_t pte_mkdirty(pte_t pte) {
        pte_val(pte) |= _PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkyoung(pte_t pte) {
        pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkhuge(pte_t pte) {
+       pte_val(pte) |= _PAGE_HUGE; return pte; }
 
 /* Atomic PTE updates */
 static inline unsigned long pte_update(pte_t *p, unsigned long clr)
@@ -306,7 +311,10 @@ static inline unsigned long pte_update(pte_t *p, unsigned long clr)
        return old;
 }
 
-/* PTE updating functions */
+/* PTE updating functions, this function puts the PTE in the
+ * batch, doesn't actually triggers the hash flush immediately,
+ * you need to call flush_tlb_pending() to do that.
+ */
 extern void hpte_update(pte_t *ptep, unsigned long pte, int wrprot);
 
 static inline int ptep_test_and_clear_young(pte_t *ptep)
@@ -318,7 +326,7 @@ static inline int ptep_test_and_clear_young(pte_t *ptep)
        old = pte_update(ptep, _PAGE_ACCESSED);
        if (old & _PAGE_HASHPTE) {
                hpte_update(ptep, old, 0);
-               flush_tlb_pending();    /* XXX generic code doesn't flush */
+               flush_tlb_pending();
        }
        return (old & _PAGE_ACCESSED) != 0;
 }
@@ -396,11 +404,40 @@ static inline void pte_clear(pte_t * ptep)
  */
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
-       if (pte_present(*ptep))
+       if (pte_present(*ptep)) {
                pte_clear(ptep);
+               flush_tlb_pending();
+       }
        *ptep = __pte(pte_val(pte)) & ~_PAGE_HPTEFLAGS;
 }
 
+/* Set the dirty and/or accessed bits atomically in a linux PTE, this
+ * function doesn't need to flush the hash entry
+ */
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
+{
+       unsigned long bits = pte_val(entry) &
+               (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW);
+       unsigned long old, tmp;
+
+       __asm__ __volatile__(
+       "1:     ldarx   %0,0,%4\n\
+               andi.   %1,%0,%6\n\
+               bne-    1b \n\
+               or      %0,%3,%0\n\
+               stdcx.  %0,0,%4\n\
+               bne-    1b"
+       :"=&r" (old), "=&r" (tmp), "=m" (*ptep)
+       :"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
+       :"cc");
+}
+#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+       do {                                                               \
+               __ptep_set_access_flags(__ptep, __entry, __dirty);         \
+               flush_tlb_page_nohash(__vma, __address);                   \
+       } while(0)
+
 /*
  * Macro to mark a page protection value as "uncacheable".
  */
@@ -425,6 +462,10 @@ extern pgd_t ioremap_dir[1024];
 
 extern void paging_init(void);
 
+struct mmu_gather;
+void hugetlb_free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *prev,
+                          unsigned long start, unsigned long end);
+
 /*
  * This gets called at the end of handling a page fault, when
  * the kernel has put a new PTE into the page table for the process.
@@ -453,11 +494,13 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
  */
 #define kern_addr_valid(addr)  (1)
 
-#define io_remap_page_range remap_page_range 
+#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
+               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
 void pgtable_cache_init(void);
 
-extern void hpte_init_pSeries(void);
+extern void hpte_init_native(void);
+extern void hpte_init_lpar(void);
 extern void hpte_init_iSeries(void);
 
 /* imalloc region types */
@@ -465,22 +508,21 @@ extern void hpte_init_iSeries(void);
 #define IM_REGION_SUBSET       0x2
 #define IM_REGION_EXISTS       0x4
 #define IM_REGION_OVERLAP      0x8
+#define IM_REGION_SUPERSET     0x10
 
 extern struct vm_struct * im_get_free_area(unsigned long size);
 extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
                        int region_type);
 unsigned long im_free(void *addr);
 
-typedef pte_t *pte_addr_t;
-
-long pSeries_lpar_hpte_insert(unsigned long hpte_group,
-                             unsigned long va, unsigned long prpn,
-                             int secondary, unsigned long hpteflags,
-                             int bolted, int large);
+extern long pSeries_lpar_hpte_insert(unsigned long hpte_group,
+                                    unsigned long va, unsigned long prpn,
+                                    int secondary, unsigned long hpteflags,
+                                    int bolted, int large);
 
-long pSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
-                        unsigned long prpn, int secondary,
-                        unsigned long hpteflags, int bolted, int large);
+extern long native_hpte_insert(unsigned long hpte_group, unsigned long va,
+                              unsigned long prpn, int secondary,
+                              unsigned long hpteflags, int bolted, int large);
 
 /*
  * find_linux_pte returns the address of a linux pte for a given