diff options
Diffstat (limited to 'include/asm-powerpc/pgtable-ppc32.h')
-rw-r--r-- | include/asm-powerpc/pgtable-ppc32.h | 80 |
1 files changed, 55 insertions, 25 deletions
diff --git a/include/asm-powerpc/pgtable-ppc32.h b/include/asm-powerpc/pgtable-ppc32.h index c08e714d0c4..3a96d001cb7 100644 --- a/include/asm-powerpc/pgtable-ppc32.h +++ b/include/asm-powerpc/pgtable-ppc32.h @@ -182,6 +182,9 @@ extern int icache_44x_need_flush; #define _PMD_SIZE_16M 0x0e0 #define PMD_PAGE_SIZE(pmdval) (1024 << (((pmdval) & _PMD_SIZE) >> 4)) +/* Until my rework is finished, 40x still needs atomic PTE updates */ +#define PTE_ATOMIC_UPDATES 1 + #elif defined(CONFIG_44x) /* * Definitions for PPC440 @@ -253,17 +256,17 @@ extern int icache_44x_need_flush; */ #define _PAGE_PRESENT 0x00000001 /* S: PTE valid */ -#define _PAGE_RW 0x00000002 /* S: Write permission */ +#define _PAGE_RW 0x00000002 /* S: Write permission */ #define _PAGE_FILE 0x00000004 /* S: nonlinear file mapping */ +#define _PAGE_HWEXEC 0x00000004 /* H: Execute permission */ #define _PAGE_ACCESSED 0x00000008 /* S: Page referenced */ -#define _PAGE_HWWRITE 0x00000010 /* H: Dirty & RW */ -#define _PAGE_HWEXEC 0x00000020 /* H: Execute permission */ -#define _PAGE_USER 0x00000040 /* S: User page */ -#define _PAGE_ENDIAN 0x00000080 /* H: E bit */ -#define _PAGE_GUARDED 0x00000100 /* H: G bit */ -#define _PAGE_DIRTY 0x00000200 /* S: Page dirty */ -#define _PAGE_NO_CACHE 0x00000400 /* H: I bit */ -#define _PAGE_WRITETHRU 0x00000800 /* H: W bit */ +#define _PAGE_DIRTY 0x00000010 /* S: Page dirty */ +#define _PAGE_USER 0x00000040 /* S: User page */ +#define _PAGE_ENDIAN 0x00000080 /* H: E bit */ +#define _PAGE_GUARDED 0x00000100 /* H: G bit */ +#define _PAGE_COHERENT 0x00000200 /* H: M bit */ +#define _PAGE_NO_CACHE 0x00000400 /* H: I bit */ +#define _PAGE_WRITETHRU 0x00000800 /* H: W bit */ /* TODO: Add large page lowmem mapping support */ #define _PMD_PRESENT 0 @@ -273,6 +276,7 @@ extern int icache_44x_need_flush; /* ERPN in a PTE never gets cleared, ignore it */ #define _PTE_NONE_MASK 0xffffffff00000000ULL + #elif defined(CONFIG_FSL_BOOKE) /* MMU Assist Register 3: @@ -291,10 +295,10 @@ extern int icache_44x_need_flush; #define _PAGE_PRESENT 0x00001 /* S: PTE contains a translation */ #define _PAGE_USER 0x00002 /* S: User page (maps to UR) */ #define _PAGE_FILE 0x00002 /* S: when !present: nonlinear file mapping */ -#define _PAGE_ACCESSED 0x00004 /* S: Page referenced */ -#define _PAGE_HWWRITE 0x00008 /* H: Dirty & RW, set in exception */ -#define _PAGE_RW 0x00010 /* S: Write permission */ -#define _PAGE_HWEXEC 0x00020 /* H: UX permission */ +#define _PAGE_RW 0x00004 /* S: Write permission (SW) */ +#define _PAGE_DIRTY 0x00008 /* S: Page dirty */ +#define _PAGE_HWEXEC 0x00010 /* H: SX permission */ +#define _PAGE_ACCESSED 0x00020 /* S: Page referenced */ #define _PAGE_ENDIAN 0x00040 /* H: E bit */ #define _PAGE_GUARDED 0x00080 /* H: G bit */ @@ -303,12 +307,8 @@ extern int icache_44x_need_flush; #define _PAGE_WRITETHRU 0x00400 /* H: W bit */ #ifdef CONFIG_PTE_64BIT -#define _PAGE_DIRTY 0x08000 /* S: Page dirty */ - /* ERPN in a PTE never gets cleared, ignore it */ #define _PTE_NONE_MASK 0xffffffffffff0000ULL -#else -#define _PAGE_DIRTY 0x00800 /* S: Page dirty */ #endif #define _PMD_PRESENT 0 @@ -345,6 +345,9 @@ extern int icache_44x_need_flush; #define _PTE_NONE_MASK _PAGE_ACCESSED +/* Until my rework is finished, 8xx still needs atomic PTE updates */ +#define PTE_ATOMIC_UPDATES 1 + #else /* CONFIG_6xx */ /* Definitions for 60x, 740/750, etc. */ #define _PAGE_PRESENT 0x001 /* software: pte contains a translation */ @@ -365,6 +368,10 @@ extern int icache_44x_need_flush; #define _PMD_PRESENT 0 #define _PMD_PRESENT_MASK (PAGE_MASK) #define _PMD_BAD (~PAGE_MASK) + +/* Hash table based platforms need atomic updates of the linux PTE */ +#define PTE_ATOMIC_UPDATES 1 + #endif /* @@ -557,9 +564,11 @@ extern void add_hash_page(unsigned context, unsigned long va, * low PTE word since we expect ALL flag bits to be there */ #ifndef CONFIG_PTE_64BIT -static inline unsigned long pte_update(pte_t *p, unsigned long clr, +static inline unsigned long pte_update(pte_t *p, + unsigned long clr, unsigned long set) { +#ifdef PTE_ATOMIC_UPDATES unsigned long old, tmp; __asm__ __volatile__("\ @@ -572,16 +581,26 @@ static inline unsigned long pte_update(pte_t *p, unsigned long clr, : "=&r" (old), "=&r" (tmp), "=m" (*p) : "r" (p), "r" (clr), "r" (set), "m" (*p) : "cc" ); +#else /* PTE_ATOMIC_UPDATES */ + unsigned long old = pte_val(*p); + *p = __pte((old & ~clr) | set); +#endif /* !PTE_ATOMIC_UPDATES */ + #ifdef CONFIG_44x if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC)) icache_44x_need_flush = 1; #endif return old; } -#else -static inline unsigned long long pte_update(pte_t *p, unsigned long clr, - unsigned long set) +#else /* CONFIG_PTE_64BIT */ +/* TODO: Change that to only modify the low word and move set_pte_at() + * out of line + */ +static inline unsigned long long pte_update(pte_t *p, + unsigned long clr, + unsigned long set) { +#ifdef PTE_ATOMIC_UPDATES unsigned long long old; unsigned long tmp; @@ -596,13 +615,18 @@ static inline unsigned long long pte_update(pte_t *p, unsigned long clr, : "=&r" (old), "=&r" (tmp), "=m" (*p) : "r" (p), "r" ((unsigned long)(p) + 4), "r" (clr), "r" (set), "m" (*p) : "cc" ); +#else /* PTE_ATOMIC_UPDATES */ + unsigned long long old = pte_val(*p); + *p = __pte((old & ~(unsigned long long)clr) | set); +#endif /* !PTE_ATOMIC_UPDATES */ + #ifdef CONFIG_44x if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC)) icache_44x_need_flush = 1; #endif return old; } -#endif +#endif /* CONFIG_PTE_64BIT */ /* * set_pte stores a linux PTE into the linux page table. @@ -620,8 +644,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, } /* - * 2.6 calles this without flushing the TLB entry, this is wrong - * for our hash-based implementation, we fix that up here + * 2.6 calls this without flushing the TLB entry; this is wrong + * for our hash-based implementation, we fix that up here. */ #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG static inline int __ptep_test_and_clear_young(unsigned int context, unsigned long addr, pte_t *ptep) @@ -652,6 +676,12 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, { pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0); } +static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + ptep_set_wrprotect(mm, addr, ptep); +} + #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) @@ -665,7 +695,7 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) ({ \ int __changed = !pte_same(*(__ptep), __entry); \ if (__changed) { \ - __ptep_set_access_flags(__ptep, __entry, __dirty); \ + __ptep_set_access_flags(__ptep, __entry, __dirty); \ flush_tlb_page_nohash(__vma, __address); \ } \ __changed; \ |