Commit 63eca94ca206e342bad4a06a86d8e7eda3053a4e
1 parent
b6fe8e7c01
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
ARC: [SMP] ASID allocation
-Track a Per CPU ASID counter -mm-per-cpu ASID (multiple threads, or mm migrated around) Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Showing 3 changed files with 37 additions and 23 deletions Side-by-side Diff
arch/arc/include/asm/mmu.h
arch/arc/include/asm/mmu_context.h
... | ... | @@ -30,13 +30,13 @@ |
30 | 30 | * "Fast Context Switch" i.e. no TLB flush on ctxt-switch |
31 | 31 | * |
32 | 32 | * Linux assigns each task a unique ASID. A simple round-robin allocation |
33 | - * of H/w ASID is done using software tracker @asid_cache. | |
33 | + * of H/w ASID is done using software tracker @asid_cpu. | |
34 | 34 | * When it reaches max 255, the allocation cycle starts afresh by flushing |
35 | 35 | * the entire TLB and wrapping ASID back to zero. |
36 | 36 | * |
37 | 37 | * A new allocation cycle, post rollover, could potentially reassign an ASID |
38 | 38 | * to a different task. Thus the rule is to refresh the ASID in a new cycle. |
39 | - * The 32 bit @asid_cache (and mm->asid) have 8 bits MMU PID and rest 24 bits | |
39 | + * The 32 bit @asid_cpu (and mm->asid) have 8 bits MMU PID and rest 24 bits | |
40 | 40 | * serve as cycle/generation indicator and natural 32 bit unsigned math |
41 | 41 | * automagically increments the generation when lower 8 bits rollover. |
42 | 42 | */ |
43 | 43 | |
... | ... | @@ -47,9 +47,11 @@ |
47 | 47 | #define MM_CTXT_FIRST_CYCLE (MM_CTXT_ASID_MASK + 1) |
48 | 48 | #define MM_CTXT_NO_ASID 0UL |
49 | 49 | |
50 | -#define hw_pid(mm) (mm->context.asid & MM_CTXT_ASID_MASK) | |
50 | +#define asid_mm(mm, cpu) mm->context.asid[cpu] | |
51 | +#define hw_pid(mm, cpu) (asid_mm(mm, cpu) & MM_CTXT_ASID_MASK) | |
51 | 52 | |
52 | -extern unsigned int asid_cache; | |
53 | +DECLARE_PER_CPU(unsigned int, asid_cache); | |
54 | +#define asid_cpu(cpu) per_cpu(asid_cache, cpu) | |
53 | 55 | |
54 | 56 | /* |
55 | 57 | * Get a new ASID if task doesn't have a valid one (unalloc or from prev cycle) |
... | ... | @@ -57,6 +59,7 @@ |
57 | 59 | */ |
58 | 60 | static inline void get_new_mmu_context(struct mm_struct *mm) |
59 | 61 | { |
62 | + const unsigned int cpu = smp_processor_id(); | |
60 | 63 | unsigned long flags; |
61 | 64 | |
62 | 65 | local_irq_save(flags); |
63 | 66 | |
... | ... | @@ -71,11 +74,11 @@ |
71 | 74 | * first need to destroy the context, setting it to invalid |
72 | 75 | * value. |
73 | 76 | */ |
74 | - if (!((mm->context.asid ^ asid_cache) & MM_CTXT_CYCLE_MASK)) | |
77 | + if (!((asid_mm(mm, cpu) ^ asid_cpu(cpu)) & MM_CTXT_CYCLE_MASK)) | |
75 | 78 | goto set_hw; |
76 | 79 | |
77 | 80 | /* move to new ASID and handle rollover */ |
78 | - if (unlikely(!(++asid_cache & MM_CTXT_ASID_MASK))) { | |
81 | + if (unlikely(!(++asid_cpu(cpu) & MM_CTXT_ASID_MASK))) { | |
79 | 82 | |
80 | 83 | flush_tlb_all(); |
81 | 84 | |
82 | 85 | |
83 | 86 | |
... | ... | @@ -84,15 +87,15 @@ |
84 | 87 | * If the container itself wrapped around, set it to a non zero |
85 | 88 | * "generation" to distinguish from no context |
86 | 89 | */ |
87 | - if (!asid_cache) | |
88 | - asid_cache = MM_CTXT_FIRST_CYCLE; | |
90 | + if (!asid_cpu(cpu)) | |
91 | + asid_cpu(cpu) = MM_CTXT_FIRST_CYCLE; | |
89 | 92 | } |
90 | 93 | |
91 | 94 | /* Assign new ASID to tsk */ |
92 | - mm->context.asid = asid_cache; | |
95 | + asid_mm(mm, cpu) = asid_cpu(cpu); | |
93 | 96 | |
94 | 97 | set_hw: |
95 | - write_aux_reg(ARC_REG_PID, hw_pid(mm) | MMU_ENABLE); | |
98 | + write_aux_reg(ARC_REG_PID, hw_pid(mm, cpu) | MMU_ENABLE); | |
96 | 99 | |
97 | 100 | local_irq_restore(flags); |
98 | 101 | } |
99 | 102 | |
... | ... | @@ -104,10 +107,24 @@ |
104 | 107 | static inline int |
105 | 108 | init_new_context(struct task_struct *tsk, struct mm_struct *mm) |
106 | 109 | { |
107 | - mm->context.asid = MM_CTXT_NO_ASID; | |
110 | + int i; | |
111 | + | |
112 | + for_each_possible_cpu(i) | |
113 | + asid_mm(mm, i) = MM_CTXT_NO_ASID; | |
114 | + | |
108 | 115 | return 0; |
109 | 116 | } |
110 | 117 | |
118 | +static inline void destroy_context(struct mm_struct *mm) | |
119 | +{ | |
120 | + unsigned long flags; | |
121 | + | |
122 | + /* Needed to elide CONFIG_DEBUG_PREEMPT warning */ | |
123 | + local_irq_save(flags); | |
124 | + asid_mm(mm, smp_processor_id()) = MM_CTXT_NO_ASID; | |
125 | + local_irq_restore(flags); | |
126 | +} | |
127 | + | |
111 | 128 | /* Prepare the MMU for task: setup PID reg with allocated ASID |
112 | 129 | If task doesn't have an ASID (never alloc or stolen, get a new ASID) |
113 | 130 | */ |
... | ... | @@ -130,11 +147,6 @@ |
130 | 147 | * only if it was unallocated |
131 | 148 | */ |
132 | 149 | #define activate_mm(prev, next) switch_mm(prev, next, NULL) |
133 | - | |
134 | -static inline void destroy_context(struct mm_struct *mm) | |
135 | -{ | |
136 | - mm->context.asid = MM_CTXT_NO_ASID; | |
137 | -} | |
138 | 150 | |
139 | 151 | /* it seemed that deactivate_mm( ) is a reasonable place to do book-keeping |
140 | 152 | * for retiring-mm. However destroy_context( ) still needs to do that because |
arch/arc/mm/tlb.c
... | ... | @@ -100,7 +100,7 @@ |
100 | 100 | |
101 | 101 | |
102 | 102 | /* A copy of the ASID from the PID reg is kept in asid_cache */ |
103 | -unsigned int asid_cache = MM_CTXT_FIRST_CYCLE; | |
103 | +DEFINE_PER_CPU(unsigned int, asid_cache) = MM_CTXT_FIRST_CYCLE; | |
104 | 104 | |
105 | 105 | /* |
106 | 106 | * Utility Routine to erase a J-TLB entry |
... | ... | @@ -274,6 +274,7 @@ |
274 | 274 | void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, |
275 | 275 | unsigned long end) |
276 | 276 | { |
277 | + const unsigned int cpu = smp_processor_id(); | |
277 | 278 | unsigned long flags; |
278 | 279 | |
279 | 280 | /* If range @start to @end is more than 32 TLB entries deep, |
280 | 281 | |
... | ... | @@ -297,9 +298,9 @@ |
297 | 298 | |
298 | 299 | local_irq_save(flags); |
299 | 300 | |
300 | - if (vma->vm_mm->context.asid != MM_CTXT_NO_ASID) { | |
301 | + if (asid_mm(vma->vm_mm, cpu) != MM_CTXT_NO_ASID) { | |
301 | 302 | while (start < end) { |
302 | - tlb_entry_erase(start | hw_pid(vma->vm_mm)); | |
303 | + tlb_entry_erase(start | hw_pid(vma->vm_mm, cpu)); | |
303 | 304 | start += PAGE_SIZE; |
304 | 305 | } |
305 | 306 | } |
... | ... | @@ -346,6 +347,7 @@ |
346 | 347 | |
347 | 348 | void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) |
348 | 349 | { |
350 | + const unsigned int cpu = smp_processor_id(); | |
349 | 351 | unsigned long flags; |
350 | 352 | |
351 | 353 | /* Note that it is critical that interrupts are DISABLED between |
... | ... | @@ -353,8 +355,8 @@ |
353 | 355 | */ |
354 | 356 | local_irq_save(flags); |
355 | 357 | |
356 | - if (vma->vm_mm->context.asid != MM_CTXT_NO_ASID) { | |
357 | - tlb_entry_erase((page & PAGE_MASK) | hw_pid(vma->vm_mm)); | |
358 | + if (asid_mm(vma->vm_mm, cpu) != MM_CTXT_NO_ASID) { | |
359 | + tlb_entry_erase((page & PAGE_MASK) | hw_pid(vma->vm_mm, cpu)); | |
358 | 360 | utlb_invalidate(); |
359 | 361 | } |
360 | 362 | |
... | ... | @@ -400,7 +402,7 @@ |
400 | 402 | |
401 | 403 | local_irq_save(flags); |
402 | 404 | |
403 | - tlb_paranoid_check(vma->vm_mm->context.asid, address); | |
405 | + tlb_paranoid_check(asid_mm(vma->vm_mm, smp_processor_id()), address); | |
404 | 406 | |
405 | 407 | address &= PAGE_MASK; |
406 | 408 |