Skip to content

Commit 9e11306

Browse files
Alexandre Ghitipalmer-dabbelt
authored andcommitted
riscv: Improve flush_tlb_range() for hugetlb pages
flush_tlb_range() uses a fixed stride of PAGE_SIZE and in its current form, when a hugetlb mapping needs to be flushed, flush_tlb_range() flushes the whole tlb: so set a stride of the size of the hugetlb mapping in order to only flush the hugetlb mapping. However, if the hugepage is a NAPOT region, all PTEs that constitute this mapping must be invalidated, so the stride size must actually be the size of the PTE. Note that THPs are directly handled by flush_pmd_tlb_range(). Signed-off-by: Alexandre Ghiti <[email protected]> Reviewed-by: Samuel Holland <[email protected]> Tested-by: Lad Prabhakar <[email protected]> # On RZ/Five SMARC Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 114d5c8 commit 9e11306

File tree

1 file changed

+28
-1
lines changed

1 file changed

+28
-1
lines changed

arch/riscv/mm/tlbflush.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/mm.h>
44
#include <linux/smp.h>
55
#include <linux/sched.h>
6+
#include <linux/hugetlb.h>
67
#include <asm/sbi.h>
78
#include <asm/mmu_context.h>
89

@@ -147,7 +148,33 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
147148
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
148149
unsigned long end)
149150
{
150-
__flush_tlb_range(vma->vm_mm, start, end - start, PAGE_SIZE);
151+
unsigned long stride_size;
152+
153+
if (!is_vm_hugetlb_page(vma)) {
154+
stride_size = PAGE_SIZE;
155+
} else {
156+
stride_size = huge_page_size(hstate_vma(vma));
157+
158+
/*
159+
* As stated in the privileged specification, every PTE in a
160+
* NAPOT region must be invalidated, so reset the stride in that
161+
* case.
162+
*/
163+
if (has_svnapot()) {
164+
if (stride_size >= PGDIR_SIZE)
165+
stride_size = PGDIR_SIZE;
166+
else if (stride_size >= P4D_SIZE)
167+
stride_size = P4D_SIZE;
168+
else if (stride_size >= PUD_SIZE)
169+
stride_size = PUD_SIZE;
170+
else if (stride_size >= PMD_SIZE)
171+
stride_size = PMD_SIZE;
172+
else
173+
stride_size = PAGE_SIZE;
174+
}
175+
}
176+
177+
__flush_tlb_range(vma->vm_mm, start, end - start, stride_size);
151178
}
152179
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
153180
void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,

0 commit comments

Comments
 (0)