mm: remove ptep_test_and_clear_dirty and ptep_clear_flush_dirty
[powerpc.git] / include / asm-i386 / pgtable.h
index c3b58d4..c7fefa6 100644 (file)
@@ -35,17 +35,16 @@ struct vm_area_struct;
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 extern unsigned long empty_zero_page[1024];
 extern pgd_t swapper_pg_dir[1024];
-extern struct kmem_cache *pgd_cache;
 extern struct kmem_cache *pmd_cache;
 extern spinlock_t pgd_lock;
 extern struct page *pgd_list;
+void check_pgt_cache(void);
 
 void pmd_ctor(void *, struct kmem_cache *, unsigned long);
-void pgd_ctor(void *, struct kmem_cache *, unsigned long);
-void pgd_dtor(void *, struct kmem_cache *, unsigned long);
 void pgtable_cache_init(void);
 void paging_init(void);
 
+
 /*
  * The Linux x86 paging architecture is 'compile-time dual-mode', it
  * implements both the traditional 2-level x86 page tables and the
@@ -80,7 +79,7 @@ void paging_init(void);
  * area for the same reason. ;)
  */
 #define VMALLOC_OFFSET (8*1024*1024)
-#define VMALLOC_START  (((unsigned long) high_memory + vmalloc_earlyreserve + \
+#define VMALLOC_START  (((unsigned long) high_memory + \
                        2*VMALLOC_OFFSET-1) & ~(VMALLOC_OFFSET-1))
 #ifdef CONFIG_HIGHMEM
 # define VMALLOC_END   (PKMAP_BASE-2*PAGE_SIZE)
@@ -159,6 +158,7 @@ void paging_init(void);
 
 extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
 #define __PAGE_KERNEL_RO               (__PAGE_KERNEL & ~_PAGE_RW)
+#define __PAGE_KERNEL_RX               (__PAGE_KERNEL_EXEC & ~_PAGE_RW)
 #define __PAGE_KERNEL_NOCACHE          (__PAGE_KERNEL | _PAGE_PCD)
 #define __PAGE_KERNEL_LARGE            (__PAGE_KERNEL | _PAGE_PSE)
 #define __PAGE_KERNEL_LARGE_EXEC       (__PAGE_KERNEL_EXEC | _PAGE_PSE)
@@ -166,6 +166,7 @@ extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
 #define PAGE_KERNEL            __pgprot(__PAGE_KERNEL)
 #define PAGE_KERNEL_RO         __pgprot(__PAGE_KERNEL_RO)
 #define PAGE_KERNEL_EXEC       __pgprot(__PAGE_KERNEL_EXEC)
+#define PAGE_KERNEL_RX         __pgprot(__PAGE_KERNEL_RX)
 #define PAGE_KERNEL_NOCACHE    __pgprot(__PAGE_KERNEL_NOCACHE)
 #define PAGE_KERNEL_LARGE      __pgprot(__PAGE_KERNEL_LARGE)
 #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC)
@@ -217,8 +218,6 @@ extern unsigned long pg0[];
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-static inline int pte_user(pte_t pte)          { return (pte).pte_low & _PAGE_USER; }
-static inline int pte_read(pte_t pte)          { return (pte).pte_low & _PAGE_USER; }
 static inline int pte_dirty(pte_t pte)         { return (pte).pte_low & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)         { return (pte).pte_low & _PAGE_ACCESSED; }
 static inline int pte_write(pte_t pte)         { return (pte).pte_low & _PAGE_RW; }
@@ -229,13 +228,9 @@ static inline int pte_huge(pte_t pte)              { return (pte).pte_low & _PAGE_PSE; }
  */
 static inline int pte_file(pte_t pte)          { return (pte).pte_low & _PAGE_FILE; }
 
