Skip to content

Commit

Permalink
powerpc: mmu_gather rework
Browse files Browse the repository at this point in the history
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: Peter Zijlstra <[email protected]>
Acked-by: Benjamin Herrenschmidt <[email protected]>
Cc: David Miller <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Russell King <[email protected]>
Cc: Paul Mundt <[email protected]>
Cc: Jeff Dike <[email protected]>
Cc: Richard Weinberger <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: KAMEZAWA Hiroyuki <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: Mel Gorman <[email protected]>
Cc: KOSAKI Motohiro <[email protected]>
Cc: Nick Piggin <[email protected]>
Cc: Namhyung Kim <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Peter Zijlstra authored and torvalds committed May 25, 2011
1 parent d16dfc5 commit d6bf29b
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 17 deletions.
4 changes: 2 additions & 2 deletions arch/powerpc/include/asm/pgalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)

#ifdef CONFIG_SMP
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 */
static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned 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 */

static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage,
Expand Down
2 changes: 2 additions & 0 deletions arch/powerpc/include/asm/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,12 @@ static inline struct thread_info *current_thread_info(void)
#define TLF_NAPPING 0 /* idle thread enabled NAP mode */
#define TLF_SLEEPING 1 /* suspend code enabled SLEEP mode */
#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_SLEEPING (1 << TLF_SLEEPING)
#define _TLF_RESTORE_SIGMASK (1 << TLF_RESTORE_SIGMASK)
#define _TLF_LAZY_MMU (1 << TLF_LAZY_MMU)

#ifndef __ASSEMBLY__
#define HAVE_SET_RESTORE_SIGMASK 1
Expand Down
10 changes: 10 additions & 0 deletions arch/powerpc/include/asm/tlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@
#define tlb_start_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);

/* Get the generic bits... */
Expand Down
23 changes: 22 additions & 1 deletion arch/powerpc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
struct thread_struct *new_thread, *old_thread;
unsigned long flags;
struct task_struct *last;
#ifdef CONFIG_PPC_BOOK3S_64
struct ppc64_tlb_batch *batch;
#endif

#ifdef CONFIG_SMP
/* avoid complexity of lazy save/restore of fpu
Expand Down Expand Up @@ -513,7 +516,17 @@ struct task_struct *__switch_to(struct task_struct *prev,
old_thread->accum_tb += (current_tb - start_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);

Expand All @@ -528,6 +541,14 @@ struct task_struct *__switch_to(struct task_struct *prev,
hard_irq_disable();
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);

return last;
Expand Down
14 changes: 4 additions & 10 deletions arch/powerpc/mm/pgtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@

#include "mmu_decl.h"

DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);

#ifdef CONFIG_SMP

/*
Expand All @@ -43,7 +41,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
* 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;

struct pte_freelist_batch
Expand Down Expand Up @@ -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)
{
/* This is safe since tlb_gather_mmu has disabled preemption */
struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
struct pte_freelist_batch **batchp = &tlb->arch.batch;
unsigned long pgf;

if (atomic_read(&tlb->mm->mm_users) < 2 ||
cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){
if (atomic_read(&tlb->mm->mm_users) < 2) {
pgtable_free(table, shift);
return;
}
Expand All @@ -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 = &__get_cpu_var(pte_freelist_cur);
struct pte_freelist_batch **batchp = &tlb->arch.batch;

if (*batchp == NULL)
return;
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/mm/tlb_hash32.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void tlb_flush(struct mmu_gather *tlb)
}

/* Push out batch of freed page tables */
pte_free_finish();
pte_free_finish(tlb);
}

/*
Expand Down
6 changes: 4 additions & 2 deletions arch/powerpc/mm/tlb_hash64.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)

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
* pages are going to be freed and we really don't want to have a CPU
Expand All @@ -164,8 +164,10 @@ void tlb_flush(struct mmu_gather *tlb)
if (tlbbatch->index)
__flush_tlb_pending(tlbbatch);

put_cpu_var(ppc64_tlb_batch);

/* Push out batch of freed page tables */
pte_free_finish();
pte_free_finish(tlb);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/mm/tlb_nohash.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ void tlb_flush(struct mmu_gather *tlb)
flush_tlb_mm(tlb->mm);

/* Push out batch of freed page tables */
pte_free_finish();
pte_free_finish(tlb);
}

/*
Expand Down

0 comments on commit d6bf29b

Please sign in to comment.