]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/powerpc/mm/tlb-radix.c
Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / arch / powerpc / mm / tlb-radix.c
1 /*
2  * TLB flush routines for radix kernels.
3  *
4  * Copyright 2015-2016, Aneesh Kumar K.V, IBM Corporation.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #include <linux/mm.h>
13 #include <linux/hugetlb.h>
14 #include <linux/memblock.h>
15 #include <asm/ppc-opcode.h>
16
17 #include <asm/tlb.h>
18 #include <asm/tlbflush.h>
19
20
21 #define RIC_FLUSH_TLB 0
22 #define RIC_FLUSH_PWC 1
23 #define RIC_FLUSH_ALL 2
24
25 static inline void __tlbiel_pid(unsigned long pid, int set,
26                                 unsigned long ric)
27 {
28         unsigned long rb,rs,prs,r;
29
30         rb = PPC_BIT(53); /* IS = 1 */
31         rb |= set << PPC_BITLSHIFT(51);
32         rs = ((unsigned long)pid) << PPC_BITLSHIFT(31);
33         prs = 1; /* process scoped */
34         r = 1;   /* raidx format */
35
36         asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
37                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
38 }
39
40 /*
41  * We use 128 set in radix mode and 256 set in hpt mode.
42  */
43 static inline void _tlbiel_pid(unsigned long pid, unsigned long ric)
44 {
45         int set;
46
47         asm volatile("ptesync": : :"memory");
48
49         /*
50          * Flush the first set of the TLB, and if we're doing a RIC_FLUSH_ALL,
51          * also flush the entire Page Walk Cache.
52          */
53         __tlbiel_pid(pid, 0, ric);
54
55         if (ric == RIC_FLUSH_ALL)
56                 /* For the remaining sets, just flush the TLB */
57                 ric = RIC_FLUSH_TLB;
58
59         for (set = 1; set < POWER9_TLB_SETS_RADIX ; set++)
60                 __tlbiel_pid(pid, set, ric);
61
62         asm volatile("ptesync": : :"memory");
63         asm volatile(PPC_INVALIDATE_ERAT "; isync" : : :"memory");
64 }
65
66 static inline void tlbiel_pwc(unsigned long pid)
67 {
68         asm volatile("ptesync": : :"memory");
69
70         /* For PWC flush, we don't look at set number */
71         __tlbiel_pid(pid, 0, RIC_FLUSH_PWC);
72
73         asm volatile("ptesync": : :"memory");
74         asm volatile(PPC_INVALIDATE_ERAT "; isync" : : :"memory");
75 }
76
77 static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
78 {
79         unsigned long rb,rs,prs,r;
80
81         rb = PPC_BIT(53); /* IS = 1 */
82         rs = pid << PPC_BITLSHIFT(31);
83         prs = 1; /* process scoped */
84         r = 1;   /* raidx format */
85
86         asm volatile("ptesync": : :"memory");
87         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
88                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
89         asm volatile("eieio; tlbsync; ptesync": : :"memory");
90 }
91
92 static inline void _tlbiel_va(unsigned long va, unsigned long pid,
93                               unsigned long ap, unsigned long ric)
94 {
95         unsigned long rb,rs,prs,r;
96
97         rb = va & ~(PPC_BITMASK(52, 63));
98         rb |= ap << PPC_BITLSHIFT(58);
99         rs = pid << PPC_BITLSHIFT(31);
100         prs = 1; /* process scoped */
101         r = 1;   /* raidx format */
102
103         asm volatile("ptesync": : :"memory");
104         asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
105                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
106         asm volatile("ptesync": : :"memory");
107 }
108
109 static inline void _tlbie_va(unsigned long va, unsigned long pid,
110                              unsigned long ap, unsigned long ric)
111 {
112         unsigned long rb,rs,prs,r;
113
114         rb = va & ~(PPC_BITMASK(52, 63));
115         rb |= ap << PPC_BITLSHIFT(58);
116         rs = pid << PPC_BITLSHIFT(31);
117         prs = 1; /* process scoped */
118         r = 1;   /* raidx format */
119
120         asm volatile("ptesync": : :"memory");
121         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
122                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
123         asm volatile("eieio; tlbsync; ptesync": : :"memory");
124 }
125
126 /*
127  * Base TLB flushing operations:
128  *
129  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
130  *  - flush_tlb_page(vma, vmaddr) flushes one page
131  *  - flush_tlb_range(vma, start, end) flushes a range of pages
132  *  - flush_tlb_kernel_range(start, end) flushes kernel pages
133  *
134  *  - local_* variants of page and mm only apply to the current
135  *    processor
136  */
137 void radix__local_flush_tlb_mm(struct mm_struct *mm)
138 {
139         unsigned long pid;
140
141         preempt_disable();
142         pid = mm->context.id;
143         if (pid != MMU_NO_CONTEXT)
144                 _tlbiel_pid(pid, RIC_FLUSH_ALL);
145         preempt_enable();
146 }
147 EXPORT_SYMBOL(radix__local_flush_tlb_mm);
148
149 void radix__local_flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr)
150 {
151         unsigned long pid;
152         struct mm_struct *mm = tlb->mm;
153         /*
154          * If we are doing a full mm flush, we will do a tlb flush
155          * with RIC_FLUSH_ALL later.
156          */
157         if (tlb->fullmm)
158                 return;
159
160         preempt_disable();
161
162         pid = mm->context.id;
163         if (pid != MMU_NO_CONTEXT)
164                 tlbiel_pwc(pid);
165
166         preempt_enable();
167 }
168 EXPORT_SYMBOL(radix__local_flush_tlb_pwc);
169
170 void radix__local_flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
171                                        int psize)
172 {
173         unsigned long pid;
174         unsigned long ap = mmu_get_ap(psize);
175
176         preempt_disable();
177         pid = mm ? mm->context.id : 0;
178         if (pid != MMU_NO_CONTEXT)
179                 _tlbiel_va(vmaddr, pid, ap, RIC_FLUSH_TLB);
180         preempt_enable();
181 }
182
183 void radix__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
184 {
185 #ifdef CONFIG_HUGETLB_PAGE
186         /* need the return fix for nohash.c */
187         if (vma && is_vm_hugetlb_page(vma))
188                 return __local_flush_hugetlb_page(vma, vmaddr);
189 #endif
190         radix__local_flush_tlb_page_psize(vma ? vma->vm_mm : NULL, vmaddr,
191                                           mmu_virtual_psize);
192 }
193 EXPORT_SYMBOL(radix__local_flush_tlb_page);
194
195 #ifdef CONFIG_SMP
196 void radix__flush_tlb_mm(struct mm_struct *mm)
197 {
198         unsigned long pid;
199
200         preempt_disable();
201         pid = mm->context.id;
202         if (unlikely(pid == MMU_NO_CONTEXT))
203                 goto no_context;
204
205         if (!mm_is_thread_local(mm))
206                 _tlbie_pid(pid, RIC_FLUSH_ALL);
207         else
208                 _tlbiel_pid(pid, RIC_FLUSH_ALL);
209 no_context:
210         preempt_enable();
211 }
212 EXPORT_SYMBOL(radix__flush_tlb_mm);
213
214 void radix__flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr)
215 {
216         unsigned long pid;
217         struct mm_struct *mm = tlb->mm;
218
219         /*
220          * If we are doing a full mm flush, we will do a tlb flush
221          * with RIC_FLUSH_ALL later.
222          */
223         if (tlb->fullmm)
224                 return;
225         preempt_disable();
226
227         pid = mm->context.id;
228         if (unlikely(pid == MMU_NO_CONTEXT))
229                 goto no_context;
230
231         if (!mm_is_thread_local(mm))
232                 _tlbie_pid(pid, RIC_FLUSH_PWC);
233         else
234                 tlbiel_pwc(pid);
235 no_context:
236         preempt_enable();
237 }
238 EXPORT_SYMBOL(radix__flush_tlb_pwc);
239
240 void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
241                                  int psize)
242 {
243         unsigned long pid;
244         unsigned long ap = mmu_get_ap(psize);
245
246         preempt_disable();
247         pid = mm ? mm->context.id : 0;
248         if (unlikely(pid == MMU_NO_CONTEXT))
249                 goto bail;
250         if (!mm_is_thread_local(mm))
251                 _tlbie_va(vmaddr, pid, ap, RIC_FLUSH_TLB);
252         else
253                 _tlbiel_va(vmaddr, pid, ap, RIC_FLUSH_TLB);
254 bail:
255         preempt_enable();
256 }
257
258 void radix__flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
259 {
260 #ifdef CONFIG_HUGETLB_PAGE
261         if (vma && is_vm_hugetlb_page(vma))
262                 return flush_hugetlb_page(vma, vmaddr);
263 #endif
264         radix__flush_tlb_page_psize(vma ? vma->vm_mm : NULL, vmaddr,
265                                     mmu_virtual_psize);
266 }
267 EXPORT_SYMBOL(radix__flush_tlb_page);
268
269 #endif /* CONFIG_SMP */
270
271 void radix__flush_tlb_kernel_range(unsigned long start, unsigned long end)
272 {
273         _tlbie_pid(0, RIC_FLUSH_ALL);
274 }
275 EXPORT_SYMBOL(radix__flush_tlb_kernel_range);
276
277 /*
278  * Currently, for range flushing, we just do a full mm flush. Because
279  * we use this in code path where we don' track the page size.
280  */
281 void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
282                      unsigned long end)
283
284 {
285         struct mm_struct *mm = vma->vm_mm;
286         radix__flush_tlb_mm(mm);
287 }
288 EXPORT_SYMBOL(radix__flush_tlb_range);
289
290 static int radix_get_mmu_psize(int page_size)
291 {
292         int psize;
293
294         if (page_size == (1UL << mmu_psize_defs[mmu_virtual_psize].shift))
295                 psize = mmu_virtual_psize;
296         else if (page_size == (1UL << mmu_psize_defs[MMU_PAGE_2M].shift))
297                 psize = MMU_PAGE_2M;
298         else if (page_size == (1UL << mmu_psize_defs[MMU_PAGE_1G].shift))
299                 psize = MMU_PAGE_1G;
300         else
301                 return -1;
302         return psize;
303 }
304
305 void radix__tlb_flush(struct mmu_gather *tlb)
306 {
307         int psize = 0;
308         struct mm_struct *mm = tlb->mm;
309         int page_size = tlb->page_size;
310
311         psize = radix_get_mmu_psize(page_size);
312         /*
313          * if page size is not something we understand, do a full mm flush
314          */
315         if (psize != -1 && !tlb->fullmm && !tlb->need_flush_all)
316                 radix__flush_tlb_range_psize(mm, tlb->start, tlb->end, psize);
317         else
318                 radix__flush_tlb_mm(mm);
319 }
320
321 #define TLB_FLUSH_ALL -1UL
322 /*
323  * Number of pages above which we will do a bcast tlbie. Just a
324  * number at this point copied from x86
325  */
326 static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33;
327
328 void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start,
329                                   unsigned long end, int psize)
330 {
331         unsigned long pid;
332         unsigned long addr;
333         int local = mm_is_thread_local(mm);
334         unsigned long ap = mmu_get_ap(psize);
335         unsigned long page_size = 1UL << mmu_psize_defs[psize].shift;
336
337
338         preempt_disable();
339         pid = mm ? mm->context.id : 0;
340         if (unlikely(pid == MMU_NO_CONTEXT))
341                 goto err_out;
342
343         if (end == TLB_FLUSH_ALL ||
344             (end - start) > tlb_single_page_flush_ceiling * page_size) {
345                 if (local)
346                         _tlbiel_pid(pid, RIC_FLUSH_TLB);
347                 else
348                         _tlbie_pid(pid, RIC_FLUSH_TLB);
349                 goto err_out;
350         }
351         for (addr = start; addr < end; addr += page_size) {
352
353                 if (local)
354                         _tlbiel_va(addr, pid, ap, RIC_FLUSH_TLB);
355                 else
356                         _tlbie_va(addr, pid, ap, RIC_FLUSH_TLB);
357         }
358 err_out:
359         preempt_enable();
360 }
361
362 void radix__flush_tlb_lpid_va(unsigned long lpid, unsigned long gpa,
363                               unsigned long page_size)
364 {
365         unsigned long rb,rs,prs,r;
366         unsigned long ap;
367         unsigned long ric = RIC_FLUSH_TLB;
368
369         ap = mmu_get_ap(radix_get_mmu_psize(page_size));
370         rb = gpa & ~(PPC_BITMASK(52, 63));
371         rb |= ap << PPC_BITLSHIFT(58);
372         rs = lpid & ((1UL << 32) - 1);
373         prs = 0; /* process scoped */
374         r = 1;   /* raidx format */
375
376         asm volatile("ptesync": : :"memory");
377         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
378                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
379         asm volatile("eieio; tlbsync; ptesync": : :"memory");
380 }
381 EXPORT_SYMBOL(radix__flush_tlb_lpid_va);
382
383 void radix__flush_tlb_lpid(unsigned long lpid)
384 {
385         unsigned long rb,rs,prs,r;
386         unsigned long ric = RIC_FLUSH_ALL;
387
388         rb = 0x2 << PPC_BITLSHIFT(53); /* IS = 2 */
389         rs = lpid & ((1UL << 32) - 1);
390         prs = 0; /* partition scoped */
391         r = 1;   /* raidx format */
392
393         asm volatile("ptesync": : :"memory");
394         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
395                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
396         asm volatile("eieio; tlbsync; ptesync": : :"memory");
397 }
398 EXPORT_SYMBOL(radix__flush_tlb_lpid);
399
400 void radix__flush_pmd_tlb_range(struct vm_area_struct *vma,
401                                 unsigned long start, unsigned long end)
402 {
403         radix__flush_tlb_range_psize(vma->vm_mm, start, end, MMU_PAGE_2M);
404 }
405 EXPORT_SYMBOL(radix__flush_pmd_tlb_range);
406
407 void radix__flush_tlb_all(void)
408 {
409         unsigned long rb,prs,r,rs;
410         unsigned long ric = RIC_FLUSH_ALL;
411
412         rb = 0x3 << PPC_BITLSHIFT(53); /* IS = 3 */
413         prs = 0; /* partition scoped */
414         r = 1;   /* raidx format */
415         rs = 1 & ((1UL << 32) - 1); /* any LPID value to flush guest mappings */
416
417         asm volatile("ptesync": : :"memory");
418         /*
419          * now flush guest entries by passing PRS = 1 and LPID != 0
420          */
421         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
422                      : : "r"(rb), "i"(r), "i"(1), "i"(ric), "r"(rs) : "memory");
423         /*
424          * now flush host entires by passing PRS = 0 and LPID == 0
425          */
426         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
427                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(0) : "memory");
428         asm volatile("eieio; tlbsync; ptesync": : :"memory");
429 }
430
431 void radix__flush_tlb_pte_p9_dd1(unsigned long old_pte, struct mm_struct *mm,
432                                  unsigned long address)
433 {
434         /*
435          * We track page size in pte only for DD1, So we can
436          * call this only on DD1.
437          */
438         if (!cpu_has_feature(CPU_FTR_POWER9_DD1)) {
439                 VM_WARN_ON(1);
440                 return;
441         }
442
443         if (old_pte & R_PAGE_LARGE)
444                 radix__flush_tlb_page_psize(mm, address, MMU_PAGE_2M);
445         else
446                 radix__flush_tlb_page_psize(mm, address, mmu_virtual_psize);
447 }