-static inline pte_t pte_rdprotect(pte_t pte)   { (pte).pte_low &= ~_PAGE_USER; return pte; }
-static inline pte_t pte_exprotect(pte_t pte)   { (pte).pte_low &= ~_PAGE_USER; return pte; }
 static inline pte_t pte_mkclean(pte_t pte)     { (pte).pte_low &= ~_PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkold(pte_t pte)       { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; }
 static inline pte_t pte_wrprotect(pte_t pte)   { (pte).pte_low &= ~_PAGE_RW; return pte; }
-static inline pte_t pte_mkread(pte_t pte)      { (pte).pte_low |= _PAGE_USER; return pte; }
-static inline pte_t pte_mkexec(pte_t pte)      { (pte).pte_low |= _PAGE_USER; return pte; }
 static inline pte_t pte_mkdirty(pte_t pte)     { (pte).pte_low |= _PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)     { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)     { (pte).pte_low |= _PAGE_RW; return pte; }
@@ -263,9 +258,18 @@ static inline pte_t pte_mkhuge(pte_t pte)  { (pte).pte_low |= _PAGE_PSE; return p
  */
 #define pte_update(mm, addr, ptep)             do { } while (0)
 #define pte_update_defer(mm, addr, ptep)       do { } while (0)
-#define paravirt_map_pt_hook(slot, va, pfn)    do { } while (0)
 #endif
 
+/* local pte updates need not use xchg for locking */
+static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
+{
+       pte_t res = *ptep;
+
+       /* Pure native function needs no input for mm, addr */
+       native_pte_clear(NULL, 0, ptep);
+       return res;
+}
+
 /*
  * We only update the dirty/accessed state if we set
  * the dirty bit by hand in the kernel, since the hardware
@@ -275,62 +279,41 @@ static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return p
  */
 #define  __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 #define ptep_set_access_flags(vma, address, ptep, entry, dirty)                \
-do {                                                                   \
-       if (dirty) {                                                    \
+({                                                                     \
+       int __changed = !pte_same(*(ptep), entry);                      \
+       if (__changed && dirty) {                                       \
                (ptep)->pte_low = (entry).pte_low;                      \
                pte_update_defer((vma)->vm_mm, (address), (ptep));      \
                flush_tlb_page(vma, address);                           \
        }                                                               \
-} while (0)
+       __changed;                                                      \
+})
 
-/*
- * We don't actually have these, but we want to advertise them so that
- * we can encompass the flush here.
- */
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-
-/*
- * Rules for using ptep_establish: the pte MUST be a user pte, and
- * must be a present->present transition.
- */
-#define __HAVE_ARCH_PTEP_ESTABLISH
-#define ptep_establish(vma, address, ptep, pteval)                     \
-do {                                                                   \
-       set_pte_present((vma)->vm_mm, address, ptep, pteval);           \
-       flush_tlb_page(vma, address);                                   \
-} while (0)
-
-#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
-#define ptep_clear_flush_dirty(vma, address, ptep)                     \
-({                                                                     \
-       int __dirty;                                                    \
-       __dirty = pte_dirty(*(ptep));                                   \
-       if (__dirty) {                                                  \
-               clear_bit(_PAGE_BIT_DIRTY, &(ptep)->pte_low);           \
-               pte_update_defer((vma)->vm_mm, (address), (ptep));      \
-               flush_tlb_page(vma, address);                           \
-       }                                                               \
-       __dirty;                                                        \
+#define ptep_test_and_clear_young(vma, addr, ptep) ({                  \
+       int __ret = 0;                                                  \
+       if (pte_young(*(ptep)))                                         \
+               __ret = test_and_clear_bit(_PAGE_BIT_ACCESSED,          \
+                                               &(ptep)->pte_low);      \
+       if (__ret)                                                      \
+               pte_update((vma)->vm_mm, addr, ptep);                   \
+       __ret;                                                          \
 })
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
 #define ptep_clear_flush_young(vma, address, ptep)                     \
 ({                                                                     \
        int __young;                                                    \
-       __young = pte_young(*(ptep));                                   \
-       if (__young) {                                                  \
-               clear_bit(_PAGE_BIT_ACCESSED, &(ptep)->pte_low);        \
-               pte_update_defer((vma)->vm_mm, (address), (ptep));      \
+       __young = ptep_test_and_clear_young((vma), (address), (ptep));  \
+       if (__young)                                                    \
                flush_tlb_page(vma, address);                           \
-       }                                                               \
        __young;                                                        \
 })
 
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-       pte_t pte = raw_ptep_get_and_clear(ptep);
+       pte_t pte = native_ptep_get_and_clear(ptep);
        pte_update(mm, addr, ptep);
        return pte;
 }
@@ -340,8 +323,11 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
 {
        pte_t pte;
        if (full) {
-               pte = *ptep;
-               pte_clear(mm, addr, ptep);
+               /*
+                * Full address destruction in progress; paravirt does not
+                * care about updates and native needs no locking
+                */
+               pte = native_local_ptep_get_and_clear(ptep);
        } else {
                pte = ptep_get_and_clear(mm, addr, ptep);
        }
@@ -470,24 +456,10 @@ extern pte_t *lookup_address(unsigned long address);
 #endif
 
 #if defined(CONFIG_HIGHPTE)
-#define pte_offset_map(dir, address)                           \
-({                                                             \
-       pte_t *__ptep;                                          \
-       unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT;           \
-       __ptep = (pte_t *)kmap_atomic(pfn_to_page(pfn),KM_PTE0);\
-       paravirt_map_pt_hook(KM_PTE0,__ptep, pfn);              \
-       __ptep = __ptep + pte_index(address);                   \
-       __ptep;                                                 \
-})
-#define pte_offset_map_nested(dir, address)                    \
-({                                                             \
-       pte_t *__ptep;                                          \
-       unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT;           \
-       __ptep = (pte_t *)kmap_atomic(pfn_to_page(pfn),KM_PTE1);\
-       paravirt_map_pt_hook(KM_PTE1,__ptep, pfn);              \
-       __ptep = __ptep + pte_index(address);                   \
-       __ptep;                                                 \
-})
+#define pte_offset_map(dir, address) \
+       ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
+#define pte_offset_map_nested(dir, address) \
+       ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + pte_index(address))
 #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
 #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
 #else
@@ -510,6 +482,22 @@ do {                                                                       \
  * tables contain all the necessary information.
  */
 #define update_mmu_cache(vma,address,pte) do { } while (0)
+
+void native_pagetable_setup_start(pgd_t *base);
+void native_pagetable_setup_done(pgd_t *base);
+
+#ifndef CONFIG_PARAVIRT
+static inline void paravirt_pagetable_setup_start(pgd_t *base)
+{
+       native_pagetable_setup_start(base);
+}
+
+static inline void paravirt_pagetable_setup_done(pgd_t *base)
+{
+       native_pagetable_setup_done(base);
+}
+#endif /* !CONFIG_PARAVIRT */
+
 #endif /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_FLATMEM
@@ -519,10 +507,6 @@ do {                                                                       \
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)     (pfn)
-#define GET_IOSPACE(pfn)               0
-#define GET_PFN(pfn)                   (pfn)
-
 #include <asm-generic/pgtable.h>
 
 #endif /* _I386_PGTABLE_H */