Hi Peter, On Thu, 08 Apr 2010 21:17:37 +0200 Peter Zijlstra <a.p.zijlstra@xxxxxxxxx> wrote: > The side-effects are that we can finally make mmu_gather preemptible, something > which lots of people have wanted to do for a long time. Yes, that is a good thing. With the preemptible mmu_gather s390 will use less IDTEs (that is the instruction that flushes all TLBs for a given address space) on a full flush. Good :-) > This patch-set seems to build and boot on my x86_64 machines and even builds a > kernel. I've also attempted powerpc and sparc, which I've compile tested with > their respective defconfigs, remaining are (afaikt the rest uses the generic > tlb bits): > > - s390 > - ia64 > - arm > - superh > - um > > From those, s390 and ia64 look 'interesting', arm and superh seem very similar > and should be relatively easy (-rt has a patchlet for arm iirc). To get the 'interesting' TLB flushing on s390 working again you need this patch: -- [PATCH] s390: preemptible mmu_gather From: Martin Schwidefsky <schwidefsky@xxxxxxxxxx> Adapt the stand-alone s390 mmu_gather implementation to the new preemptible mmu_gather interface. Signed-off-by: Martin Schwidefsky <schwidefsky@xxxxxxxxxx> --- arch/s390/include/asm/tlb.h | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) --- a/arch/s390/include/asm/tlb.h +++ b/arch/s390/include/asm/tlb.h @@ -28,45 +28,51 @@ #include <asm/smp.h> #include <asm/tlbflush.h> -#ifndef CONFIG_SMP -#define TLB_NR_PTRS 1 -#else -#define TLB_NR_PTRS 508 -#endif - struct mmu_gather { struct mm_struct *mm; unsigned int fullmm; unsigned int nr_ptes; unsigned int nr_pxds; - void *array[TLB_NR_PTRS]; + unsigned int max; + void **array; + void *local[8]; }; -DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); - -static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, - unsigned int full_mm_flush) +static inline void __tlb_alloc_pages(struct mmu_gather *tlb) { - struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); + unsigned long addr = __get_free_pages(GFP_ATOMIC, 0); + + if (addr) { + tlb->array = (void *) addr; + tlb->max = PAGE_SIZE / sizeof(void *); + } +} +static inline void tlb_gather_mmu(struct mmu_gather *tlb, + struct mm_struct *mm, + unsigned int full_mm_flush) +{ tlb->mm = mm; + tlb->max = ARRAY_SIZE(tlb->local); + tlb->array = tlb->local; tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) || (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm); - tlb->nr_ptes = 0; - tlb->nr_pxds = TLB_NR_PTRS; if (tlb->fullmm) __tlb_flush_mm(mm); - return tlb; + else + __tlb_alloc_pages(tlb); + tlb->nr_ptes = 0; + tlb->nr_pxds = tlb->max; } static inline void tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) { - if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS)) + if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < tlb->max)) __tlb_flush_mm(tlb->mm); while (tlb->nr_ptes > 0) pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]); - while (tlb->nr_pxds < TLB_NR_PTRS) + while (tlb->nr_pxds < tlb->max) /* pgd_free frees the pointer as region or segment table */ pgd_free(tlb->mm, tlb->array[tlb->nr_pxds++]); } @@ -79,7 +85,8 @@ static inline void tlb_finish_mmu(struct /* keep the page table cache within bounds */ check_pgt_cache(); - put_cpu_var(mmu_gathers); + if (tlb->array != tlb->local) + free_pages((unsigned long) tlb->array, 0); } /* -- blue skies, Martin. "Reality continues to ruin my life." - Calvin. -- To unsubscribe from this list: send the line "unsubscribe linux-arch" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html