Skip to content

Commit 5b3f891

Browse files
Ryan Robertswilldeacon
authored andcommitted
arm64: hugetlb: Refine tlb maintenance scope
When operating on contiguous blocks of ptes (or pmds) for some hugetlb sizes, we must honour break-before-make requirements and clear down the block to invalid state in the pgtable then invalidate the relevant tlb entries before making the pgtable entries valid again. However, the tlb maintenance is currently always done assuming the worst case stride (PAGE_SIZE), last_level (false) and tlb_level (TLBI_TTL_UNKNOWN). We can do much better with the hinting; In reality, we know the stride from the huge_pte pgsize, we are always operating only on the last level, and we always know the tlb_level, again based on pgsize. So let's start providing these hints. Additionally, avoid tlb maintenace in set_huge_pte_at(). Break-before-make is only required if we are transitioning the contiguous pte block from valid -> valid. So let's elide the clear-and-flush ("break") if the pte range was previously invalid. Reviewed-by: Catalin Marinas <[email protected]> Reviewed-by: Anshuman Khandual <[email protected]> Signed-off-by: Ryan Roberts <[email protected]> Tested-by: Luiz Capitulino <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 29cb805 commit 5b3f891

File tree

2 files changed

+25
-13
lines changed

2 files changed

+25
-13
lines changed

arch/arm64/include/asm/hugetlb.h

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,29 +69,38 @@ extern void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
6969

7070
#include <asm-generic/hugetlb.h>
7171

72-
#define __HAVE_ARCH_FLUSH_HUGETLB_TLB_RANGE
73-
static inline void flush_hugetlb_tlb_range(struct vm_area_struct *vma,
74-
unsigned long start,
75-
unsigned long end)
72+
static inline void __flush_hugetlb_tlb_range(struct vm_area_struct *vma,
73+
unsigned long start,
74+
unsigned long end,
75+
unsigned long stride,
76+
bool last_level)
7677
{
77-
unsigned long stride = huge_page_size(hstate_vma(vma));
78-
7978
switch (stride) {
8079
#ifndef __PAGETABLE_PMD_FOLDED
8180
case PUD_SIZE:
82-
__flush_tlb_range(vma, start, end, PUD_SIZE, false, 1);
81+
__flush_tlb_range(vma, start, end, PUD_SIZE, last_level, 1);
8382
break;
8483
#endif
8584
case CONT_PMD_SIZE:
8685
case PMD_SIZE:
87-
__flush_tlb_range(vma, start, end, PMD_SIZE, false, 2);
86+
__flush_tlb_range(vma, start, end, PMD_SIZE, last_level, 2);
8887
break;
8988
case CONT_PTE_SIZE:
90-
__flush_tlb_range(vma, start, end, PAGE_SIZE, false, 3);
89+
__flush_tlb_range(vma, start, end, PAGE_SIZE, last_level, 3);
9190
break;
9291
default:
93-
__flush_tlb_range(vma, start, end, PAGE_SIZE, false, TLBI_TTL_UNKNOWN);
92+
__flush_tlb_range(vma, start, end, PAGE_SIZE, last_level, TLBI_TTL_UNKNOWN);
9493
}
9594
}
9695

96+
#define __HAVE_ARCH_FLUSH_HUGETLB_TLB_RANGE
97+
static inline void flush_hugetlb_tlb_range(struct vm_area_struct *vma,
98+
unsigned long start,
99+
unsigned long end)
100+
{
101+
unsigned long stride = huge_page_size(hstate_vma(vma));
102+
103+
__flush_hugetlb_tlb_range(vma, start, end, stride, false);
104+
}
105+
97106
#endif /* __ASM_HUGETLB_H */

arch/arm64/mm/hugetlbpage.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,9 @@ static pte_t get_clear_contig_flush(struct mm_struct *mm,
183183
{
184184
pte_t orig_pte = get_clear_contig(mm, addr, ptep, pgsize, ncontig);
185185
struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
186+
unsigned long end = addr + (pgsize * ncontig);
186187

187-
flush_tlb_range(&vma, addr, addr + (pgsize * ncontig));
188+
__flush_hugetlb_tlb_range(&vma, addr, end, pgsize, true);
188189
return orig_pte;
189190
}
190191

@@ -209,7 +210,7 @@ static void clear_flush(struct mm_struct *mm,
209210
for (i = 0; i < ncontig; i++, addr += pgsize, ptep++)
210211
__ptep_get_and_clear(mm, addr, ptep);
211212

212-
flush_tlb_range(&vma, saddr, addr);
213+
__flush_hugetlb_tlb_range(&vma, saddr, addr, pgsize, true);
213214
}
214215

215216
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
@@ -238,7 +239,9 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
238239
dpfn = pgsize >> PAGE_SHIFT;
239240
hugeprot = pte_pgprot(pte);
240241

241-
clear_flush(mm, addr, ptep, pgsize, ncontig);
242+
/* Only need to "break" if transitioning valid -> valid. */
243+
if (pte_valid(__ptep_get(ptep)))
244+
clear_flush(mm, addr, ptep, pgsize, ncontig);
242245

243246
for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn)
244247
__set_ptes(mm, addr, ptep, pfn_pte(pfn, hugeprot), 1);

0 commit comments

Comments
 (0)