提交 d6bf29b4 编写于 作者: P Peter Zijlstra 提交者: Linus Torvalds

powerpc: mmu_gather rework

Fix up powerpc to the new mmu_gather stuff.

PPC has an extra batching queue to RCU free the actual pagetable
allocations, use the ARCH extentions for that for now.

For the ppc64_tlb_batch, which tracks the vaddrs to unhash from the
hardware hash-table, keep using per-cpu arrays but flush on context switch
and use a TLF bit to track the lazy_mmu state.
Signed-off-by: NPeter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: NBenjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Miller <davem@davemloft.net>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Richard Weinberger <richard@nod.at>
Cc: Tony Luck <tony.luck@intel.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Nick Piggin <npiggin@kernel.dk>
Cc: Namhyung Kim <namhyung@gmail.com>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 d16dfc55
...@@ -32,13 +32,13 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage) ...@@ -32,13 +32,13 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift); extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift);
extern void pte_free_finish(void); extern void pte_free_finish(struct mmu_gather *tlb);
#else /* CONFIG_SMP */ #else /* CONFIG_SMP */
static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift) static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
{ {
pgtable_free(table, shift); pgtable_free(table, shift);
} }
static inline void pte_free_finish(void) { } static inline void pte_free_finish(struct mmu_gather *tlb) { }
#endif /* !CONFIG_SMP */ #endif /* !CONFIG_SMP */
static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage, static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage,
......
...@@ -139,10 +139,12 @@ static inline struct thread_info *current_thread_info(void) ...@@ -139,10 +139,12 @@ static inline struct thread_info *current_thread_info(void)
#define TLF_NAPPING 0 /* idle thread enabled NAP mode */ #define TLF_NAPPING 0 /* idle thread enabled NAP mode */
#define TLF_SLEEPING 1 /* suspend code enabled SLEEP mode */ #define TLF_SLEEPING 1 /* suspend code enabled SLEEP mode */
#define TLF_RESTORE_SIGMASK 2 /* Restore signal mask in do_signal */ #define TLF_RESTORE_SIGMASK 2 /* Restore signal mask in do_signal */
#define TLF_LAZY_MMU 3 /* tlb_batch is active */
#define _TLF_NAPPING (1 << TLF_NAPPING) #define _TLF_NAPPING (1 << TLF_NAPPING)
#define _TLF_SLEEPING (1 << TLF_SLEEPING) #define _TLF_SLEEPING (1 << TLF_SLEEPING)
#define _TLF_RESTORE_SIGMASK (1 << TLF_RESTORE_SIGMASK) #define _TLF_RESTORE_SIGMASK (1 << TLF_RESTORE_SIGMASK)
#define _TLF_LAZY_MMU (1 << TLF_LAZY_MMU)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define HAVE_SET_RESTORE_SIGMASK 1 #define HAVE_SET_RESTORE_SIGMASK 1
......
...@@ -28,6 +28,16 @@ ...@@ -28,6 +28,16 @@
#define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_start_vma(tlb, vma) do { } while (0)
#define tlb_end_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0)
#define HAVE_ARCH_MMU_GATHER 1
struct pte_freelist_batch;
struct arch_mmu_gather {
struct pte_freelist_batch *batch;
};
#define ARCH_MMU_GATHER_INIT (struct arch_mmu_gather){ .batch = NULL, }
extern void tlb_flush(struct mmu_gather *tlb); extern void tlb_flush(struct mmu_gather *tlb);
/* Get the generic bits... */ /* Get the generic bits... */
......
...@@ -395,6 +395,9 @@ struct task_struct *__switch_to(struct task_struct *prev, ...@@ -395,6 +395,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
struct thread_struct *new_thread, *old_thread; struct thread_struct *new_thread, *old_thread;
unsigned long flags; unsigned long flags;
struct task_struct *last; struct task_struct *last;
#ifdef CONFIG_PPC_BOOK3S_64
struct ppc64_tlb_batch *batch;
#endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* avoid complexity of lazy save/restore of fpu /* avoid complexity of lazy save/restore of fpu
...@@ -513,7 +516,17 @@ struct task_struct *__switch_to(struct task_struct *prev, ...@@ -513,7 +516,17 @@ struct task_struct *__switch_to(struct task_struct *prev,
old_thread->accum_tb += (current_tb - start_tb); old_thread->accum_tb += (current_tb - start_tb);
new_thread->start_tb = current_tb; new_thread->start_tb = current_tb;
} }
#endif #endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC_BOOK3S_64
batch = &__get_cpu_var(ppc64_tlb_batch);
if (batch->active) {
current_thread_info()->local_flags |= _TLF_LAZY_MMU;
if (batch->index)
__flush_tlb_pending(batch);
batch->active = 0;
}
#endif /* CONFIG_PPC_BOOK3S_64 */
local_irq_save(flags); local_irq_save(flags);
...@@ -528,6 +541,14 @@ struct task_struct *__switch_to(struct task_struct *prev, ...@@ -528,6 +541,14 @@ struct task_struct *__switch_to(struct task_struct *prev,
hard_irq_disable(); hard_irq_disable();
last = _switch(old_thread, new_thread); last = _switch(old_thread, new_thread);
#ifdef CONFIG_PPC_BOOK3S_64
if (current_thread_info()->local_flags & _TLF_LAZY_MMU) {
current_thread_info()->local_flags &= ~_TLF_LAZY_MMU;
batch = &__get_cpu_var(ppc64_tlb_batch);
batch->active = 1;
}
#endif /* CONFIG_PPC_BOOK3S_64 */
local_irq_restore(flags); local_irq_restore(flags);
return last; return last;
......
...@@ -33,8 +33,6 @@ ...@@ -33,8 +33,6 @@
#include "mmu_decl.h" #include "mmu_decl.h"
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* /*
...@@ -43,7 +41,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ...@@ -43,7 +41,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
* freeing a page table page that is being walked without locks * freeing a page table page that is being walked without locks
*/ */
static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
static unsigned long pte_freelist_forced_free; static unsigned long pte_freelist_forced_free;
struct pte_freelist_batch struct pte_freelist_batch
...@@ -97,12 +94,10 @@ static void pte_free_submit(struct pte_freelist_batch *batch) ...@@ -97,12 +94,10 @@ static void pte_free_submit(struct pte_freelist_batch *batch)
void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift) void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
{ {
/* This is safe since tlb_gather_mmu has disabled preemption */ struct pte_freelist_batch **batchp = &tlb->arch.batch;
struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
unsigned long pgf; unsigned long pgf;
if (atomic_read(&tlb->mm->mm_users) < 2 || if (atomic_read(&tlb->mm->mm_users) < 2) {
cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){
pgtable_free(table, shift); pgtable_free(table, shift);
return; return;
} }
...@@ -124,10 +119,9 @@ void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift) ...@@ -124,10 +119,9 @@ void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
} }
} }
void pte_free_finish(void) void pte_free_finish(struct mmu_gather *tlb)
{ {
/* This is safe since tlb_gather_mmu has disabled preemption */ struct pte_freelist_batch **batchp = &tlb->arch.batch;
struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
if (*batchp == NULL) if (*batchp == NULL)
return; return;
......
...@@ -73,7 +73,7 @@ void tlb_flush(struct mmu_gather *tlb) ...@@ -73,7 +73,7 @@ void tlb_flush(struct mmu_gather *tlb)
} }
/* Push out batch of freed page tables */ /* Push out batch of freed page tables */
pte_free_finish(); pte_free_finish(tlb);
} }
/* /*
......
...@@ -155,7 +155,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch) ...@@ -155,7 +155,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
void tlb_flush(struct mmu_gather *tlb) void tlb_flush(struct mmu_gather *tlb)
{ {
struct ppc64_tlb_batch *tlbbatch = &__get_cpu_var(ppc64_tlb_batch); struct ppc64_tlb_batch *tlbbatch = &get_cpu_var(ppc64_tlb_batch);
/* If there's a TLB batch pending, then we must flush it because the /* If there's a TLB batch pending, then we must flush it because the
* pages are going to be freed and we really don't want to have a CPU * pages are going to be freed and we really don't want to have a CPU
...@@ -164,8 +164,10 @@ void tlb_flush(struct mmu_gather *tlb) ...@@ -164,8 +164,10 @@ void tlb_flush(struct mmu_gather *tlb)
if (tlbbatch->index) if (tlbbatch->index)
__flush_tlb_pending(tlbbatch); __flush_tlb_pending(tlbbatch);
put_cpu_var(ppc64_tlb_batch);
/* Push out batch of freed page tables */ /* Push out batch of freed page tables */
pte_free_finish(); pte_free_finish(tlb);
} }
/** /**
......
...@@ -301,7 +301,7 @@ void tlb_flush(struct mmu_gather *tlb) ...@@ -301,7 +301,7 @@ void tlb_flush(struct mmu_gather *tlb)
flush_tlb_mm(tlb->mm); flush_tlb_mm(tlb->mm);
/* Push out batch of freed page tables */ /* Push out batch of freed page tables */
pte_free_finish(); pte_free_finish(tlb);
} }
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册