From df3b8611554e389e703fa753540289874fa5126c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 19 Nov 2008 05:53:24 +0000 Subject: powerpc: Add a local_flush_tlb_page to handle kmap_atomic invalidates The tlb invalidates in kmap_atomic/kunmap_atomic can be called from IRQ context, however they are only local invalidates (on the processor that the kmap was called on). In the future we want to use IPIs to do tlb invalidates this causes issue since flush_tlb_page() is considered a broadcast invalidate. Add local_flush_tlb_page() as a non-broadcast invalidate and use it in kmap_atomic() since we don't have enough information in the flush_tlb_page() call to determine its local. Signed-off-by: Kumar Gala Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/tlbflush.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'arch/powerpc/include/asm/tlbflush.h') diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index a2c6bfd85fb7..93716a9f4e16 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -6,6 +6,7 @@ * * - flush_tlb_mm(mm) flushes the specified mm context TLB's * - flush_tlb_page(vma, vmaddr) flushes one page + * - local_flush_tlb_page(vmaddr) flushes one page on the local processor * - flush_tlb_page_nohash(vma, vmaddr) flushes one page if SW loaded TLB * - flush_tlb_range(vma, start, end) flushes a range of pages * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages @@ -44,6 +45,11 @@ static inline void flush_tlb_mm(struct mm_struct *mm) _tlbil_pid(mm->context.id); } +static inline void local_flush_tlb_page(unsigned long vmaddr) +{ + _tlbil_va(vmaddr, 0); +} + static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) { @@ -81,6 +87,10 @@ extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); +static inline void local_flush_tlb_page(unsigned long vmaddr) +{ + flush_tlb_page(NULL, vmaddr); +} #else /* @@ -138,6 +148,10 @@ static inline void flush_tlb_mm(struct mm_struct *mm) { } +static inline void local_flush_tlb_page(unsigned long vmaddr) +{ +} + static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) { -- cgit v1.2.2 From 1a37a3fd7f12d8f9f720cceec84e23152e116668 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 14 Dec 2008 19:44:24 +0000 Subject: powerpc/mm: Add local_flush_tlb_mm() to SW loaded TLB implementations This adds a local_flush_tlb_mm() call as a pre-requisite for some SMP work for BookE processors. Signed-off-by: Benjamin Herrenschmidt Acked-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/tlbflush.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/powerpc/include/asm/tlbflush.h') diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index 93716a9f4e16..333c24b54379 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -40,6 +40,11 @@ extern void _tlbil_va(unsigned long address, unsigned int pid); extern void _tlbia(void); #endif +static inline void local_flush_tlb_mm(struct mm_struct *mm) +{ + _tlbil_pid(mm->context.id); +} + static inline void flush_tlb_mm(struct mm_struct *mm) { _tlbil_pid(mm->context.id); -- cgit v1.2.2 From 2ca8cf738907180e7fbda90f25f32b86feda609f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 18 Dec 2008 19:13:29 +0000 Subject: powerpc/mm: Rework context management for CPUs with no hash table This reworks the context management code used by 4xx,8xx and freescale BookE. It adds support for SMP by implementing a concept of stale context map to lazily flush the TLB on processors where a context may have been invalidated. This also contains the ground work for generalizing such lazy TLB flushing by just picking up a new PID and marking the old one stale. This will be implemented later. This is a first implementation that uses a global spinlock. Ideally, we should try to get at least the fast path (context ID already assigned) lockless or limited to a per context lock, but for now this will do. I tried to keep the UP case reasonably simple to avoid adding too much overhead to 8xx which does a lot of context stealing since it effectively has only 16 PIDs available. Signed-off-by: Benjamin Herrenschmidt Acked-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/tlbflush.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/powerpc/include/asm/tlbflush.h') diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index 333c24b54379..9ed363d3de44 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -29,6 +29,8 @@ #include +#define MMU_NO_CONTEXT ((unsigned int)-1) + extern void _tlbie(unsigned long address, unsigned int pid); extern void _tlbil_all(void); extern void _tlbil_pid(unsigned int pid); -- cgit v1.2.2 From f048aace29e007f2b642097e2da8231e0e9cce2d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 18 Dec 2008 19:13:38 +0000 Subject: powerpc/mm: Add SMP support to no-hash TLB handling This commit moves the whole no-hash TLB handling out of line into a new tlb_nohash.c file, and implements some basic SMP support using IPIs and/or broadcast tlbivax instructions. Note that I'm using local invalidations for D->I cache coherency. At worst, if another processor is trying to execute the same and has the old entry in its TLB, it will just take a fault and re-do the TLB flush locally (it won't re-do the cache flush in any case). Signed-off-by: Benjamin Herrenschmidt Acked-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/tlbflush.h | 84 +++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 46 deletions(-) (limited to 'arch/powerpc/include/asm/tlbflush.h') diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index 9ed363d3de44..8c39b27c1ed7 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -6,7 +6,9 @@ * * - flush_tlb_mm(mm) flushes the specified mm context TLB's * - flush_tlb_page(vma, vmaddr) flushes one page - * - local_flush_tlb_page(vmaddr) flushes one page on the local processor + * - local_flush_tlb_mm(mm) flushes the specified mm context on + * the local processor + * - local_flush_tlb_page(vma, vmaddr) flushes one page on the local processor * - flush_tlb_page_nohash(vma, vmaddr) flushes one page if SW loaded TLB * - flush_tlb_range(vma, start, end) flushes a range of pages * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages @@ -18,7 +20,7 @@ */ #ifdef __KERNEL__ -#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE) +#ifdef CONFIG_PPC_MMU_NOHASH /* * TLB flushing for software loaded TLB chips * @@ -31,10 +33,10 @@ #define MMU_NO_CONTEXT ((unsigned int)-1) -extern void _tlbie(unsigned long address, unsigned int pid); extern void _tlbil_all(void); extern void _tlbil_pid(unsigned int pid); extern void _tlbil_va(unsigned long address, unsigned int pid); +extern void _tlbivax_bcast(unsigned long address, unsigned int pid); #if defined(CONFIG_40x) || defined(CONFIG_8xx) #define _tlbia() asm volatile ("tlbia; sync" : : : "memory") @@ -42,48 +44,26 @@ extern void _tlbil_va(unsigned long address, unsigned int pid); extern void _tlbia(void); #endif -static inline void local_flush_tlb_mm(struct mm_struct *mm) -{ - _tlbil_pid(mm->context.id); -} - -static inline void flush_tlb_mm(struct mm_struct *mm) -{ - _tlbil_pid(mm->context.id); -} - -static inline void local_flush_tlb_page(unsigned long vmaddr) -{ - _tlbil_va(vmaddr, 0); -} - -static inline void flush_tlb_page(struct vm_area_struct *vma, - unsigned long vmaddr) -{ - _tlbil_va(vmaddr, vma ? vma->vm_mm->context.id : 0); -} +extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); -static inline void flush_tlb_page_nohash(struct vm_area_struct *vma, - unsigned long vmaddr) -{ - flush_tlb_page(vma, vmaddr); -} +extern void local_flush_tlb_mm(struct mm_struct *mm); +extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); -static inline void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - _tlbil_pid(vma->vm_mm->context.id); -} +#ifdef CONFIG_SMP +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); +#else +#define flush_tlb_mm(mm) local_flush_tlb_mm(mm) +#define flush_tlb_page(vma,addr) local_flush_tlb_page(vma,addr) +#endif +#define flush_tlb_page_nohash(vma,addr) flush_tlb_page(vma,addr) -static inline void flush_tlb_kernel_range(unsigned long start, - unsigned long end) -{ - _tlbil_pid(0); -} +#elif defined(CONFIG_PPC_STD_MMU_32) -#elif defined(CONFIG_PPC32) /* - * TLB flushing for "classic" hash-MMMU 32-bit CPUs, 6xx, 7xx, 7xxx + * TLB flushing for "classic" hash-MMU 32-bit CPUs, 6xx, 7xx, 7xxx */ extern void _tlbie(unsigned long address); extern void _tlbia(void); @@ -94,14 +74,20 @@ extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); -static inline void local_flush_tlb_page(unsigned long vmaddr) +static inline void local_flush_tlb_page(struct vm_area_struct *vma, + unsigned long vmaddr) { - flush_tlb_page(NULL, vmaddr); + flush_tlb_page(vma, vmaddr); +} +static inline void local_flush_tlb_mm(struct mm_struct *mm) +{ + flush_tlb_mm(mm); } -#else +#elif defined(CONFIG_PPC_STD_MMU_64) + /* - * TLB flushing for 64-bit has-MMU CPUs + * TLB flushing for 64-bit hash-MMU CPUs */ #include @@ -151,11 +137,16 @@ extern void flush_hash_page(unsigned long va, real_pte_t pte, int psize, extern void flush_hash_range(unsigned long number, int local); +static inline void local_flush_tlb_mm(struct mm_struct *mm) +{ +} + static inline void flush_tlb_mm(struct mm_struct *mm) { } -static inline void local_flush_tlb_page(unsigned long vmaddr) +static inline void local_flush_tlb_page(struct vm_area_struct *vma, + unsigned long vmaddr) { } @@ -183,7 +174,8 @@ static inline void flush_tlb_kernel_range(unsigned long start, extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start, unsigned long end); - +#else +#error Unsupported MMU type #endif #endif /*__KERNEL__ */ -- cgit v1.2.2 From 2a4aca1144394653269720ffbb5a325a77abd5fa Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 18 Dec 2008 19:13:42 +0000 Subject: powerpc/mm: Split low level tlb invalidate for nohash processors Currently, the various forms of low level TLB invalidations are all implemented in misc_32.S for 32-bit processors, in a fairly scary mess of #ifdef's and with interesting duplication such as a whole bunch of code for FSL _tlbie and _tlbia which are no longer used. This moves things around such that _tlbie is now defined in hash_low_32.S and is only used by the 32-bit hash code, and all nohash CPUs use the various _tlbil_* forms that are now moved to a new file, tlb_nohash_low.S. I moved all the definitions for that stuff out of include/asm/tlbflush.h as they are really internal mm stuff, into mm/mmu_decl.h The code should have no functional changes. I kept some variants inline for trivial forms on things like 40x and 8xx. Signed-off-by: Benjamin Herrenschmidt Acked-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/tlbflush.h | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'arch/powerpc/include/asm/tlbflush.h') diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index 8c39b27c1ed7..abbe3419d1dd 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -33,17 +33,6 @@ #define MMU_NO_CONTEXT ((unsigned int)-1) -extern void _tlbil_all(void); -extern void _tlbil_pid(unsigned int pid); -extern void _tlbil_va(unsigned long address, unsigned int pid); -extern void _tlbivax_bcast(unsigned long address, unsigned int pid); - -#if defined(CONFIG_40x) || defined(CONFIG_8xx) -#define _tlbia() asm volatile ("tlbia; sync" : : : "memory") -#else /* CONFIG_44x || CONFIG_FSL_BOOKE */ -extern void _tlbia(void); -#endif - extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); @@ -65,9 +54,6 @@ extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); /* * TLB flushing for "classic" hash-MMU 32-bit CPUs, 6xx, 7xx, 7xxx */ -extern void _tlbie(unsigned long address); -extern void _tlbia(void); - extern void flush_tlb_mm(struct mm_struct *mm); extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr); -- cgit v1.2.2