aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKumar Gala <galak@kernel.crashing.org>2008-07-16 16:54:21 -0400
committerKumar Gala <galak@kernel.crashing.org>2008-09-24 17:29:41 -0400
commit9bf2b5cdc5fe5e3136ceeecc85141765023ded6e (patch)
treee1e25d6aa5a18ca63314192173d93cc0d20ac066
parent0ba3418b8b1c85ee1771c63f1dd12041614e56ff (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.h2
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc32.h25
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 */
618static inline unsigned long long pte_update(pte_t *p, 616static 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 */
655static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, 653
654static 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
671static 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.