Skip to content

Commit f0293cd

Browse files
mdchitalepalmer-dabbelt
authored andcommitted
riscv: mm: Implement pmdp_collapse_flush for THP
When THP is enabled, 4K pages are collapsed into a single huge page using the generic pmdp_collapse_flush() which will further use flush_tlb_range() to shoot-down stale TLB entries. Unfortunately, the generic pmdp_collapse_flush() only invalidates cached leaf PTEs using address specific SFENCEs which results in repetitive (or unpredictable) page faults on RISC-V implementations which cache non-leaf PTEs. Provide a RISC-V specific pmdp_collapse_flush() which ensures both cached leaf and non-leaf PTEs are invalidated by using non-address specific SFENCEs as recommended by the RISC-V privileged specification. Fixes: e88b333 ("riscv: mm: add THP support on 64-bit") Signed-off-by: Mayuresh Chitale <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 2f394c0 commit f0293cd

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

arch/riscv/include/asm/pgtable.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,10 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
721721
page_table_check_pmd_set(vma->vm_mm, address, pmdp, pmd);
722722
return __pmd(atomic_long_xchg((atomic_long_t *)pmdp, pmd_val(pmd)));
723723
}
724+
725+
#define pmdp_collapse_flush pmdp_collapse_flush
726+
extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
727+
unsigned long address, pmd_t *pmdp);
724728
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
725729

726730
/*

arch/riscv/mm/pgtable.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,23 @@ int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
8181
}
8282

8383
#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
84+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
85+
pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
86+
unsigned long address, pmd_t *pmdp)
87+
{
88+
pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
89+
90+
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
91+
VM_BUG_ON(pmd_trans_huge(*pmdp));
92+
/*
93+
* When leaf PTE entries (regular pages) are collapsed into a leaf
94+
* PMD entry (huge page), a valid non-leaf PTE is converted into a
95+
* valid leaf PTE at the level 1 page table. Since the sfence.vma
96+
* forms that specify an address only apply to leaf PTEs, we need a
97+
* global flush here. collapse_huge_page() assumes these flushes are
98+
* eager, so just do the fence here.
99+
*/
100+
flush_tlb_mm(vma->vm_mm);
101+
return pmd;
102+
}
103+
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */

0 commit comments

Comments
 (0)