aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2018-08-26 06:56:48 -0400
committerPeter Zijlstra <peterz@infradead.org>2018-10-09 10:51:11 -0400
commita31acd3ee8f7dbc0370bdf4a4bfef7a8c13c7542 (patch)
treefe6035ec072385441ded002ba945960ba1ddc034
parenta5b966ae42a70b194b03eaa5eaea70d8b3790c40 (diff)
x86/mm: Page size aware flush_tlb_mm_range()
Use the new tlb_get_unmap_shift() to determine the stride of the INVLPG loop. Cc: Nick Piggin <npiggin@gmail.com> Cc: Will Deacon <will.deacon@arm.com> Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Dave Hansen <dave.hansen@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
-rw-r--r--arch/x86/include/asm/tlb.h21
-rw-r--r--arch/x86/include/asm/tlbflush.h12
-rw-r--r--arch/x86/kernel/ldt.c2
-rw-r--r--arch/x86/kernel/vm86_32.c2
-rw-r--r--arch/x86/mm/tlb.c17
-rw-r--r--mm/pgtable-generic.c1
6 files changed, 33 insertions, 22 deletions
diff --git a/arch/x86/include/asm/tlb.h b/arch/x86/include/asm/tlb.h
index cb0a1f470980..afbe7d1e68cf 100644
--- a/arch/x86/include/asm/tlb.h
+++ b/arch/x86/include/asm/tlb.h
@@ -6,16 +6,23 @@
6#define tlb_end_vma(tlb, vma) do { } while (0) 6#define tlb_end_vma(tlb, vma) do { } while (0)
7#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) 7#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
8 8
9#define tlb_flush(tlb) \ 9static inline void tlb_flush(struct mmu_gather *tlb);
10{ \
11 if (!tlb->fullmm && !tlb->need_flush_all) \
12 flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end, 0UL); \
13 else \
14 flush_tlb_mm_range(tlb->mm, 0UL, TLB_FLUSH_ALL, 0UL); \
15}
16 10
17#include <asm-generic/tlb.h> 11#include <asm-generic/tlb.h>
18 12
13static inline void tlb_flush(struct mmu_gather *tlb)
14{
15 unsigned long start = 0UL, end = TLB_FLUSH_ALL;
16 unsigned int stride_shift = tlb_get_unmap_shift(tlb);
17
18 if (!tlb->fullmm && !tlb->need_flush_all) {
19 start = tlb->start;
20 end = tlb->end;
21 }
22
23 flush_tlb_mm_range(tlb->mm, start, end, stride_shift);
24}
25
19/* 26/*
20 * While x86 architecture in general requires an IPI to perform TLB 27 * While x86 architecture in general requires an IPI to perform TLB
21 * shootdown, enablement code for several hypervisors overrides 28 * shootdown, enablement code for several hypervisors overrides
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index 58ce5288878e..671f65309ce7 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -547,23 +547,27 @@ struct flush_tlb_info {
547 unsigned long start; 547 unsigned long start;
548 unsigned long end; 548 unsigned long end;
549 u64 new_tlb_gen; 549 u64 new_tlb_gen;
550 unsigned int stride_shift;
550}; 551};
551 552
552#define local_flush_tlb() __flush_tlb() 553#define local_flush_tlb() __flush_tlb()
553 554
554#define flush_tlb_mm(mm) flush_tlb_mm_range(mm, 0UL, TLB_FLUSH_ALL, 0UL) 555#define flush_tlb_mm(mm) flush_tlb_mm_range(mm, 0UL, TLB_FLUSH_ALL, 0UL)
555 556
556#define flush_tlb_range(vma, start, end) \ 557#define flush_tlb_range(vma, start, end) \
557 flush_tlb_mm_range(vma->vm_mm, start, end, vma->vm_flags) 558 flush_tlb_mm_range((vma)->vm_mm, start, end, \
559 ((vma)->vm_flags & VM_HUGETLB) \
560 ? huge_page_shift(hstate_vma(vma)) \
561 : PAGE_SHIFT)
558 562
559extern void flush_tlb_all(void); 563extern void flush_tlb_all(void);
560extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, 564extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
561 unsigned long end, unsigned long vmflag); 565 unsigned long end, unsigned int stride_shift);
562extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); 566extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
563 567
564static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long a) 568static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long a)
565{ 569{
566 flush_tlb_mm_range(vma->vm_mm, a, a + PAGE_SIZE, VM_NONE); 570 flush_tlb_mm_range(vma->vm_mm, a, a + PAGE_SIZE, PAGE_SHIFT);
567} 571}
568 572
569void native_flush_tlb_others(const struct cpumask *cpumask, 573void native_flush_tlb_others(const struct cpumask *cpumask,
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index 733e6ace0fa4..7fdb2414ca65 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -273,7 +273,7 @@ map_ldt_struct(struct mm_struct *mm, struct ldt_struct *ldt, int slot)
273 map_ldt_struct_to_user(mm); 273 map_ldt_struct_to_user(mm);
274 274
275 va = (unsigned long)ldt_slot_va(slot); 275 va = (unsigned long)ldt_slot_va(slot);
276 flush_tlb_mm_range(mm, va, va + LDT_SLOT_STRIDE, 0); 276 flush_tlb_mm_range(mm, va, va + LDT_SLOT_STRIDE, PAGE_SHIFT);
277 277
278 ldt->slot = slot; 278 ldt->slot = slot;
279 return 0; 279 return 0;
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 1c03e4aa6474..52fed70f671e 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -199,7 +199,7 @@ static void mark_screen_rdonly(struct mm_struct *mm)
199 pte_unmap_unlock(pte, ptl); 199 pte_unmap_unlock(pte, ptl);
200out: 200out:
201 up_write(&mm->mmap_sem); 201 up_write(&mm->mmap_sem);
202 flush_tlb_mm_range(mm, 0xA0000, 0xA0000 + 32*PAGE_SIZE, 0UL); 202 flush_tlb_mm_range(mm, 0xA0000, 0xA0000 + 32*PAGE_SIZE, PAGE_SHIFT);
203} 203}
204 204
205 205
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index e96b99eb800c..6aa195796dec 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -528,17 +528,16 @@ static void flush_tlb_func_common(const struct flush_tlb_info *f,
528 f->new_tlb_gen == local_tlb_gen + 1 && 528 f->new_tlb_gen == local_tlb_gen + 1 &&
529 f->new_tlb_gen == mm_tlb_gen) { 529 f->new_tlb_gen == mm_tlb_gen) {
530 /* Partial flush */ 530 /* Partial flush */
531 unsigned long addr; 531 unsigned long nr_invalidate = (f->end - f->start) >> f->stride_shift;
532 unsigned long nr_pages = (f->end - f->start) >> PAGE_SHIFT; 532 unsigned long addr = f->start;
533 533
534 addr = f->start;
535 while (addr < f->end) { 534 while (addr < f->end) {
536 __flush_tlb_one_user(addr); 535 __flush_tlb_one_user(addr);
537 addr += PAGE_SIZE; 536 addr += 1UL << f->stride_shift;
538 } 537 }
539 if (local) 538 if (local)
540 count_vm_tlb_events(NR_TLB_LOCAL_FLUSH_ONE, nr_pages); 539 count_vm_tlb_events(NR_TLB_LOCAL_FLUSH_ONE, nr_invalidate);
541 trace_tlb_flush(reason, nr_pages); 540 trace_tlb_flush(reason, nr_invalidate);
542 } else { 541 } else {
543 /* Full flush. */ 542 /* Full flush. */
544 local_flush_tlb(); 543 local_flush_tlb();
@@ -623,12 +622,13 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
623static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33; 622static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33;
624 623
625void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, 624void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
626 unsigned long end, unsigned long vmflag) 625 unsigned long end, unsigned int stride_shift)
627{ 626{
628 int cpu; 627 int cpu;
629 628
630 struct flush_tlb_info info __aligned(SMP_CACHE_BYTES) = { 629 struct flush_tlb_info info __aligned(SMP_CACHE_BYTES) = {
631 .mm = mm, 630 .mm = mm,
631 .stride_shift = stride_shift,
632 }; 632 };
633 633
634 cpu = get_cpu(); 634 cpu = get_cpu();
@@ -638,8 +638,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
638 638
639 /* Should we flush just the requested range? */ 639 /* Should we flush just the requested range? */
640 if ((end != TLB_FLUSH_ALL) && 640 if ((end != TLB_FLUSH_ALL) &&
641 !(vmflag & VM_HUGETLB) && 641 ((end - start) >> stride_shift) <= tlb_single_page_flush_ceiling) {
642 ((end - start) >> PAGE_SHIFT) <= tlb_single_page_flush_ceiling) {
643 info.start = start; 642 info.start = start;
644 info.end = end; 643 info.end = end;
645 } else { 644 } else {
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
index cf2af04b34b9..532c29276fce 100644
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -8,6 +8,7 @@
8 */ 8 */
9 9
10#include <linux/pagemap.h> 10#include <linux/pagemap.h>
11#include <linux/hugetlb.h>
11#include <asm/tlb.h> 12#include <asm/tlb.h>
12#include <asm-generic/pgtable.h> 13#include <asm-generic/pgtable.h>
13 14