]> Git Repo - linux.git/blob - arch/powerpc/mm/tlb-radix.c
fork: Provide usercopy whitelisting for task_struct
[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
16 #include <asm/ppc-opcode.h>
17 #include <asm/tlb.h>
18 #include <asm/tlbflush.h>
19 #include <asm/trace.h>
20 #include <asm/cputhreads.h>
21
22 #define RIC_FLUSH_TLB 0
23 #define RIC_FLUSH_PWC 1
24 #define RIC_FLUSH_ALL 2
25
26 static inline void __tlbiel_pid(unsigned long pid, int set,
27                                 unsigned long ric)
28 {
29         unsigned long rb,rs,prs,r;
30
31         rb = PPC_BIT(53); /* IS = 1 */
32         rb |= set << PPC_BITLSHIFT(51);
33         rs = ((unsigned long)pid) << PPC_BITLSHIFT(31);
34         prs = 1; /* process scoped */
35         r = 1;   /* raidx format */
36
37         asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
38                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
39         trace_tlbie(0, 1, rb, rs, ric, prs, r);
40 }
41
42 static inline void __tlbie_pid(unsigned long pid, unsigned long ric)
43 {
44         unsigned long rb,rs,prs,r;
45
46         rb = PPC_BIT(53); /* IS = 1 */
47         rs = pid << PPC_BITLSHIFT(31);
48         prs = 1; /* process scoped */
49         r = 1;   /* raidx format */
50
51         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
52                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
53         trace_tlbie(0, 0, rb, rs, ric, prs, r);
54 }
55
56 /*
57  * We use 128 set in radix mode and 256 set in hpt mode.
58  */
59 static inline void _tlbiel_pid(unsigned long pid, unsigned long ric)
60 {
61         int set;
62
63         asm volatile("ptesync": : :"memory");
64
65         /*
66          * Flush the first set of the TLB, and if we're doing a RIC_FLUSH_ALL,
67          * also flush the entire Page Walk Cache.
68          */
69         __tlbiel_pid(pid, 0, ric);
70
71         /* For PWC, only one flush is needed */
72         if (ric == RIC_FLUSH_PWC) {
73                 asm volatile("ptesync": : :"memory");
74                 return;
75         }
76
77         /* For the remaining sets, just flush the TLB */
78         for (set = 1; set < POWER9_TLB_SETS_RADIX ; set++)
79                 __tlbiel_pid(pid, set, RIC_FLUSH_TLB);
80
81         asm volatile("ptesync": : :"memory");
82         asm volatile(PPC_INVALIDATE_ERAT "; isync" : : :"memory");
83 }
84
85 static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
86 {
87         asm volatile("ptesync": : :"memory");
88         __tlbie_pid(pid, ric);
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(PPC_TLBIEL(%0, %4, %3, %2, %1)
104                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
105         trace_tlbie(0, 1, rb, rs, ric, prs, r);
106 }
107
108 static inline void __tlbiel_va_range(unsigned long start, unsigned long end,
109                                     unsigned long pid, unsigned long page_size,
110                                     unsigned long psize)
111 {
112         unsigned long addr;
113         unsigned long ap = mmu_get_ap(psize);
114
115         for (addr = start; addr < end; addr += page_size)
116                 __tlbiel_va(addr, pid, ap, RIC_FLUSH_TLB);
117 }
118
119 static inline void _tlbiel_va(unsigned long va, unsigned long pid,
120                               unsigned long psize, unsigned long ric)
121 {
122         unsigned long ap = mmu_get_ap(psize);
123
124         asm volatile("ptesync": : :"memory");
125         __tlbiel_va(va, pid, ap, ric);
126         asm volatile("ptesync": : :"memory");
127 }
128
129 static inline void _tlbiel_va_range(unsigned long start, unsigned long end,
130                                     unsigned long pid, unsigned long page_size,
131                                     unsigned long psize, bool also_pwc)
132 {
133         asm volatile("ptesync": : :"memory");
134         if (also_pwc)
135                 __tlbiel_pid(pid, 0, RIC_FLUSH_PWC);
136         __tlbiel_va_range(start, end, pid, page_size, psize);
137         asm volatile("ptesync": : :"memory");
138 }
139
140 static inline void __tlbie_va(unsigned long va, unsigned long pid,
141                              unsigned long ap, unsigned long ric)
142 {
143         unsigned long rb,rs,prs,r;
144
145         rb = va & ~(PPC_BITMASK(52, 63));
146         rb |= ap << PPC_BITLSHIFT(58);
147         rs = pid << PPC_BITLSHIFT(31);
148         prs = 1; /* process scoped */
149         r = 1;   /* raidx format */
150
151         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
152                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
153         trace_tlbie(0, 0, rb, rs, ric, prs, r);
154 }
155
156 static inline void __tlbie_va_range(unsigned long start, unsigned long end,
157                                     unsigned long pid, unsigned long page_size,
158                                     unsigned long psize)
159 {
160         unsigned long addr;
161         unsigned long ap = mmu_get_ap(psize);
162
163         for (addr = start; addr < end; addr += page_size)
164                 __tlbie_va(addr, pid, ap, RIC_FLUSH_TLB);
165 }
166
167 static inline void _tlbie_va(unsigned long va, unsigned long pid,
168                               unsigned long psize, unsigned long ric)
169 {
170         unsigned long ap = mmu_get_ap(psize);
171
172         asm volatile("ptesync": : :"memory");
173         __tlbie_va(va, pid, ap, ric);
174         asm volatile("eieio; tlbsync; ptesync": : :"memory");
175 }
176
177 static inline void _tlbie_va_range(unsigned long start, unsigned long end,
178                                     unsigned long pid, unsigned long page_size,
179                                     unsigned long psize, bool also_pwc)
180 {
181         asm volatile("ptesync": : :"memory");
182         if (also_pwc)
183                 __tlbie_pid(pid, RIC_FLUSH_PWC);
184         __tlbie_va_range(start, end, pid, page_size, psize);
185         asm volatile("eieio; tlbsync; ptesync": : :"memory");
186 }
187
188 /*
189  * Base TLB flushing operations:
190  *
191  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
192  *  - flush_tlb_page(vma, vmaddr) flushes one page
193  *  - flush_tlb_range(vma, start, end) flushes a range of pages
194  *  - flush_tlb_kernel_range(start, end) flushes kernel pages
195  *
196  *  - local_* variants of page and mm only apply to the current
197  *    processor
198  */
199 void radix__local_flush_tlb_mm(struct mm_struct *mm)
200 {
201         unsigned long pid;
202
203         preempt_disable();
204         pid = mm->context.id;
205         if (pid != MMU_NO_CONTEXT)
206                 _tlbiel_pid(pid, RIC_FLUSH_TLB);
207         preempt_enable();
208 }
209 EXPORT_SYMBOL(radix__local_flush_tlb_mm);
210
211 #ifndef CONFIG_SMP
212 void radix__local_flush_all_mm(struct mm_struct *mm)
213 {
214         unsigned long pid;
215
216         preempt_disable();
217         pid = mm->context.id;
218         if (pid != MMU_NO_CONTEXT)
219                 _tlbiel_pid(pid, RIC_FLUSH_ALL);
220         preempt_enable();
221 }
222 EXPORT_SYMBOL(radix__local_flush_all_mm);
223 #endif /* CONFIG_SMP */
224
225 void radix__local_flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
226                                        int psize)
227 {
228         unsigned long pid;
229
230         preempt_disable();
231         pid = mm->context.id;
232         if (pid != MMU_NO_CONTEXT)
233                 _tlbiel_va(vmaddr, pid, psize, RIC_FLUSH_TLB);
234         preempt_enable();
235 }
236
237 void radix__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
238 {
239 #ifdef CONFIG_HUGETLB_PAGE
240         /* need the return fix for nohash.c */
241         if (is_vm_hugetlb_page(vma))
242                 return radix__local_flush_hugetlb_page(vma, vmaddr);
243 #endif
244         radix__local_flush_tlb_page_psize(vma->vm_mm, vmaddr, mmu_virtual_psize);
245 }
246 EXPORT_SYMBOL(radix__local_flush_tlb_page);
247
248 #ifdef CONFIG_SMP
249 void radix__flush_tlb_mm(struct mm_struct *mm)
250 {
251         unsigned long pid;
252
253         pid = mm->context.id;
254         if (unlikely(pid == MMU_NO_CONTEXT))
255                 return;
256
257         preempt_disable();
258         if (!mm_is_thread_local(mm))
259                 _tlbie_pid(pid, RIC_FLUSH_TLB);
260         else
261                 _tlbiel_pid(pid, RIC_FLUSH_TLB);
262         preempt_enable();
263 }
264 EXPORT_SYMBOL(radix__flush_tlb_mm);
265
266 void radix__flush_all_mm(struct mm_struct *mm)
267 {
268         unsigned long pid;
269
270         pid = mm->context.id;
271         if (unlikely(pid == MMU_NO_CONTEXT))
272                 return;
273
274         preempt_disable();
275         if (!mm_is_thread_local(mm))
276                 _tlbie_pid(pid, RIC_FLUSH_ALL);
277         else
278                 _tlbiel_pid(pid, RIC_FLUSH_ALL);
279         preempt_enable();
280 }
281 EXPORT_SYMBOL(radix__flush_all_mm);
282
283 void radix__flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr)
284 {
285         tlb->need_flush_all = 1;
286 }
287 EXPORT_SYMBOL(radix__flush_tlb_pwc);
288
289 void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
290                                  int psize)
291 {
292         unsigned long pid;
293
294         pid = mm->context.id;
295         if (unlikely(pid == MMU_NO_CONTEXT))
296                 return;
297
298         preempt_disable();
299         if (!mm_is_thread_local(mm))
300                 _tlbie_va(vmaddr, pid, psize, RIC_FLUSH_TLB);
301         else
302                 _tlbiel_va(vmaddr, pid, psize, RIC_FLUSH_TLB);
303         preempt_enable();
304 }
305
306 void radix__flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
307 {
308 #ifdef CONFIG_HUGETLB_PAGE
309         if (is_vm_hugetlb_page(vma))
310                 return radix__flush_hugetlb_page(vma, vmaddr);
311 #endif
312         radix__flush_tlb_page_psize(vma->vm_mm, vmaddr, mmu_virtual_psize);
313 }
314 EXPORT_SYMBOL(radix__flush_tlb_page);
315
316 #else /* CONFIG_SMP */
317 #define radix__flush_all_mm radix__local_flush_all_mm
318 #endif /* CONFIG_SMP */
319
320 void radix__flush_tlb_kernel_range(unsigned long start, unsigned long end)
321 {
322         _tlbie_pid(0, RIC_FLUSH_ALL);
323 }
324 EXPORT_SYMBOL(radix__flush_tlb_kernel_range);
325
326 #define TLB_FLUSH_ALL -1UL
327
328 /*
329  * Number of pages above which we invalidate the entire PID rather than
330  * flush individual pages, for local and global flushes respectively.
331  *
332  * tlbie goes out to the interconnect and individual ops are more costly.
333  * It also does not iterate over sets like the local tlbiel variant when
334  * invalidating a full PID, so it has a far lower threshold to change from
335  * individual page flushes to full-pid flushes.
336  */
337 static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33;
338 static unsigned long tlb_local_single_page_flush_ceiling __read_mostly = POWER9_TLB_SETS_RADIX * 2;
339
340 void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
341                      unsigned long end)
342
343 {
344         struct mm_struct *mm = vma->vm_mm;
345         unsigned long pid;
346         unsigned int page_shift = mmu_psize_defs[mmu_virtual_psize].shift;
347         unsigned long page_size = 1UL << page_shift;
348         unsigned long nr_pages = (end - start) >> page_shift;
349         bool local, full;
350
351 #ifdef CONFIG_HUGETLB_PAGE
352         if (is_vm_hugetlb_page(vma))
353                 return radix__flush_hugetlb_tlb_range(vma, start, end);
354 #endif
355
356         pid = mm->context.id;
357         if (unlikely(pid == MMU_NO_CONTEXT))
358                 return;
359
360         preempt_disable();
361         if (mm_is_thread_local(mm)) {
362                 local = true;
363                 full = (end == TLB_FLUSH_ALL ||
364                                 nr_pages > tlb_local_single_page_flush_ceiling);
365         } else {
366                 local = false;
367                 full = (end == TLB_FLUSH_ALL ||
368                                 nr_pages > tlb_single_page_flush_ceiling);
369         }
370
371         if (full) {
372                 if (local)
373                         _tlbiel_pid(pid, RIC_FLUSH_TLB);
374                 else
375                         _tlbie_pid(pid, RIC_FLUSH_TLB);
376         } else {
377                 bool hflush = false;
378                 unsigned long hstart, hend;
379
380 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
381                 hstart = (start + HPAGE_PMD_SIZE - 1) >> HPAGE_PMD_SHIFT;
382                 hend = end >> HPAGE_PMD_SHIFT;
383                 if (hstart < hend) {
384                         hstart <<= HPAGE_PMD_SHIFT;
385                         hend <<= HPAGE_PMD_SHIFT;
386                         hflush = true;
387                 }
388 #endif
389
390                 asm volatile("ptesync": : :"memory");
391                 if (local) {
392                         __tlbiel_va_range(start, end, pid, page_size, mmu_virtual_psize);
393                         if (hflush)
394                                 __tlbiel_va_range(hstart, hend, pid,
395                                                 HPAGE_PMD_SIZE, MMU_PAGE_2M);
396                         asm volatile("ptesync": : :"memory");
397                 } else {
398                         __tlbie_va_range(start, end, pid, page_size, mmu_virtual_psize);
399                         if (hflush)
400                                 __tlbie_va_range(hstart, hend, pid,
401                                                 HPAGE_PMD_SIZE, MMU_PAGE_2M);
402                         asm volatile("eieio; tlbsync; ptesync": : :"memory");
403                 }
404         }
405         preempt_enable();
406 }
407 EXPORT_SYMBOL(radix__flush_tlb_range);
408
409 static int radix_get_mmu_psize(int page_size)
410 {
411         int psize;
412
413         if (page_size == (1UL << mmu_psize_defs[mmu_virtual_psize].shift))
414                 psize = mmu_virtual_psize;
415         else if (page_size == (1UL << mmu_psize_defs[MMU_PAGE_2M].shift))
416                 psize = MMU_PAGE_2M;
417         else if (page_size == (1UL << mmu_psize_defs[MMU_PAGE_1G].shift))
418                 psize = MMU_PAGE_1G;
419         else
420                 return -1;
421         return psize;
422 }
423
424 static void radix__flush_tlb_pwc_range_psize(struct mm_struct *mm, unsigned long start,
425                                   unsigned long end, int psize);
426
427 void radix__tlb_flush(struct mmu_gather *tlb)
428 {
429         int psize = 0;
430         struct mm_struct *mm = tlb->mm;
431         int page_size = tlb->page_size;
432
433         /*
434          * if page size is not something we understand, do a full mm flush
435          *
436          * A "fullmm" flush must always do a flush_all_mm (RIC=2) flush
437          * that flushes the process table entry cache upon process teardown.
438          * See the comment for radix in arch_exit_mmap().
439          */
440         if (tlb->fullmm) {
441                 radix__flush_all_mm(mm);
442         } else if ( (psize = radix_get_mmu_psize(page_size)) == -1) {
443                 if (!tlb->need_flush_all)
444                         radix__flush_tlb_mm(mm);
445                 else
446                         radix__flush_all_mm(mm);
447         } else {
448                 unsigned long start = tlb->start;
449                 unsigned long end = tlb->end;
450
451                 if (!tlb->need_flush_all)
452                         radix__flush_tlb_range_psize(mm, start, end, psize);
453                 else
454                         radix__flush_tlb_pwc_range_psize(mm, start, end, psize);
455         }
456         tlb->need_flush_all = 0;
457 }
458
459 static inline void __radix__flush_tlb_range_psize(struct mm_struct *mm,
460                                 unsigned long start, unsigned long end,
461                                 int psize, bool also_pwc)
462 {
463         unsigned long pid;
464         unsigned int page_shift = mmu_psize_defs[psize].shift;
465         unsigned long page_size = 1UL << page_shift;
466         unsigned long nr_pages = (end - start) >> page_shift;
467         bool local, full;
468
469         pid = mm->context.id;
470         if (unlikely(pid == MMU_NO_CONTEXT))
471                 return;
472
473         preempt_disable();
474         if (mm_is_thread_local(mm)) {
475                 local = true;
476                 full = (end == TLB_FLUSH_ALL ||
477                                 nr_pages > tlb_local_single_page_flush_ceiling);
478         } else {
479                 local = false;
480                 full = (end == TLB_FLUSH_ALL ||
481                                 nr_pages > tlb_single_page_flush_ceiling);
482         }
483
484         if (full) {
485                 if (local)
486                         _tlbiel_pid(pid, also_pwc ? RIC_FLUSH_ALL : RIC_FLUSH_TLB);
487                 else
488                         _tlbie_pid(pid, also_pwc ? RIC_FLUSH_ALL: RIC_FLUSH_TLB);
489         } else {
490                 if (local)
491                         _tlbiel_va_range(start, end, pid, page_size, psize, also_pwc);
492                 else
493                         _tlbie_va_range(start, end, pid, page_size, psize, also_pwc);
494         }
495         preempt_enable();
496 }
497
498 void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start,
499                                   unsigned long end, int psize)
500 {
501         return __radix__flush_tlb_range_psize(mm, start, end, psize, false);
502 }
503
504 static void radix__flush_tlb_pwc_range_psize(struct mm_struct *mm, unsigned long start,
505                                   unsigned long end, int psize)
506 {
507         __radix__flush_tlb_range_psize(mm, start, end, psize, true);
508 }
509
510 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
511 void radix__flush_tlb_collapsed_pmd(struct mm_struct *mm, unsigned long addr)
512 {
513         unsigned long pid, end;
514
515         pid = mm->context.id;
516         if (unlikely(pid == MMU_NO_CONTEXT))
517                 return;
518
519         /* 4k page size, just blow the world */
520         if (PAGE_SIZE == 0x1000) {
521                 radix__flush_all_mm(mm);
522                 return;
523         }
524
525         end = addr + HPAGE_PMD_SIZE;
526
527         /* Otherwise first do the PWC, then iterate the pages. */
528         preempt_disable();
529
530         if (mm_is_thread_local(mm)) {
531                 _tlbiel_va_range(addr, end, pid, PAGE_SIZE, mmu_virtual_psize, true);
532         } else {
533                 _tlbie_va_range(addr, end, pid, PAGE_SIZE, mmu_virtual_psize, true);
534         }
535
536         preempt_enable();
537 }
538 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
539
540 void radix__flush_tlb_lpid_va(unsigned long lpid, unsigned long gpa,
541                               unsigned long page_size)
542 {
543         unsigned long rb,rs,prs,r;
544         unsigned long ap;
545         unsigned long ric = RIC_FLUSH_TLB;
546
547         ap = mmu_get_ap(radix_get_mmu_psize(page_size));
548         rb = gpa & ~(PPC_BITMASK(52, 63));
549         rb |= ap << PPC_BITLSHIFT(58);
550         rs = lpid & ((1UL << 32) - 1);
551         prs = 0; /* process scoped */
552         r = 1;   /* raidx format */
553
554         asm volatile("ptesync": : :"memory");
555         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
556                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
557         asm volatile("eieio; tlbsync; ptesync": : :"memory");
558         trace_tlbie(lpid, 0, rb, rs, ric, prs, r);
559 }
560 EXPORT_SYMBOL(radix__flush_tlb_lpid_va);
561
562 void radix__flush_tlb_lpid(unsigned long lpid)
563 {
564         unsigned long rb,rs,prs,r;
565         unsigned long ric = RIC_FLUSH_ALL;
566
567         rb = 0x2 << PPC_BITLSHIFT(53); /* IS = 2 */
568         rs = lpid & ((1UL << 32) - 1);
569         prs = 0; /* partition scoped */
570         r = 1;   /* raidx format */
571
572         asm volatile("ptesync": : :"memory");
573         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
574                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
575         asm volatile("eieio; tlbsync; ptesync": : :"memory");
576         trace_tlbie(lpid, 0, rb, rs, ric, prs, r);
577 }
578 EXPORT_SYMBOL(radix__flush_tlb_lpid);
579
580 void radix__flush_pmd_tlb_range(struct vm_area_struct *vma,
581                                 unsigned long start, unsigned long end)
582 {
583         radix__flush_tlb_range_psize(vma->vm_mm, start, end, MMU_PAGE_2M);
584 }
585 EXPORT_SYMBOL(radix__flush_pmd_tlb_range);
586
587 void radix__flush_tlb_all(void)
588 {
589         unsigned long rb,prs,r,rs;
590         unsigned long ric = RIC_FLUSH_ALL;
591
592         rb = 0x3 << PPC_BITLSHIFT(53); /* IS = 3 */
593         prs = 0; /* partition scoped */
594         r = 1;   /* raidx format */
595         rs = 1 & ((1UL << 32) - 1); /* any LPID value to flush guest mappings */
596
597         asm volatile("ptesync": : :"memory");
598         /*
599          * now flush guest entries by passing PRS = 1 and LPID != 0
600          */
601         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
602                      : : "r"(rb), "i"(r), "i"(1), "i"(ric), "r"(rs) : "memory");
603         trace_tlbie(0, 0, rb, rs, ric, prs, r);
604         /*
605          * now flush host entires by passing PRS = 0 and LPID == 0
606          */
607         asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
608                      : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(0) : "memory");
609         asm volatile("eieio; tlbsync; ptesync": : :"memory");
610         trace_tlbie(0, 0, rb, 0, ric, prs, r);
611 }
612
613 void radix__flush_tlb_pte_p9_dd1(unsigned long old_pte, struct mm_struct *mm,
614                                  unsigned long address)
615 {
616         /*
617          * We track page size in pte only for DD1, So we can
618          * call this only on DD1.
619          */
620         if (!cpu_has_feature(CPU_FTR_POWER9_DD1)) {
621                 VM_WARN_ON(1);
622                 return;
623         }
624
625         if (old_pte & R_PAGE_LARGE)
626                 radix__flush_tlb_page_psize(mm, address, MMU_PAGE_2M);
627         else
628                 radix__flush_tlb_page_psize(mm, address, mmu_virtual_psize);
629 }
630
631 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
632 extern void radix_kvm_prefetch_workaround(struct mm_struct *mm)
633 {
634         unsigned int pid = mm->context.id;
635
636         if (unlikely(pid == MMU_NO_CONTEXT))
637                 return;
638
639         /*
640          * If this context hasn't run on that CPU before and KVM is
641          * around, there's a slim chance that the guest on another
642          * CPU just brought in obsolete translation into the TLB of
643          * this CPU due to a bad prefetch using the guest PID on
644          * the way into the hypervisor.
645          *
646          * We work around this here. If KVM is possible, we check if
647          * any sibling thread is in KVM. If it is, the window may exist
648          * and thus we flush that PID from the core.
649          *
650          * A potential future improvement would be to mark which PIDs
651          * have never been used on the system and avoid it if the PID
652          * is new and the process has no other cpumask bit set.
653          */
654         if (cpu_has_feature(CPU_FTR_HVMODE) && radix_enabled()) {
655                 int cpu = smp_processor_id();
656                 int sib = cpu_first_thread_sibling(cpu);
657                 bool flush = false;
658
659                 for (; sib <= cpu_last_thread_sibling(cpu) && !flush; sib++) {
660                         if (sib == cpu)
661                                 continue;
662                         if (paca[sib].kvm_hstate.kvm_vcpu)
663                                 flush = true;
664                 }
665                 if (flush)
666                         _tlbiel_pid(pid, RIC_FLUSH_ALL);
667         }
668 }
669 EXPORT_SYMBOL_GPL(radix_kvm_prefetch_workaround);
670 #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
This page took 0.073022 seconds and 4 git commands to generate.