diff options
author | Kumar Gala <galak@kernel.crashing.org> | 2008-07-16 16:54:21 -0400 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2008-09-24 17:29:41 -0400 |
commit | 9bf2b5cdc5fe5e3136ceeecc85141765023ded6e (patch) | |
tree | e1e25d6aa5a18ca63314192173d93cc0d20ac066 | |
parent | 0ba3418b8b1c85ee1771c63f1dd12041614e56ff (diff) |
powerpc: Fixes for CONFIG_PTE_64BIT for SMP support
There are some minor issues with support 64-bit PTEs on a 32-bit processor
when dealing with SMP.
* We need to order the stores in set_pte_at to make sure the flag word
is set second.
* Change pte_clear to use pte_update so only the flag word is cleared
* Added a WARN_ON to set_pte_at to ensure the pte isn't present for
the 64-bit pte/SMP case (to ensure our assumption of this fact).
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Acked-by: Becky Bruce <becky.bruce@freescale.com>
-rw-r--r-- | arch/powerpc/include/asm/highmem.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/pgtable-ppc32.h | 25 |
2 files changed, 21 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index 5d99b6489d56..91c589520c0a 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h | |||
@@ -84,7 +84,7 @@ static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgpro | |||
84 | #ifdef CONFIG_DEBUG_HIGHMEM | 84 | #ifdef CONFIG_DEBUG_HIGHMEM |
85 | BUG_ON(!pte_none(*(kmap_pte-idx))); | 85 | BUG_ON(!pte_none(*(kmap_pte-idx))); |
86 | #endif | 86 | #endif |
87 | set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); | 87 | __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); |
88 | flush_tlb_page(NULL, vaddr); | 88 | flush_tlb_page(NULL, vaddr); |
89 | 89 | ||
90 | return (void*) vaddr; | 90 | return (void*) vaddr; |
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h index 6fe39e327047..1b1195555473 100644 --- a/arch/powerpc/include/asm/pgtable-ppc32.h +++ b/arch/powerpc/include/asm/pgtable-ppc32.h | |||
@@ -517,7 +517,8 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void); | |||
517 | 517 | ||
518 | #define pte_none(pte) ((pte_val(pte) & ~_PTE_NONE_MASK) == 0) | 518 | #define pte_none(pte) ((pte_val(pte) & ~_PTE_NONE_MASK) == 0) |
519 | #define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) | 519 | #define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) |
520 | #define pte_clear(mm,addr,ptep) do { set_pte_at((mm), (addr), (ptep), __pte(0)); } while (0) | 520 | #define pte_clear(mm, addr, ptep) \ |
521 | do { pte_update(ptep, ~_PAGE_HASHPTE, 0); } while (0) | ||
521 | 522 | ||
522 | #define pmd_none(pmd) (!pmd_val(pmd)) | 523 | #define pmd_none(pmd) (!pmd_val(pmd)) |
523 | #define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD) | 524 | #define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD) |
@@ -612,9 +613,6 @@ static inline unsigned long pte_update(pte_t *p, | |||
612 | return old; | 613 | return old; |
613 | } | 614 | } |
614 | #else /* CONFIG_PTE_64BIT */ | 615 | #else /* CONFIG_PTE_64BIT */ |
615 | /* TODO: Change that to only modify the low word and move set_pte_at() | ||
616 | * out of line | ||
617 | */ | ||
618 | static inline unsigned long long pte_update(pte_t *p, | 616 | static inline unsigned long long pte_update(pte_t *p, |
619 | unsigned long clr, | 617 | unsigned long clr, |
620 | unsigned long set) | 618 | unsigned long set) |
@@ -652,16 +650,33 @@ static inline unsigned long long pte_update(pte_t *p, | |||
652 | * On machines which use an MMU hash table we avoid changing the | 650 | * On machines which use an MMU hash table we avoid changing the |
653 | * _PAGE_HASHPTE bit. | 651 | * _PAGE_HASHPTE bit. |
654 | */ | 652 | */ |
655 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | 653 | |
654 | static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
656 | pte_t *ptep, pte_t pte) | 655 | pte_t *ptep, pte_t pte) |
657 | { | 656 | { |
658 | #if _PAGE_HASHPTE != 0 | 657 | #if _PAGE_HASHPTE != 0 |
659 | pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE); | 658 | pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE); |
659 | #elif defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP) | ||
660 | __asm__ __volatile__("\ | ||
661 | stw%U0%X0 %2,%0\n\ | ||
662 | eieio\n\ | ||
663 | stw%U0%X0 %L2,%1" | ||
664 | : "=m" (*ptep), "=m" (*((unsigned char *)ptep+4)) | ||
665 | : "r" (pte) : "memory"); | ||
660 | #else | 666 | #else |
661 | *ptep = pte; | 667 | *ptep = pte; |
662 | #endif | 668 | #endif |
663 | } | 669 | } |
664 | 670 | ||
671 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
672 | pte_t *ptep, pte_t pte) | ||
673 | { | ||
674 | #if defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP) | ||
675 | WARN_ON(pte_present(*ptep)); | ||
676 | #endif | ||
677 | __set_pte_at(mm, addr, ptep, pte); | ||
678 | } | ||
679 | |||
665 | /* | 680 | /* |
666 | * 2.6 calls this without flushing the TLB entry; this is wrong | 681 | * 2.6 calls this without flushing the TLB entry; this is wrong |
667 | * for our hash-based implementation, we fix that up here. | 682 | * for our hash-based implementation, we fix that up here. |