aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2016-05-25 03:45:26 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-06-13 09:58:22 -0400
commit64f31d5802af11fd87872b4bae07b35cf0acb358 (patch)
tree73f514c73762092fd6710efa6863a5a6124d86a3 /arch/s390/mm
parent7dd968163f7c12bcb2132792bf873133b397a2d2 (diff)
s390/mm: simplify the TLB flushing code
ptep_flush_lazy and pmdp_flush_lazy use mm->context.attach_count to decide between a lazy TLB flush vs an immediate TLB flush. The field contains two 16-bit counters, the number of CPUs that have the mm attached and can create TLB entries for it and the number of CPUs in the middle of a page table update. The __tlb_flush_asce, ptep_flush_direct and pmdp_flush_direct functions use the attach counter and a mask check with mm_cpumask(mm) to decide between a local flush local of the current CPU and a global flush. For all these functions the decision between lazy vs immediate and local vs global TLB flush can be based on CPU masks. There are two masks: the mm->context.cpu_attach_mask with the CPUs that are actively using the mm, and the mm_cpumask(mm) with the CPUs that have used the mm since the last full flush. The decision between lazy vs immediate flush is based on the mm->context.cpu_attach_mask, to decide between local vs global flush the mm_cpumask(mm) is used. With this patch all checks will use the CPU masks, the old counter mm->context.attach_count with its two 16-bit values is turned into a single counter mm->context.flush_count that keeps track of the number of CPUs with incomplete page table updates. The sole user of this counter is finish_arch_post_lock_switch() which waits for the end of all page table updates. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/mm')
-rw-r--r--arch/s390/mm/init.c4
-rw-r--r--arch/s390/mm/pgtable.c34
2 files changed, 15 insertions, 23 deletions
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 44db60d9e519..de2cdf4fbb9a 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -118,10 +118,8 @@ void mark_rodata_ro(void)
118 118
119void __init mem_init(void) 119void __init mem_init(void)
120{ 120{
121 if (MACHINE_HAS_TLB_LC) 121 cpumask_set_cpu(0, &init_mm.context.cpu_attach_mask);
122 cpumask_set_cpu(0, &init_mm.context.cpu_attach_mask);
123 cpumask_set_cpu(0, mm_cpumask(&init_mm)); 122 cpumask_set_cpu(0, mm_cpumask(&init_mm));
124 atomic_set(&init_mm.context.attach_count, 1);
125 123
126 set_max_mapnr(max_low_pfn); 124 set_max_mapnr(max_low_pfn);
127 high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); 125 high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 67111ccbb5e0..74f8f2a8a4e8 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -27,40 +27,37 @@
27static inline pte_t ptep_flush_direct(struct mm_struct *mm, 27static inline pte_t ptep_flush_direct(struct mm_struct *mm,
28 unsigned long addr, pte_t *ptep) 28 unsigned long addr, pte_t *ptep)
29{ 29{
30 int active, count;
31 pte_t old; 30 pte_t old;
32 31
33 old = *ptep; 32 old = *ptep;
34 if (unlikely(pte_val(old) & _PAGE_INVALID)) 33 if (unlikely(pte_val(old) & _PAGE_INVALID))
35 return old; 34 return old;
36 active = (mm == current->active_mm) ? 1 : 0; 35 atomic_inc(&mm->context.flush_count);
37 count = atomic_add_return(0x10000, &mm->context.attach_count); 36 if (MACHINE_HAS_TLB_LC &&
38 if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active &&
39 cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) 37 cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
40 __ptep_ipte_local(addr, ptep); 38 __ptep_ipte_local(addr, ptep);
41 else 39 else
42 __ptep_ipte(addr, ptep); 40 __ptep_ipte(addr, ptep);
43 atomic_sub(0x10000, &mm->context.attach_count); 41 atomic_dec(&mm->context.flush_count);
44 return old; 42 return old;
45} 43}
46 44
47static inline pte_t ptep_flush_lazy(struct mm_struct *mm, 45static inline pte_t ptep_flush_lazy(struct mm_struct *mm,
48 unsigned long addr, pte_t *ptep) 46 unsigned long addr, pte_t *ptep)
49{ 47{
50 int active, count;
51 pte_t old; 48 pte_t old;
52 49
53 old = *ptep; 50 old = *ptep;
54 if (unlikely(pte_val(old) & _PAGE_INVALID)) 51 if (unlikely(pte_val(old) & _PAGE_INVALID))
55 return old; 52 return old;
56 active = (mm == current->active_mm) ? 1 : 0; 53 atomic_inc(&mm->context.flush_count);
57 count = atomic_add_return(0x10000, &mm->context.attach_count); 54 if (cpumask_equal(&mm->context.cpu_attach_mask,
58 if ((count & 0xffff) <= active) { 55 cpumask_of(smp_processor_id()))) {
59 pte_val(*ptep) |= _PAGE_INVALID; 56 pte_val(*ptep) |= _PAGE_INVALID;
60 mm->context.flush_mm = 1; 57 mm->context.flush_mm = 1;
61 } else 58 } else
62 __ptep_ipte(addr, ptep); 59 __ptep_ipte(addr, ptep);
63 atomic_sub(0x10000, &mm->context.attach_count); 60 atomic_dec(&mm->context.flush_count);
64 return old; 61 return old;
65} 62}
66 63
@@ -289,7 +286,6 @@ EXPORT_SYMBOL(ptep_modify_prot_commit);
289static inline pmd_t pmdp_flush_direct(struct mm_struct *mm, 286static inline pmd_t pmdp_flush_direct(struct mm_struct *mm,
290 unsigned long addr, pmd_t *pmdp) 287 unsigned long addr, pmd_t *pmdp)
291{ 288{
292 int active, count;
293 pmd_t old; 289 pmd_t old;
294 290
295 old = *pmdp; 291 old = *pmdp;
@@ -299,36 +295,34 @@ static inline pmd_t pmdp_flush_direct(struct mm_struct *mm,
299 __pmdp_csp(pmdp); 295 __pmdp_csp(pmdp);
300 return old; 296 return old;
301 } 297 }
302 active = (mm == current->active_mm) ? 1 : 0; 298 atomic_inc(&mm->context.flush_count);
303 count = atomic_add_return(0x10000, &mm->context.attach_count); 299 if (MACHINE_HAS_TLB_LC &&
304 if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active &&
305 cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) 300 cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
306 __pmdp_idte_local(addr, pmdp); 301 __pmdp_idte_local(addr, pmdp);
307 else 302 else
308 __pmdp_idte(addr, pmdp); 303 __pmdp_idte(addr, pmdp);
309 atomic_sub(0x10000, &mm->context.attach_count); 304 atomic_dec(&mm->context.flush_count);
310 return old; 305 return old;
311} 306}
312 307
313static inline pmd_t pmdp_flush_lazy(struct mm_struct *mm, 308static inline pmd_t pmdp_flush_lazy(struct mm_struct *mm,
314 unsigned long addr, pmd_t *pmdp) 309 unsigned long addr, pmd_t *pmdp)
315{ 310{
316 int active, count;
317 pmd_t old; 311 pmd_t old;
318 312
319 old = *pmdp; 313 old = *pmdp;
320 if (pmd_val(old) & _SEGMENT_ENTRY_INVALID) 314 if (pmd_val(old) & _SEGMENT_ENTRY_INVALID)
321 return old; 315 return old;
322 active = (mm == current->active_mm) ? 1 : 0; 316 atomic_inc(&mm->context.flush_count);
323 count = atomic_add_return(0x10000, &mm->context.attach_count); 317 if (cpumask_equal(&mm->context.cpu_attach_mask,
324 if ((count & 0xffff) <= active) { 318 cpumask_of(smp_processor_id()))) {
325 pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID; 319 pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID;
326 mm->context.flush_mm = 1; 320 mm->context.flush_mm = 1;
327 } else if (MACHINE_HAS_IDTE) 321 } else if (MACHINE_HAS_IDTE)
328 __pmdp_idte(addr, pmdp); 322 __pmdp_idte(addr, pmdp);
329 else 323 else
330 __pmdp_csp(pmdp); 324 __pmdp_csp(pmdp);
331 atomic_sub(0x10000, &mm->context.attach_count); 325 atomic_dec(&mm->context.flush_count);
332 return old; 326 return old;
333} 327}
334 328