diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-07-08 01:54:40 -0400 |
---|---|---|
committer | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2008-07-09 13:36:17 -0400 |
commit | 1bc54c03117b90716e0dedd7abb2a20405de65df (patch) | |
tree | 8e82fd610abaff36f1e20b5aaaf7bdeaee883aac /include/asm-powerpc | |
parent | beae4c03c0fe69cf7d57518aa0572ad21730b8be (diff) |
powerpc: rework 4xx PTE access and TLB miss
This is some preliminary work to improve TLB management on SW loaded
TLB powerpc platforms. This introduce support for non-atomic PTE
operations in pgtable-ppc32.h and removes write back to the PTE from
the TLB miss handlers. In addition, the DSI interrupt code no longer
tries to fixup write permission, this is left to generic code, and
_PAGE_HWWRITE is gone.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'include/asm-powerpc')
-rw-r--r-- | include/asm-powerpc/pgtable-ppc32.h | 61 |
1 files changed, 46 insertions, 15 deletions
diff --git a/include/asm-powerpc/pgtable-ppc32.h b/include/asm-powerpc/pgtable-ppc32.h index e1d2bb57f1d5..11eede4a2906 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; | |||
182 | #define _PMD_SIZE_16M 0x0e0 | 182 | #define _PMD_SIZE_16M 0x0e0 |
183 | #define PMD_PAGE_SIZE(pmdval) (1024 << (((pmdval) & _PMD_SIZE) >> 4)) | 183 | #define PMD_PAGE_SIZE(pmdval) (1024 << (((pmdval) & _PMD_SIZE) >> 4)) |
184 | 184 | ||
185 | /* Until my rework is finished, 40x still needs atomic PTE updates */ | ||
186 | #define PTE_ATOMIC_UPDATES 1 | ||
187 | |||
185 | #elif defined(CONFIG_44x) | 188 | #elif defined(CONFIG_44x) |
186 | /* | 189 | /* |
187 | * Definitions for PPC440 | 190 | * Definitions for PPC440 |
@@ -253,17 +256,17 @@ extern int icache_44x_need_flush; | |||
253 | */ | 256 | */ |
254 | 257 | ||
255 | #define _PAGE_PRESENT 0x00000001 /* S: PTE valid */ | 258 | #define _PAGE_PRESENT 0x00000001 /* S: PTE valid */ |
256 | #define _PAGE_RW 0x00000002 /* S: Write permission */ | 259 | #define _PAGE_RW 0x00000002 /* S: Write permission */ |
257 | #define _PAGE_FILE 0x00000004 /* S: nonlinear file mapping */ | 260 | #define _PAGE_FILE 0x00000004 /* S: nonlinear file mapping */ |
261 | #define _PAGE_HWEXEC 0x00000004 /* H: Execute permission */ | ||
258 | #define _PAGE_ACCESSED 0x00000008 /* S: Page referenced */ | 262 | #define _PAGE_ACCESSED 0x00000008 /* S: Page referenced */ |
259 | #define _PAGE_HWWRITE 0x00000010 /* H: Dirty & RW */ | 263 | #define _PAGE_DIRTY 0x00000010 /* S: Page dirty */ |
260 | #define _PAGE_HWEXEC 0x00000020 /* H: Execute permission */ | 264 | #define _PAGE_USER 0x00000040 /* S: User page */ |
261 | #define _PAGE_USER 0x00000040 /* S: User page */ | 265 | #define _PAGE_ENDIAN 0x00000080 /* H: E bit */ |
262 | #define _PAGE_ENDIAN 0x00000080 /* H: E bit */ | 266 | #define _PAGE_GUARDED 0x00000100 /* H: G bit */ |
263 | #define _PAGE_GUARDED 0x00000100 /* H: G bit */ | 267 | #define _PAGE_COHERENT 0x00000200 /* H: M bit */ |
264 | #define _PAGE_DIRTY 0x00000200 /* S: Page dirty */ | 268 | #define _PAGE_NO_CACHE 0x00000400 /* H: I bit */ |
265 | #define _PAGE_NO_CACHE 0x00000400 /* H: I bit */ | 269 | #define _PAGE_WRITETHRU 0x00000800 /* H: W bit */ |
266 | #define _PAGE_WRITETHRU 0x00000800 /* H: W bit */ | ||
267 | 270 | ||
268 | /* TODO: Add large page lowmem mapping support */ | 271 | /* TODO: Add large page lowmem mapping support */ |
269 | #define _PMD_PRESENT 0 | 272 | #define _PMD_PRESENT 0 |
@@ -273,6 +276,7 @@ extern int icache_44x_need_flush; | |||
273 | /* ERPN in a PTE never gets cleared, ignore it */ | 276 | /* ERPN in a PTE never gets cleared, ignore it */ |
274 | #define _PTE_NONE_MASK 0xffffffff00000000ULL | 277 | #define _PTE_NONE_MASK 0xffffffff00000000ULL |
275 | 278 | ||
279 | |||
276 | #elif defined(CONFIG_FSL_BOOKE) | 280 | #elif defined(CONFIG_FSL_BOOKE) |
277 | /* | 281 | /* |
278 | MMU Assist Register 3: | 282 | MMU Assist Register 3: |
@@ -315,6 +319,9 @@ extern int icache_44x_need_flush; | |||
315 | #define _PMD_PRESENT_MASK (PAGE_MASK) | 319 | #define _PMD_PRESENT_MASK (PAGE_MASK) |
316 | #define _PMD_BAD (~PAGE_MASK) | 320 | #define _PMD_BAD (~PAGE_MASK) |
317 | 321 | ||
322 | /* Until my rework is finished, FSL BookE still needs atomic PTE updates */ | ||
323 | #define PTE_ATOMIC_UPDATES 1 | ||
324 | |||
318 | #elif defined(CONFIG_8xx) | 325 | #elif defined(CONFIG_8xx) |
319 | /* Definitions for 8xx embedded chips. */ | 326 | /* Definitions for 8xx embedded chips. */ |
320 | #define _PAGE_PRESENT 0x0001 /* Page is valid */ | 327 | #define _PAGE_PRESENT 0x0001 /* Page is valid */ |
@@ -345,6 +352,9 @@ extern int icache_44x_need_flush; | |||
345 | 352 | ||
346 | #define _PTE_NONE_MASK _PAGE_ACCESSED | 353 | #define _PTE_NONE_MASK _PAGE_ACCESSED |
347 | 354 | ||
355 | /* Until my rework is finished, 8xx still needs atomic PTE updates */ | ||
356 | #define PTE_ATOMIC_UPDATES 1 | ||
357 | |||
348 | #else /* CONFIG_6xx */ | 358 | #else /* CONFIG_6xx */ |
349 | /* Definitions for 60x, 740/750, etc. */ | 359 | /* Definitions for 60x, 740/750, etc. */ |
350 | #define _PAGE_PRESENT 0x001 /* software: pte contains a translation */ | 360 | #define _PAGE_PRESENT 0x001 /* software: pte contains a translation */ |
@@ -365,6 +375,10 @@ extern int icache_44x_need_flush; | |||
365 | #define _PMD_PRESENT 0 | 375 | #define _PMD_PRESENT 0 |
366 | #define _PMD_PRESENT_MASK (PAGE_MASK) | 376 | #define _PMD_PRESENT_MASK (PAGE_MASK) |
367 | #define _PMD_BAD (~PAGE_MASK) | 377 | #define _PMD_BAD (~PAGE_MASK) |
378 | |||
379 | /* Hash table based platforms need atomic updates of the linux PTE */ | ||
380 | #define PTE_ATOMIC_UPDATES 1 | ||
381 | |||
368 | #endif | 382 | #endif |
369 | 383 | ||
370 | /* | 384 | /* |
@@ -557,9 +571,11 @@ extern void add_hash_page(unsigned context, unsigned long va, | |||
557 | * low PTE word since we expect ALL flag bits to be there | 571 | * low PTE word since we expect ALL flag bits to be there |
558 | */ | 572 | */ |
559 | #ifndef CONFIG_PTE_64BIT | 573 | #ifndef CONFIG_PTE_64BIT |
560 | static inline unsigned long pte_update(pte_t *p, unsigned long clr, | 574 | static inline unsigned long pte_update(pte_t *p, |
575 | unsigned long clr, | ||
561 | unsigned long set) | 576 | unsigned long set) |
562 | { | 577 | { |
578 | #ifdef PTE_ATOMIC_UPDATES | ||
563 | unsigned long old, tmp; | 579 | unsigned long old, tmp; |
564 | 580 | ||
565 | __asm__ __volatile__("\ | 581 | __asm__ __volatile__("\ |
@@ -572,16 +588,26 @@ static inline unsigned long pte_update(pte_t *p, unsigned long clr, | |||
572 | : "=&r" (old), "=&r" (tmp), "=m" (*p) | 588 | : "=&r" (old), "=&r" (tmp), "=m" (*p) |
573 | : "r" (p), "r" (clr), "r" (set), "m" (*p) | 589 | : "r" (p), "r" (clr), "r" (set), "m" (*p) |
574 | : "cc" ); | 590 | : "cc" ); |
591 | #else /* PTE_ATOMIC_UPDATES */ | ||
592 | unsigned long old = pte_val(*p); | ||
593 | *p = __pte((old & ~clr) | set); | ||
594 | #endif /* !PTE_ATOMIC_UPDATES */ | ||
595 | |||
575 | #ifdef CONFIG_44x | 596 | #ifdef CONFIG_44x |
576 | if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC)) | 597 | if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC)) |
577 | icache_44x_need_flush = 1; | 598 | icache_44x_need_flush = 1; |
578 | #endif | 599 | #endif |
579 | return old; | 600 | return old; |
580 | } | 601 | } |
581 | #else | 602 | #else /* CONFIG_PTE_64BIT */ |
582 | static inline unsigned long long pte_update(pte_t *p, unsigned long clr, | 603 | /* TODO: Change that to only modify the low word and move set_pte_at() |
583 | unsigned long set) | 604 | * out of line |
605 | */ | ||
606 | static inline unsigned long long pte_update(pte_t *p, | ||
607 | unsigned long clr, | ||
608 | unsigned long set) | ||
584 | { | 609 | { |
610 | #ifdef PTE_ATOMIC_UPDATES | ||
585 | unsigned long long old; | 611 | unsigned long long old; |
586 | unsigned long tmp; | 612 | unsigned long tmp; |
587 | 613 | ||
@@ -596,13 +622,18 @@ static inline unsigned long long pte_update(pte_t *p, unsigned long clr, | |||
596 | : "=&r" (old), "=&r" (tmp), "=m" (*p) | 622 | : "=&r" (old), "=&r" (tmp), "=m" (*p) |
597 | : "r" (p), "r" ((unsigned long)(p) + 4), "r" (clr), "r" (set), "m" (*p) | 623 | : "r" (p), "r" ((unsigned long)(p) + 4), "r" (clr), "r" (set), "m" (*p) |
598 | : "cc" ); | 624 | : "cc" ); |
625 | #else /* PTE_ATOMIC_UPDATES */ | ||
626 | unsigned long long old = pte_val(*p); | ||
627 | *p = __pte((old & ~clr) | set); | ||
628 | #endif /* !PTE_ATOMIC_UPDATES */ | ||
629 | |||
599 | #ifdef CONFIG_44x | 630 | #ifdef CONFIG_44x |
600 | if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC)) | 631 | if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC)) |
601 | icache_44x_need_flush = 1; | 632 | icache_44x_need_flush = 1; |
602 | #endif | 633 | #endif |
603 | return old; | 634 | return old; |
604 | } | 635 | } |
605 | #endif | 636 | #endif /* CONFIG_PTE_64BIT */ |
606 | 637 | ||
607 | /* | 638 | /* |
608 | * set_pte stores a linux PTE into the linux page table. | 639 | * set_pte stores a linux PTE into the linux page table. |
@@ -671,7 +702,7 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) | |||
671 | ({ \ | 702 | ({ \ |
672 | int __changed = !pte_same(*(__ptep), __entry); \ | 703 | int __changed = !pte_same(*(__ptep), __entry); \ |
673 | if (__changed) { \ | 704 | if (__changed) { \ |
674 | __ptep_set_access_flags(__ptep, __entry, __dirty); \ | 705 | __ptep_set_access_flags(__ptep, __entry, __dirty); \ |
675 | flush_tlb_page_nohash(__vma, __address); \ | 706 | flush_tlb_page_nohash(__vma, __address); \ |
676 | } \ | 707 | } \ |
677 | __changed; \ | 708 | __changed; \ |