Skip to content

Commit 4a4c459

Browse files
Merge patch series "riscv, mm: detect svnapot cpu support at runtime"
Qinglin Pan <panqinglin00@gmail.com> says: Svnapot is a RISC-V extension for marking contiguous 4K pages as a non-4K page. This patch set is for using Svnapot in hugetlb fs and huge vmap. This patchset adds a Kconfig item for using Svnapot in "Platform type"->"SVNAPOT extension support". Its default value is on, and people can set it off if they don't allow kernel to detect Svnapot hardware support and leverage it. Tested on: - qemu rv64 with "Svnapot support" off and svnapot=true. - qemu rv64 with "Svnapot support" on and svnapot=true. - qemu rv64 with "Svnapot support" off and svnapot=false. - qemu rv64 with "Svnapot support" on and svnapot=false. * b4-shazam-merge: riscv: mm: support Svnapot in huge vmap riscv: mm: support Svnapot in hugetlb page riscv: mm: modify pte format for Svnapot Link: https://lore.kernel.org/r/20230209131647.17245-1-panqinglin00@gmail.com [Palmer: fix up the feature ordering in the merge] Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
2 parents fe15c26 + ce17347 commit 4a4c459

10 files changed

Lines changed: 489 additions & 9 deletions

File tree

arch/riscv/Kconfig

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ config RISCV
4444
select ARCH_USE_QUEUED_RWLOCKS
4545
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
4646
select ARCH_WANT_FRAME_POINTERS
47-
select ARCH_WANT_GENERAL_HUGETLB
47+
select ARCH_WANT_GENERAL_HUGETLB if !RISCV_ISA_SVNAPOT
4848
select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
4949
select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
5050
select ARCH_WANT_LD_ORPHAN_WARN if !XIP_KERNEL
@@ -398,6 +398,25 @@ config RISCV_ISA_C
398398

399399
If you don't know what to do here, say Y.
400400

401+
config RISCV_ISA_SVNAPOT
402+
bool "SVNAPOT extension support"
403+
depends on 64BIT && MMU
404+
default y
405+
select RISCV_ALTERNATIVE
406+
help
407+
Allow kernel to detect the SVNAPOT ISA-extension dynamically at boot
408+
time and enable its usage.
409+
410+
The SVNAPOT extension is used to mark contiguous PTEs as a range
411+
of contiguous virtual-to-physical translations for a naturally
412+
aligned power-of-2 (NAPOT) granularity larger than the base 4KB page
413+
size. When HUGETLBFS is also selected this option unconditionally
414+
allocates some memory for each NAPOT page size supported by the kernel.
415+
When optimizing for low memory consumption and for platforms without
416+
the SVNAPOT extension, it may be better to say N here.
417+
418+
If you don't know what to do here, say Y.
419+
401420
config RISCV_ISA_SVPBMT
402421
bool "SVPBMT extension support"
403422
depends on 64BIT && MMU

arch/riscv/include/asm/hugetlb.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#ifndef _ASM_RISCV_HUGETLB_H
33
#define _ASM_RISCV_HUGETLB_H
44

5-
#include <asm-generic/hugetlb.h>
65
#include <asm/page.h>
76

87
static inline void arch_clear_hugepage_flags(struct page *page)
@@ -11,4 +10,37 @@ static inline void arch_clear_hugepage_flags(struct page *page)
1110
}
1211
#define arch_clear_hugepage_flags arch_clear_hugepage_flags
1312

13+
#ifdef CONFIG_RISCV_ISA_SVNAPOT
14+
#define __HAVE_ARCH_HUGE_PTE_CLEAR
15+
void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
16+
pte_t *ptep, unsigned long sz);
17+
18+
#define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT
19+
void set_huge_pte_at(struct mm_struct *mm,
20+
unsigned long addr, pte_t *ptep, pte_t pte);
21+
22+
#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
23+
pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
24+
unsigned long addr, pte_t *ptep);
25+
26+
#define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH
27+
pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
28+
unsigned long addr, pte_t *ptep);
29+
30+
#define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT
31+
void huge_ptep_set_wrprotect(struct mm_struct *mm,
32+
unsigned long addr, pte_t *ptep);
33+
34+
#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS
35+
int huge_ptep_set_access_flags(struct vm_area_struct *vma,
36+
unsigned long addr, pte_t *ptep,
37+
pte_t pte, int dirty);
38+
39+
pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags);
40+
#define arch_make_huge_pte arch_make_huge_pte
41+
42+
#endif /*CONFIG_RISCV_ISA_SVNAPOT*/
43+
44+
#include <asm-generic/hugetlb.h>
45+
1446
#endif /* _ASM_RISCV_HUGETLB_H */

