diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2011-05-24 20:11:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-25 11:39:13 -0400 |
commit | 68f03921235c59507578a0165f87100d1120ec62 (patch) | |
tree | 37fb8431ceb078adff98137b6bbdffa315e771af /arch/s390 | |
parent | 90f08e399d054d017c0e2c5089a0f44a76418271 (diff) |
s390: mmu_gather rework
Adapt the stand-alone s390 mmu_gather implementation to the new
preemptible mmu_gather interface.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Miller <davem@davemloft.net>
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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/tlb.h | 62 |
1 files changed, 37 insertions, 25 deletions
diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h index 9074a54c4d10..77eee5477a52 100644 --- a/arch/s390/include/asm/tlb.h +++ b/arch/s390/include/asm/tlb.h | |||
@@ -29,65 +29,77 @@ | |||
29 | #include <asm/smp.h> | 29 | #include <asm/smp.h> |
30 | #include <asm/tlbflush.h> | 30 | #include <asm/tlbflush.h> |
31 | 31 | ||
32 | #ifndef CONFIG_SMP | ||
33 | #define TLB_NR_PTRS 1 | ||
34 | #else | ||
35 | #define TLB_NR_PTRS 508 | ||
36 | #endif | ||
37 | |||
38 | struct mmu_gather { | 32 | struct mmu_gather { |
39 | struct mm_struct *mm; | 33 | struct mm_struct *mm; |
40 | unsigned int fullmm; | 34 | unsigned int fullmm; |
41 | unsigned int nr_ptes; | 35 | unsigned int nr_ptes; |
42 | unsigned int nr_pxds; | 36 | unsigned int nr_pxds; |
43 | void *array[TLB_NR_PTRS]; | 37 | unsigned int max; |
38 | void **array; | ||
39 | void *local[8]; | ||
44 | }; | 40 | }; |
45 | 41 | ||
46 | DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); | 42 | static inline void __tlb_alloc_page(struct mmu_gather *tlb) |
47 | |||
48 | static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, | ||
49 | unsigned int full_mm_flush) | ||
50 | { | 43 | { |
51 | struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); | 44 | unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); |
52 | 45 | ||
46 | if (addr) { | ||
47 | tlb->array = (void *) addr; | ||
48 | tlb->max = PAGE_SIZE / sizeof(void *); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | static inline void tlb_gather_mmu(struct mmu_gather *tlb, | ||
53 | struct mm_struct *mm, | ||
54 | unsigned int full_mm_flush) | ||
55 | { | ||
53 | tlb->mm = mm; | 56 | tlb->mm = mm; |
57 | tlb->max = ARRAY_SIZE(tlb->local); | ||
58 | tlb->array = tlb->local; | ||
54 | tlb->fullmm = full_mm_flush; | 59 | tlb->fullmm = full_mm_flush; |
55 | tlb->nr_ptes = 0; | ||
56 | tlb->nr_pxds = TLB_NR_PTRS; | ||
57 | if (tlb->fullmm) | 60 | if (tlb->fullmm) |
58 | __tlb_flush_mm(mm); | 61 | __tlb_flush_mm(mm); |
59 | return tlb; | 62 | else |
63 | __tlb_alloc_page(tlb); | ||
64 | tlb->nr_ptes = 0; | ||
65 | tlb->nr_pxds = tlb->max; | ||
60 | } | 66 | } |
61 | 67 | ||
62 | static inline void tlb_flush_mmu(struct mmu_gather *tlb, | 68 | static inline void tlb_flush_mmu(struct mmu_gather *tlb) |
63 | unsigned long start, unsigned long end) | ||
64 | { | 69 | { |
65 | if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS)) | 70 | if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < tlb->max)) |
66 | __tlb_flush_mm(tlb->mm); | 71 | __tlb_flush_mm(tlb->mm); |
67 | while (tlb->nr_ptes > 0) | 72 | while (tlb->nr_ptes > 0) |
68 | page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]); | 73 | page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]); |
69 | while (tlb->nr_pxds < TLB_NR_PTRS) | 74 | while (tlb->nr_pxds < tlb->max) |
70 | crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]); | 75 | crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]); |
71 | } | 76 | } |
72 | 77 | ||
73 | static inline void tlb_finish_mmu(struct mmu_gather *tlb, | 78 | static inline void tlb_finish_mmu(struct mmu_gather *tlb, |
74 | unsigned long start, unsigned long end) | 79 | unsigned long start, unsigned long end) |
75 | { | 80 | { |
76 | tlb_flush_mmu(tlb, start, end); | 81 | tlb_flush_mmu(tlb); |
77 | 82 | ||
78 | rcu_table_freelist_finish(); | 83 | rcu_table_freelist_finish(); |
79 | 84 | ||
80 | /* keep the page table cache within bounds */ | 85 | /* keep the page table cache within bounds */ |
81 | check_pgt_cache(); | 86 | check_pgt_cache(); |
82 | 87 | ||
83 | put_cpu_var(mmu_gathers); | 88 | if (tlb->array != tlb->local) |
89 | free_pages((unsigned long) tlb->array, 0); | ||
84 | } | 90 | } |
85 | 91 | ||
86 | /* | 92 | /* |
87 | * Release the page cache reference for a pte removed by | 93 | * Release the page cache reference for a pte removed by |
88 | * tlb_ptep_clear_flush. In both flush modes the tlb fo a page cache page | 94 | * tlb_ptep_clear_flush. In both flush modes the tlb for a page cache page |
89 | * has already been freed, so just do free_page_and_swap_cache. | 95 | * has already been freed, so just do free_page_and_swap_cache. |
90 | */ | 96 | */ |
97 | static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) | ||
98 | { | ||
99 | free_page_and_swap_cache(page); | ||
100 | return 1; /* avoid calling tlb_flush_mmu */ | ||
101 | } | ||
102 | |||
91 | static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) | 103 | static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) |
92 | { | 104 | { |
93 | free_page_and_swap_cache(page); | 105 | free_page_and_swap_cache(page); |
@@ -103,7 +115,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, | |||
103 | if (!tlb->fullmm) { | 115 | if (!tlb->fullmm) { |
104 | tlb->array[tlb->nr_ptes++] = pte; | 116 | tlb->array[tlb->nr_ptes++] = pte; |
105 | if (tlb->nr_ptes >= tlb->nr_pxds) | 117 | if (tlb->nr_ptes >= tlb->nr_pxds) |
106 | tlb_flush_mmu(tlb, 0, 0); | 118 | tlb_flush_mmu(tlb); |
107 | } else | 119 | } else |
108 | page_table_free(tlb->mm, (unsigned long *) pte); | 120 | page_table_free(tlb->mm, (unsigned long *) pte); |
109 | } | 121 | } |
@@ -124,7 +136,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, | |||
124 | if (!tlb->fullmm) { | 136 | if (!tlb->fullmm) { |
125 | tlb->array[--tlb->nr_pxds] = pmd; | 137 | tlb->array[--tlb->nr_pxds] = pmd; |
126 | if (tlb->nr_ptes >= tlb->nr_pxds) | 138 | if (tlb->nr_ptes >= tlb->nr_pxds) |
127 | tlb_flush_mmu(tlb, 0, 0); | 139 | tlb_flush_mmu(tlb); |
128 | } else | 140 | } else |
129 | crst_table_free(tlb->mm, (unsigned long *) pmd); | 141 | crst_table_free(tlb->mm, (unsigned long *) pmd); |
130 | #endif | 142 | #endif |
@@ -146,7 +158,7 @@ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud, | |||
146 | if (!tlb->fullmm) { | 158 | if (!tlb->fullmm) { |
147 | tlb->array[--tlb->nr_pxds] = pud; | 159 | tlb->array[--tlb->nr_pxds] = pud; |
148 | if (tlb->nr_ptes >= tlb->nr_pxds) | 160 | if (tlb->nr_ptes >= tlb->nr_pxds) |
149 | tlb_flush_mmu(tlb, 0, 0); | 161 | tlb_flush_mmu(tlb); |
150 | } else | 162 | } else |
151 | crst_table_free(tlb->mm, (unsigned long *) pud); | 163 | crst_table_free(tlb->mm, (unsigned long *) pud); |
152 | #endif | 164 | #endif |