diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-06-06 08:14:41 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-06-06 08:14:56 -0400 |
commit | 36409f6353fc2d7b6516e631415f938eadd92ffa (patch) | |
tree | 6348a841e76a1ddff366bc1259c1ea64685d87b2 /arch/s390/include | |
parent | 3ec90878bade9280dee87c9e27d759f1cee07e70 (diff) |
[S390] use generic RCU page-table freeing code
Replace the s390 specific rcu page-table freeing code with the
generic variant. This requires to duplicate the definition for the
struct mmu_table_batch as s390 does not use the generic tlb flush
code.
While we are at it remove the restriction that page table fragments
can not be reused after a single fragment has been freed with rcu
and split out allocation and freeing of page tables with pgstes.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/include')
-rw-r--r-- | arch/s390/include/asm/pgalloc.h | 8 | ||||
-rw-r--r-- | arch/s390/include/asm/tlb.h | 94 |
2 files changed, 46 insertions, 56 deletions
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index f6314af3b354..38e71ebcd3c2 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h | |||
@@ -17,15 +17,15 @@ | |||
17 | #include <linux/gfp.h> | 17 | #include <linux/gfp.h> |
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | 19 | ||
20 | #define check_pgt_cache() do {} while (0) | ||
21 | |||
22 | unsigned long *crst_table_alloc(struct mm_struct *); | 20 | unsigned long *crst_table_alloc(struct mm_struct *); |
23 | void crst_table_free(struct mm_struct *, unsigned long *); | 21 | void crst_table_free(struct mm_struct *, unsigned long *); |
24 | void crst_table_free_rcu(struct mm_struct *, unsigned long *); | ||
25 | 22 | ||
26 | unsigned long *page_table_alloc(struct mm_struct *); | 23 | unsigned long *page_table_alloc(struct mm_struct *); |
27 | void page_table_free(struct mm_struct *, unsigned long *); | 24 | void page_table_free(struct mm_struct *, unsigned long *); |
28 | void page_table_free_rcu(struct mm_struct *, unsigned long *); | 25 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE |
26 | void page_table_free_rcu(struct mmu_gather *, unsigned long *); | ||
27 | void __tlb_remove_table(void *_table); | ||
28 | #endif | ||
29 | 29 | ||
30 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) | 30 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) |
31 | { | 31 | { |
diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h index 77eee5477a52..c687a2c83462 100644 --- a/arch/s390/include/asm/tlb.h +++ b/arch/s390/include/asm/tlb.h | |||
@@ -26,67 +26,60 @@ | |||
26 | #include <linux/swap.h> | 26 | #include <linux/swap.h> |
27 | #include <asm/processor.h> | 27 | #include <asm/processor.h> |
28 | #include <asm/pgalloc.h> | 28 | #include <asm/pgalloc.h> |
29 | #include <asm/smp.h> | ||
30 | #include <asm/tlbflush.h> | 29 | #include <asm/tlbflush.h> |
31 | 30 | ||
32 | struct mmu_gather { | 31 | struct mmu_gather { |
33 | struct mm_struct *mm; | 32 | struct mm_struct *mm; |
33 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | ||
34 | struct mmu_table_batch *batch; | ||
35 | #endif | ||
34 | unsigned int fullmm; | 36 | unsigned int fullmm; |
35 | unsigned int nr_ptes; | 37 | unsigned int need_flush; |
36 | unsigned int nr_pxds; | ||
37 | unsigned int max; | ||
38 | void **array; | ||
39 | void *local[8]; | ||
40 | }; | 38 | }; |
41 | 39 | ||
42 | static inline void __tlb_alloc_page(struct mmu_gather *tlb) | 40 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE |
43 | { | 41 | struct mmu_table_batch { |
44 | unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); | 42 | struct rcu_head rcu; |
43 | unsigned int nr; | ||
44 | void *tables[0]; | ||
45 | }; | ||
45 | 46 | ||
46 | if (addr) { | 47 | #define MAX_TABLE_BATCH \ |
47 | tlb->array = (void *) addr; | 48 | ((PAGE_SIZE - sizeof(struct mmu_table_batch)) / sizeof(void *)) |
48 | tlb->max = PAGE_SIZE / sizeof(void *); | 49 | |
49 | } | 50 | extern void tlb_table_flush(struct mmu_gather *tlb); |
50 | } | 51 | extern void tlb_remove_table(struct mmu_gather *tlb, void *table); |
52 | #endif | ||
51 | 53 | ||
52 | static inline void tlb_gather_mmu(struct mmu_gather *tlb, | 54 | static inline void tlb_gather_mmu(struct mmu_gather *tlb, |
53 | struct mm_struct *mm, | 55 | struct mm_struct *mm, |
54 | unsigned int full_mm_flush) | 56 | unsigned int full_mm_flush) |
55 | { | 57 | { |
56 | tlb->mm = mm; | 58 | tlb->mm = mm; |
57 | tlb->max = ARRAY_SIZE(tlb->local); | ||
58 | tlb->array = tlb->local; | ||
59 | tlb->fullmm = full_mm_flush; | 59 | tlb->fullmm = full_mm_flush; |
60 | tlb->need_flush = 0; | ||
61 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | ||
62 | tlb->batch = NULL; | ||
63 | #endif | ||
60 | if (tlb->fullmm) | 64 | if (tlb->fullmm) |
61 | __tlb_flush_mm(mm); | 65 | __tlb_flush_mm(mm); |
62 | else | ||
63 | __tlb_alloc_page(tlb); | ||
64 | tlb->nr_ptes = 0; | ||
65 | tlb->nr_pxds = tlb->max; | ||
66 | } | 66 | } |
67 | 67 | ||
68 | static inline void tlb_flush_mmu(struct mmu_gather *tlb) | 68 | static inline void tlb_flush_mmu(struct mmu_gather *tlb) |
69 | { | 69 | { |
70 | if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < tlb->max)) | 70 | if (!tlb->need_flush) |
71 | __tlb_flush_mm(tlb->mm); | 71 | return; |
72 | while (tlb->nr_ptes > 0) | 72 | tlb->need_flush = 0; |
73 | page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]); | 73 | __tlb_flush_mm(tlb->mm); |
74 | while (tlb->nr_pxds < tlb->max) | 74 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE |
75 | crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]); | 75 | tlb_table_flush(tlb); |
76 | #endif | ||
76 | } | 77 | } |
77 | 78 | ||
78 | static inline void tlb_finish_mmu(struct mmu_gather *tlb, | 79 | static inline void tlb_finish_mmu(struct mmu_gather *tlb, |
79 | unsigned long start, unsigned long end) | 80 | unsigned long start, unsigned long end) |
80 | { | 81 | { |
81 | tlb_flush_mmu(tlb); | 82 | tlb_flush_mmu(tlb); |
82 | |||
83 | rcu_table_freelist_finish(); | ||
84 | |||
85 | /* keep the page table cache within bounds */ | ||
86 | check_pgt_cache(); | ||
87 | |||
88 | if (tlb->array != tlb->local) | ||
89 | free_pages((unsigned long) tlb->array, 0); | ||
90 | } | 83 | } |
91 | 84 | ||
92 | /* | 85 | /* |
@@ -112,12 +105,11 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) | |||
112 | static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, | 105 | static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, |
113 | unsigned long address) | 106 | unsigned long address) |
114 | { | 107 | { |
115 | if (!tlb->fullmm) { | 108 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE |
116 | tlb->array[tlb->nr_ptes++] = pte; | 109 | if (!tlb->fullmm) |
117 | if (tlb->nr_ptes >= tlb->nr_pxds) | 110 | return page_table_free_rcu(tlb, (unsigned long *) pte); |
118 | tlb_flush_mmu(tlb); | 111 | #endif |
119 | } else | 112 | page_table_free(tlb->mm, (unsigned long *) pte); |
120 | page_table_free(tlb->mm, (unsigned long *) pte); | ||
121 | } | 113 | } |
122 | 114 | ||
123 | /* | 115 | /* |
@@ -133,12 +125,11 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, | |||
133 | #ifdef __s390x__ | 125 | #ifdef __s390x__ |
134 | if (tlb->mm->context.asce_limit <= (1UL << 31)) | 126 | if (tlb->mm->context.asce_limit <= (1UL << 31)) |
135 | return; | 127 | return; |
136 | if (!tlb->fullmm) { | 128 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE |
137 | tlb->array[--tlb->nr_pxds] = pmd; | 129 | if (!tlb->fullmm) |
138 | if (tlb->nr_ptes >= tlb->nr_pxds) | 130 | return tlb_remove_table(tlb, pmd); |
139 | tlb_flush_mmu(tlb); | 131 | #endif |
140 | } else | 132 | crst_table_free(tlb->mm, (unsigned long *) pmd); |
141 | crst_table_free(tlb->mm, (unsigned long *) pmd); | ||
142 | #endif | 133 | #endif |
143 | } | 134 | } |
144 | 135 | ||
@@ -155,12 +146,11 @@ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud, | |||
155 | #ifdef __s390x__ | 146 | #ifdef __s390x__ |
156 | if (tlb->mm->context.asce_limit <= (1UL << 42)) | 147 | if (tlb->mm->context.asce_limit <= (1UL << 42)) |
157 | return; | 148 | return; |
158 | if (!tlb->fullmm) { | 149 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE |
159 | tlb->array[--tlb->nr_pxds] = pud; | 150 | if (!tlb->fullmm) |
160 | if (tlb->nr_ptes >= tlb->nr_pxds) | 151 | return tlb_remove_table(tlb, pud); |
161 | tlb_flush_mmu(tlb); | 152 | #endif |
162 | } else | 153 | crst_table_free(tlb->mm, (unsigned long *) pud); |
163 | crst_table_free(tlb->mm, (unsigned long *) pud); | ||
164 | #endif | 154 | #endif |
165 | } | 155 | } |
166 | 156 | ||