arch/riscv/include/asm/hwcap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#define RISCV_ISA_EXT_ZBB 30
4343
#define RISCV_ISA_EXT_ZICBOM 31
4444
#define RISCV_ISA_EXT_ZIHINTPAUSE 32
45+
#define RISCV_ISA_EXT_SVNAPOT 33
4546

4647
#define RISCV_ISA_EXT_MAX 64
4748
#define RISCV_ISA_EXT_NAME_LEN_MAX 32

arch/riscv/include/asm/page.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
1717
#define PAGE_MASK (~(PAGE_SIZE - 1))
1818

19-
#ifdef CONFIG_64BIT
20-
#define HUGE_MAX_HSTATE 2
21-
#else
22-
#define HUGE_MAX_HSTATE 1
23-
#endif
2419
#define HPAGE_SHIFT PMD_SHIFT
2520
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
2621
#define HPAGE_MASK (~(HPAGE_SIZE - 1))

arch/riscv/include/asm/pgtable-64.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,40 @@ typedef struct {
7878
*/
7979
#define _PAGE_PFN_MASK GENMASK(53, 10)
8080

81+
/*
82+
* [63] Svnapot definitions:
83+
* 0 Svnapot disabled
84+
* 1 Svnapot enabled
85+
*/
86+
#define _PAGE_NAPOT_SHIFT 63
87+
#define _PAGE_NAPOT BIT(_PAGE_NAPOT_SHIFT)
88+
/*
89+
* Only 64KB (order 4) napot ptes supported.
90+
*/
91+
#define NAPOT_CONT_ORDER_BASE 4
92+
enum napot_cont_order {
93+
NAPOT_CONT64KB_ORDER = NAPOT_CONT_ORDER_BASE,
94+
NAPOT_ORDER_MAX,
95+
};
96+
97+
#define for_each_napot_order(order) \
98+
for (order = NAPOT_CONT_ORDER_BASE; order < NAPOT_ORDER_MAX; order++)
99+
#define for_each_napot_order_rev(order) \
100+
for (order = NAPOT_ORDER_MAX - 1; \
101+
order >= NAPOT_CONT_ORDER_BASE; order--)
102+
#define napot_cont_order(val) (__builtin_ctzl((val.pte >> _PAGE_PFN_SHIFT) << 1))
103+
104+
#define napot_cont_shift(order) ((order) + PAGE_SHIFT)
105+
#define napot_cont_size(order) BIT(napot_cont_shift(order))
106+
#define napot_cont_mask(order) (~(napot_cont_size(order) - 1UL))
107+
#define napot_pte_num(order) BIT(order)
108+
109+
#ifdef CONFIG_RISCV_ISA_SVNAPOT
110+
#define HUGE_MAX_HSTATE (2 + (NAPOT_ORDER_MAX - NAPOT_CONT_ORDER_BASE))
111+
#else
112+
#define HUGE_MAX_HSTATE 2
113+
#endif
114+
81115
/*
82116
* [62:61] Svpbmt Memory Type definitions:
83117
*

arch/riscv/include/asm/pgtable.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,47 @@ static inline pte_t pud_pte(pud_t pud)
264264
return __pte(pud_val(pud));
265265
}
266266

267+
#ifdef CONFIG_RISCV_ISA_SVNAPOT
268+
269+
static __always_inline bool has_svnapot(void)
270+
{
271+
return riscv_has_extension_likely(RISCV_ISA_EXT_SVNAPOT);
272+
}
273+
274+
static inline unsigned long pte_napot(pte_t pte)
275+
{
276+
return pte_val(pte) & _PAGE_NAPOT;
277+
}
278+
279+
static inline pte_t pte_mknapot(pte_t pte, unsigned int order)
280+
{
281+
int pos = order - 1 + _PAGE_PFN_SHIFT;
282+
unsigned long napot_bit = BIT(pos);
283+
unsigned long napot_mask = ~GENMASK(pos, _PAGE_PFN_SHIFT);
284+
285+
return __pte((pte_val(pte) & napot_mask) | napot_bit | _PAGE_NAPOT);
286+
}
287+
288+
#else
289+
290+
static __always_inline bool has_svnapot(void) { return false; }
291+
292+
static inline unsigned long pte_napot(pte_t pte)
293+
{
294+
return 0;
295+
}
296+
297+
#endif /* CONFIG_RISCV_ISA_SVNAPOT */
298+
267299
/* Yields the page frame number (PFN) of a page table entry */
268300
static inline unsigned long pte_pfn(pte_t pte)
269301
{
270-
return __page_val_to_pfn(pte_val(pte));
302+
unsigned long res = __page_val_to_pfn(pte_val(pte));
303+
304+
if (has_svnapot() && pte_napot(pte))
305+
res = res & (res - 1UL);
306+
307+
return res;
271308
}
272309

273310
#define pte_page(x) pfn_to_page(pte_pfn(x))

arch/riscv/include/asm/vmalloc.h

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,65 @@ static inline bool arch_vmap_pmd_supported(pgprot_t prot)
1717
return true;
1818
}
1919

