diff options
author | Peter Zijlstra <peterz@infradead.org> | 2018-08-26 06:56:48 -0400 |
---|---|---|
committer | Peter Zijlstra <peterz@infradead.org> | 2018-10-09 10:51:11 -0400 |
commit | a31acd3ee8f7dbc0370bdf4a4bfef7a8c13c7542 (patch) | |
tree | fe6035ec072385441ded002ba945960ba1ddc034 | |
parent | a5b966ae42a70b194b03eaa5eaea70d8b3790c40 (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.h | 21 | ||||
-rw-r--r-- | arch/x86/include/asm/tlbflush.h | 12 | ||||
-rw-r--r-- | arch/x86/kernel/ldt.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/vm86_32.c | 2 | ||||
-rw-r--r-- | arch/x86/mm/tlb.c | 17 | ||||
-rw-r--r-- | mm/pgtable-generic.c | 1 |
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) \ | 9 | static 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 | ||
13 | static 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 | ||
559 | extern void flush_tlb_all(void); | 563 | extern void flush_tlb_all(void); |
560 | extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, | 564 | extern 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); |
562 | extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); | 566 | extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); |
563 | 567 | ||
564 | static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long a) | 568 | static 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 | ||
569 | void native_flush_tlb_others(const struct cpumask *cpumask, | 573 | void 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); |
200 | out: | 200 | out: |
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, | |||
623 | static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33; | 622 | static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33; |
624 | 623 | ||
625 | void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, | 624 | void 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 | ||