1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/bitops.h>
21#include <linux/sched.h>
22#include <linux/slab.h>
23#include <linux/mm.h>
24
25#include <asm/cpufeature.h>
26#include <asm/mmu_context.h>
27#include <asm/smp.h>
28#include <asm/tlbflush.h>
29
30static u32 asid_bits;
31static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
32
33static atomic64_t asid_generation;
34static unsigned long *asid_map;
35
36static DEFINE_PER_CPU(atomic64_t, active_asids);
37static DEFINE_PER_CPU(u64, reserved_asids);
38static cpumask_t tlb_flush_pending;
39DEFINE_PER_CPU(bool, cpu_not_lazy_tlb);
40
41#define ASID_MASK (~GENMASK(asid_bits - 1, 0))
42#define ASID_FIRST_VERSION (1UL << asid_bits)
43
44#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
45#define NUM_USER_ASIDS (ASID_FIRST_VERSION >> 1)
46#define asid2idx(asid) (((asid) & ~ASID_MASK) >> 1)
47#define idx2asid(idx) (((idx) << 1) & ~ASID_MASK)
48#else
49#define NUM_USER_ASIDS (ASID_FIRST_VERSION)
50#define asid2idx(asid) ((asid) & ~ASID_MASK)
51#define idx2asid(idx) asid2idx(idx)
52#endif
53
54
55static u32 get_cpu_asid_bits(void)
56{
57 u32 asid;
58 int fld = cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR0_EL1),
59 ID_AA64MMFR0_ASID_SHIFT);
60
61 switch (fld) {
62 default:
63 pr_warn("CPU%d: Unknown ASID size (%d); assuming 8-bit\n",
64 smp_processor_id(), fld);
65
66 case 0:
67 asid = 8;
68 break;
69 case 2:
70 asid = 16;
71 }
72
73 return asid;
74}
75
76
77void verify_cpu_asid_bits(void)
78{
79 u32 asid = get_cpu_asid_bits();
80
81 if (asid < asid_bits) {
82
83
84
85
86 pr_crit("CPU%d: smaller ASID size(%u) than boot CPU (%u)\n",
87 smp_processor_id(), asid, asid_bits);
88 cpu_panic_kernel();
89 }
90}
91
92static void flush_context(void)
93{
94 int i;
95 u64 asid;
96
97
98 bitmap_clear(asid_map, 0, NUM_USER_ASIDS);
99
100 for_each_possible_cpu(i) {
101 asid = atomic64_xchg_relaxed(&per_cpu(active_asids, i), 0);
102
103
104
105
106
107
108
109 if (asid == 0)
110 asid = per_cpu(reserved_asids, i);
111 __set_bit(asid2idx(asid), asid_map);
112 per_cpu(reserved_asids, i) = asid;
113 }
114
115
116
117
118
119 cpumask_setall(&tlb_flush_pending);
120}
121
122static bool check_update_reserved_asid(u64 asid, u64 newasid)
123{
124 int cpu;
125 bool hit = false;
126
127
128
129
130
131
132
133
134
135
136 for_each_possible_cpu(cpu) {
137 if (per_cpu(reserved_asids, cpu) == asid) {
138 hit = true;
139 per_cpu(reserved_asids, cpu) = newasid;
140 }
141 }
142
143 return hit;
144}
145
146static u64 new_context(struct mm_struct *mm)
147{
148 static u32 cur_idx = 1;
149 u64 asid = atomic64_read(&mm->context.id);
150 u64 generation = atomic64_read(&asid_generation);
151
152 if (asid != 0) {
153 u64 newasid = generation | (asid & ~ASID_MASK);
154
155
156
157
158
159 if (check_update_reserved_asid(asid, newasid))
160 return newasid;
161
162
163
164
165
166 if (!__test_and_set_bit(asid2idx(asid), asid_map))
167 return newasid;
168 }
169
170
171
172
173
174
175
176
177 asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx);
178 if (asid != NUM_USER_ASIDS)
179 goto set_asid;
180
181
182 generation = atomic64_add_return_relaxed(ASID_FIRST_VERSION,
183 &asid_generation);
184 flush_context();
185
186
187 asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1);
188
189set_asid:
190 __set_bit(asid, asid_map);
191 cur_idx = asid;
192
193
194
195
196
197 cpumask_clear(mm_cpumask(mm));
198 return idx2asid(asid) | generation;
199}
200
201void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
202{
203 unsigned long flags;
204 u64 asid, old_active_asid;
205
206 if (system_supports_cnp())
207 cpu_set_reserved_ttbr0();
208
209 asid = atomic64_read(&mm->context.id);
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225 old_active_asid = atomic64_read(&per_cpu(active_asids, cpu));
226 if (old_active_asid &&
227 !((asid ^ atomic64_read(&asid_generation)) >> asid_bits) &&
228 atomic64_cmpxchg_relaxed(&per_cpu(active_asids, cpu),
229 old_active_asid, asid))
230 goto switch_mm_fastpath;
231
232 raw_spin_lock_irqsave(&cpu_asid_lock, flags);
233
234 asid = atomic64_read(&mm->context.id);
235 if ((asid ^ atomic64_read(&asid_generation)) >> asid_bits) {
236 asid = new_context(mm);
237 atomic64_set(&mm->context.id, asid);
238 }
239
240 if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending))
241 local_flush_tlb_all();
242
243 atomic64_set(&per_cpu(active_asids, cpu), asid);
244 raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
245
246switch_mm_fastpath:
247
248
249
250
251 smp_mb();
252 if (cpumask_test_cpu(cpu, mm_cpumask(mm))) {
253 cpumask_clear_cpu(cpu, mm_cpumask(mm));
254 local_flush_tlb_asid(asid);
255 }
256
257 arm64_apply_bp_hardening();
258
259
260
261
262
263 if (!system_uses_ttbr0_pan())
264 cpu_switch_mm(mm->pgd, mm);
265}
266
267enum tlb_flush_types tlb_flush_check(struct mm_struct *mm, unsigned int cpu)
268{
269 if (atomic_read(&mm->context.nr_active_mm) <= 1) {
270 bool is_local = current->active_mm == mm &&
271 per_cpu(cpu_not_lazy_tlb, cpu);
272 cpumask_t *stale_cpumask = mm_cpumask(mm);
273 unsigned int next_zero = cpumask_next_zero(-1, stale_cpumask);
274 bool local_is_clear = false;
275 if (next_zero < nr_cpu_ids &&
276 (is_local && next_zero == cpu)) {
277 next_zero = cpumask_next_zero(next_zero, stale_cpumask);
278 local_is_clear = true;
279 }
280 if (next_zero < nr_cpu_ids) {
281 cpumask_setall(stale_cpumask);
282 local_is_clear = false;
283 }
284
285
286
287
288
289
290 smp_mb();
291
292 if (likely(atomic_read(&mm->context.nr_active_mm)) <= 1) {
293 if (is_local) {
294 if (!local_is_clear)
295 cpumask_clear_cpu(cpu, stale_cpumask);
296 return TLB_FLUSH_LOCAL;
297 }
298 if (atomic_read(&mm->context.nr_active_mm) == 0)
299 return TLB_FLUSH_NO;
300 }
301 }
302 return TLB_FLUSH_BROADCAST;
303}
304
305
306asmlinkage void post_ttbr_update_workaround(void)
307{
308 asm(ALTERNATIVE("nop; nop; nop",
309 "ic iallu; dsb nsh; isb",
310 ARM64_WORKAROUND_CAVIUM_27456,
311 CONFIG_CAVIUM_ERRATUM_27456));
312}
313
314static int asids_init(void)
315{
316 asid_bits = get_cpu_asid_bits();
317
318
319
320
321 WARN_ON(NUM_USER_ASIDS - 1 <= num_possible_cpus());
322 atomic64_set(&asid_generation, ASID_FIRST_VERSION);
323 asid_map = kcalloc(BITS_TO_LONGS(NUM_USER_ASIDS), sizeof(*asid_map),
324 GFP_KERNEL);
325 if (!asid_map)
326 panic("Failed to allocate bitmap for %lu ASIDs\n",
327 NUM_USER_ASIDS);
328
329 pr_info("ASID allocator initialised with %lu entries\n", NUM_USER_ASIDS);
330 return 0;
331}
332early_initcall(asids_init);
333