114 lines
3.3 KiB
Diff
114 lines
3.3 KiB
Diff
From 7ac6508c4db81eced5f6e3d7c8913af1da6cf110 Mon Sep 17 00:00:00 2001
|
|
From: Rik van Riel <riel@surriel.com>
|
|
Date: Wed, 5 Feb 2025 23:43:22 -0500
|
|
Subject: x86/mm: consolidate full flush threshold decision
|
|
|
|
Reduce code duplication by consolidating the decision point
|
|
for whether to do individual invalidations or a full flush
|
|
inside get_flush_tlb_info.
|
|
|
|
Signed-off-by: Rik van Riel <riel@surriel.com>
|
|
Suggested-by: Dave Hansen <dave.hansen@intel.com>
|
|
---
|
|
arch/x86/mm/tlb.c | 56 ++++++++++++++++++++++++++---------------------
|
|
1 file changed, 31 insertions(+), 25 deletions(-)
|
|
|
|
--- a/arch/x86/mm/tlb.c
|
|
+++ b/arch/x86/mm/tlb.c
|
|
@@ -1000,8 +1000,13 @@ static struct flush_tlb_info *get_flush_
|
|
BUG_ON(this_cpu_inc_return(flush_tlb_info_idx) != 1);
|
|
#endif
|
|
|
|
- info->start = start;
|
|
- info->end = end;
|
|
+ /*
|
|
+ * Round the start and end addresses to the page size specified
|
|
+ * by the stride shift. This ensures partial pages at the end of
|
|
+ * a range get fully invalidated.
|
|
+ */
|
|
+ info->start = round_down(start, 1 << stride_shift);
|
|
+ info->end = round_up(end, 1 << stride_shift);
|
|
info->mm = mm;
|
|
info->stride_shift = stride_shift;
|
|
info->freed_tables = freed_tables;
|
|
@@ -1009,6 +1014,19 @@ static struct flush_tlb_info *get_flush_
|
|
info->initiating_cpu = smp_processor_id();
|
|
info->trim_cpumask = 0;
|
|
|
|
+ WARN_ONCE(start != info->start || end != info->end,
|
|
+ "TLB flush not stride %x aligned. Start %lx, end %lx\n",
|
|
+ 1 << stride_shift, start, end);
|
|
+
|
|
+ /*
|
|
+ * If the number of flushes is so large that a full flush
|
|
+ * would be faster, do a full flush.
|
|
+ */
|
|
+ if ((end - start) >> stride_shift > tlb_single_page_flush_ceiling) {
|
|
+ info->start = 0;
|
|
+ info->end = TLB_FLUSH_ALL;
|
|
+ }
|
|
+
|
|
return info;
|
|
}
|
|
|
|
@@ -1026,17 +1044,8 @@ void flush_tlb_mm_range(struct mm_struct
|
|
bool freed_tables)
|
|
{
|
|
struct flush_tlb_info *info;
|
|
+ int cpu = get_cpu();
|
|
u64 new_tlb_gen;
|
|
- int cpu;
|
|
-
|
|
- cpu = get_cpu();
|
|
-
|
|
- /* Should we flush just the requested range? */
|
|
- if ((end == TLB_FLUSH_ALL) ||
|
|
- ((end - start) >> stride_shift) > tlb_single_page_flush_ceiling) {
|
|
- start = 0;
|
|
- end = TLB_FLUSH_ALL;
|
|
- }
|
|
|
|
/* This is also a barrier that synchronizes with switch_mm(). */
|
|
new_tlb_gen = inc_mm_tlb_gen(mm);
|
|
@@ -1089,22 +1098,19 @@ static void do_kernel_range_flush(void *
|
|
|
|
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
|
{
|
|
- /* Balance as user space task's flush, a bit conservative */
|
|
- if (end == TLB_FLUSH_ALL ||
|
|
- (end - start) > tlb_single_page_flush_ceiling << PAGE_SHIFT) {
|
|
- on_each_cpu(do_flush_tlb_all, NULL, 1);
|
|
- } else {
|
|
- struct flush_tlb_info *info;
|
|
+ struct flush_tlb_info *info;
|
|
+
|
|
+ guard(preempt)();
|
|
|
|
- preempt_disable();
|
|
- info = get_flush_tlb_info(NULL, start, end, 0, false,
|
|
- TLB_GENERATION_INVALID);
|
|
+ info = get_flush_tlb_info(NULL, start, end, PAGE_SHIFT, false,
|
|
+ TLB_GENERATION_INVALID);
|
|
|
|
+ if (info->end == TLB_FLUSH_ALL)
|
|
+ on_each_cpu(do_flush_tlb_all, NULL, 1);
|
|
+ else
|
|
on_each_cpu(do_kernel_range_flush, info, 1);
|
|
|
|
- put_flush_tlb_info();
|
|
- preempt_enable();
|
|
- }
|
|
+ put_flush_tlb_info();
|
|
}
|
|
|
|
/*
|
|
@@ -1276,7 +1282,7 @@ void arch_tlbbatch_flush(struct arch_tlb
|
|
|
|
int cpu = get_cpu();
|
|
|
|
- info = get_flush_tlb_info(NULL, 0, TLB_FLUSH_ALL, 0, false,
|
|
+ info = get_flush_tlb_info(NULL, 0, TLB_FLUSH_ALL, PAGE_SHIFT, false,
|
|
TLB_GENERATION_INVALID);
|
|
/*
|
|
* flush_tlb_multi() is not optimized for the common case in which only
|