20-
#endif
20+
#ifdef CONFIG_RISCV_ISA_SVNAPOT
21+
#include <linux/pgtable.h>
2122

23+
#define arch_vmap_pte_range_map_size arch_vmap_pte_range_map_size
24+
static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr, unsigned long end,
25+
u64 pfn, unsigned int max_page_shift)
26+
{
27+
unsigned long map_size = PAGE_SIZE;
28+
unsigned long size, order;
29+
30+
if (!has_svnapot())
31+
return map_size;
32+
33+
for_each_napot_order_rev(order) {
34+
if (napot_cont_shift(order) > max_page_shift)
35+
continue;
36+
37+
size = napot_cont_size(order);
38+
if (end - addr < size)
39+
continue;
40+
41+
if (!IS_ALIGNED(addr, size))
42+
continue;
43+
44+
if (!IS_ALIGNED(PFN_PHYS(pfn), size))
45+
continue;
46+
47+
map_size = size;
48+
break;
49+
}
50+
51+
return map_size;
52+
}
53+
54+
#define arch_vmap_pte_supported_shift arch_vmap_pte_supported_shift
55+
static inline int arch_vmap_pte_supported_shift(unsigned long size)
56+
{
57+
int shift = PAGE_SHIFT;
58+
unsigned long order;
59+
60+
if (!has_svnapot())
61+
return shift;
62+
63+
WARN_ON_ONCE(size >= PMD_SIZE);
64+
65+
for_each_napot_order_rev(order) {
66+
if (napot_cont_size(order) > size)
67+
continue;
68+
69+
if (!IS_ALIGNED(size, napot_cont_size(order)))
70+
continue;
71+
72+
shift = napot_cont_shift(order);
73+
break;
74+
}
75+
76+
return shift;
77+
}
78+
79+
#endif /* CONFIG_RISCV_ISA_SVNAPOT */
80+
#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
2281
#endif /* _ASM_RISCV_VMALLOC_H */

arch/riscv/kernel/cpu.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = {
191191
__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
192192
__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
193193
__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
194+
__RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
194195
__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
195196
__RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX),
196197
};

arch/riscv/kernel/cpufeature.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ void __init riscv_fill_hwcap(void)
224224
SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF);
225225
SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC);
226226
SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL);
227+
SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT);
227228
SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT);
228229
SET_ISA_EXT_MAP("zbb", RISCV_ISA_EXT_ZBB);
229230
SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM);

0 commit comments

Comments
 (0)