Message ID | 20221005112926.3043280-2-panqinglin2020@iscas.ac.cn (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | riscv, mm: detect svnapot cpu support at runtime | expand |
On Wed, Oct 05, 2022 at 07:29:23PM +0800, panqinglin2020@iscas.ac.cn wrote: > From: Qinglin Pan <panqinglin2020@iscas.ac.cn> > > Add one static key to enable/disable svnapot support, enable this static > key when "svnapot" is in the "riscv,isa" field of fdt and SVNAPOT compile > option is set. It will influence the behavior of has_svnapot. All code > dependent on svnapot should make sure that has_svnapot return true firstly. > > Modify PTE definition for Svnapot, and creates some functions in pgtable.h > to mark a PTE as napot and check if it is a Svnapot PTE. Until now, only > 64KB napot size is supported in spec, so some macros has only 64KB version. > > Signed-off-by: Qinglin Pan <panqinglin2020@iscas.ac.cn> > > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > index d557cc50295d..69e88ab8fafd 100644 > --- a/arch/riscv/Kconfig > +++ b/arch/riscv/Kconfig > @@ -383,6 +383,20 @@ config RISCV_ISA_C > > If you don't know what to do here, say Y. > > +config RISCV_ISA_SVNAPOT > + bool "SVNAPOT extension support" > + depends on 64BIT && MMU > + select RISCV_ALTERNATIVE > + default y > + help > + Allow kernel to detect SVNAPOT ISA-extension dynamically in boot time > + and enable its usage. > + > + SVNAPOT extension helps to mark contiguous PTEs as a range > + of contiguous virtual-to-physical translations, with a naturally > + aligned power-of-2 (NAPOT) granularity larger than the base 4KB page > + size. > + > config RISCV_ISA_SVPBMT > bool "SVPBMT extension support" > depends on 64BIT && MMU > diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h > index 6f59ec64175e..2c45cc0d5d3c 100644 > --- a/arch/riscv/include/asm/hwcap.h > +++ b/arch/riscv/include/asm/hwcap.h > @@ -54,6 +54,7 @@ extern unsigned long elf_hwcap; > */ > enum riscv_isa_ext_id { > RISCV_ISA_EXT_SSCOFPMF = RISCV_ISA_EXT_BASE, > + RISCV_ISA_EXT_SVNAPOT, > RISCV_ISA_EXT_SVPBMT, > RISCV_ISA_EXT_ZICBOM, > RISCV_ISA_EXT_ZIHINTPAUSE, > @@ -68,6 +69,7 @@ enum riscv_isa_ext_id { > */ > enum riscv_isa_ext_key { > RISCV_ISA_EXT_KEY_FPU, /* For 'F' and 'D' */ > + RISCV_ISA_EXT_KEY_SVNAPOT, > RISCV_ISA_EXT_KEY_ZIHINTPAUSE, > RISCV_ISA_EXT_KEY_MAX, > }; > @@ -88,6 +90,8 @@ static __always_inline int riscv_isa_ext2key(int num) > return RISCV_ISA_EXT_KEY_FPU; > case RISCV_ISA_EXT_d: > return RISCV_ISA_EXT_KEY_FPU; > + case RISCV_ISA_EXT_SVNAPOT: > + return RISCV_ISA_EXT_KEY_SVNAPOT; > case RISCV_ISA_EXT_ZIHINTPAUSE: > return RISCV_ISA_EXT_KEY_ZIHINTPAUSE; > default: > diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h > index dc42375c2357..1cd0ffbfbdaa 100644 > --- a/arch/riscv/include/asm/pgtable-64.h > +++ b/arch/riscv/include/asm/pgtable-64.h > @@ -74,6 +74,19 @@ typedef struct { > */ > #define _PAGE_PFN_MASK GENMASK(53, 10) > > +/* > + * [63] Svnapot definitions: > + * 0 Svnapot disabled > + * 1 Svnapot enabled > + */ > +#define _PAGE_NAPOT_SHIFT 63 > +#define _PAGE_NAPOT BIT(_PAGE_NAPOT_SHIFT) > +#define NAPOT_CONT64KB_ORDER 4UL > +#define NAPOT_CONT64KB_SHIFT (NAPOT_CONT64KB_ORDER + PAGE_SHIFT) > +#define NAPOT_CONT64KB_SIZE BIT(NAPOT_CONT64KB_SHIFT) > +#define NAPOT_CONT64KB_MASK (NAPOT_CONT64KB_SIZE - 1UL) > +#define NAPOT_64KB_PTE_NUM BIT(NAPOT_CONT64KB_ORDER) I still wonder if we shouldn't future-proof a bit with something like /* * Only 64KB (order 4) napot ptes supported. */ #define napot_cont_order(pte) 4 #define napot_cont_shift(order) ((order) + PAGE_SHIFT) #define napot_cont_size(order) BIT(napot_cont_shift(order)) #define napot_cont_mask(order) BIT(napot_cont_size(order) - 1) #define napot_pte_num(order) BIT(order) > + > /* > * [62:61] Svpbmt Memory Type definitions: > * > diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h > index 7ec936910a96..a8cab063fd05 100644 > --- a/arch/riscv/include/asm/pgtable.h > +++ b/arch/riscv/include/asm/pgtable.h > @@ -6,10 +6,12 @@ > #ifndef _ASM_RISCV_PGTABLE_H > #define _ASM_RISCV_PGTABLE_H > > +#include <linux/jump_label.h> > #include <linux/mmzone.h> > #include <linux/sizes.h> > > #include <asm/pgtable-bits.h> > +#include <asm/hwcap.h> > > #ifndef CONFIG_MMU > #define KERNEL_LINK_ADDR PAGE_OFFSET > @@ -264,10 +266,38 @@ static inline pte_t pud_pte(pud_t pud) > return __pte(pud_val(pud)); > } > > +static __always_inline bool has_svnapot(void) > +{ > + return static_branch_likely(&riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_SVNAPOT]); > +} > + > +#ifdef CONFIG_RISCV_ISA_SVNAPOT > + > +static inline unsigned long pte_napot(pte_t pte) > +{ > + return pte_val(pte) & _PAGE_NAPOT; > +} > + > +static inline pte_t pte_mknapot(pte_t pte, unsigned int order) > +{ > + int pos = order - 1 + _PAGE_PFN_SHIFT; > + unsigned long napot_bit = BIT(pos); > + unsigned long napot_mask = ~GENMASK(pos, _PAGE_PFN_SHIFT); > + > + return __pte((pte_val(pte) & napot_mask) | napot_bit | _PAGE_NAPOT); > +} > +#endif /* CONFIG_RISCV_ISA_SVNAPOT */ > + > /* Yields the page frame number (PFN) of a page table entry */ > static inline unsigned long pte_pfn(pte_t pte) > { > - return __page_val_to_pfn(pte_val(pte)); > + unsigned long val = pte_val(pte); > + unsigned long res = __page_val_to_pfn(val); > + > + if (has_svnapot()) > + res = res & (res - (val >> _PAGE_NAPOT_SHIFT)); nit: res &= ... This is much easier to read. I presume the static key is doing its thing and the instructions come out the same as with the errata framework? A comment explaining what it's doing and how it works would be good for new readers and for myself, since I'll probably forget by next week... > + > + return res; > } > > #define pte_page(x) pfn_to_page(pte_pfn(x)) > diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c > index 0be8a2403212..d2a61122c595 100644 > --- a/arch/riscv/kernel/cpu.c > +++ b/arch/riscv/kernel/cpu.c > @@ -96,6 +96,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = { > __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), > __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), > __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), > + __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT), > __RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX), > }; > > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c > index 553d755483ed..bc247844e42d 100644 > --- a/arch/riscv/kernel/cpufeature.c > +++ b/arch/riscv/kernel/cpufeature.c > @@ -204,6 +204,7 @@ void __init riscv_fill_hwcap(void) > SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM); > SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE); > SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC); > + SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT); > } > #undef SET_ISA_EXT_MAP > } > -- > 2.35.1 > Otherwise Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
On 10/5/22 10:17 PM, Andrew Jones wrote: > On Wed, Oct 05, 2022 at 07:29:23PM +0800, panqinglin2020@iscas.ac.cn wrote: >> From: Qinglin Pan <panqinglin2020@iscas.ac.cn> >> >> Add one static key to enable/disable svnapot support, enable this static >> key when "svnapot" is in the "riscv,isa" field of fdt and SVNAPOT compile >> option is set. It will influence the behavior of has_svnapot. All code >> dependent on svnapot should make sure that has_svnapot return true firstly. >> >> Modify PTE definition for Svnapot, and creates some functions in pgtable.h >> to mark a PTE as napot and check if it is a Svnapot PTE. Until now, only >> 64KB napot size is supported in spec, so some macros has only 64KB version. >> >> Signed-off-by: Qinglin Pan <panqinglin2020@iscas.ac.cn> >> >> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig >> index d557cc50295d..69e88ab8fafd 100644 >> --- a/arch/riscv/Kconfig >> +++ b/arch/riscv/Kconfig >> @@ -383,6 +383,20 @@ config RISCV_ISA_C >> >> If you don't know what to do here, say Y. >> >> +config RISCV_ISA_SVNAPOT >> + bool "SVNAPOT extension support" >> + depends on 64BIT && MMU >> + select RISCV_ALTERNATIVE >> + default y >> + help >> + Allow kernel to detect SVNAPOT ISA-extension dynamically in boot time >> + and enable its usage. >> + >> + SVNAPOT extension helps to mark contiguous PTEs as a range >> + of contiguous virtual-to-physical translations, with a naturally >> + aligned power-of-2 (NAPOT) granularity larger than the base 4KB page >> + size. >> + >> config RISCV_ISA_SVPBMT >> bool "SVPBMT extension support" >> depends on 64BIT && MMU >> diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h >> index 6f59ec64175e..2c45cc0d5d3c 100644 >> --- a/arch/riscv/include/asm/hwcap.h >> +++ b/arch/riscv/include/asm/hwcap.h >> @@ -54,6 +54,7 @@ extern unsigned long elf_hwcap; >> */ >> enum riscv_isa_ext_id { >> RISCV_ISA_EXT_SSCOFPMF = RISCV_ISA_EXT_BASE, >> + RISCV_ISA_EXT_SVNAPOT, >> RISCV_ISA_EXT_SVPBMT, >> RISCV_ISA_EXT_ZICBOM, >> RISCV_ISA_EXT_ZIHINTPAUSE, >> @@ -68,6 +69,7 @@ enum riscv_isa_ext_id { >> */ >> enum riscv_isa_ext_key { >> RISCV_ISA_EXT_KEY_FPU, /* For 'F' and 'D' */ >> + RISCV_ISA_EXT_KEY_SVNAPOT, >> RISCV_ISA_EXT_KEY_ZIHINTPAUSE, >> RISCV_ISA_EXT_KEY_MAX, >> }; >> @@ -88,6 +90,8 @@ static __always_inline int riscv_isa_ext2key(int num) >> return RISCV_ISA_EXT_KEY_FPU; >> case RISCV_ISA_EXT_d: >> return RISCV_ISA_EXT_KEY_FPU; >> + case RISCV_ISA_EXT_SVNAPOT: >> + return RISCV_ISA_EXT_KEY_SVNAPOT; >> case RISCV_ISA_EXT_ZIHINTPAUSE: >> return RISCV_ISA_EXT_KEY_ZIHINTPAUSE; >> default: >> diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h >> index dc42375c2357..1cd0ffbfbdaa 100644 >> --- a/arch/riscv/include/asm/pgtable-64.h >> +++ b/arch/riscv/include/asm/pgtable-64.h >> @@ -74,6 +74,19 @@ typedef struct { >> */ >> #define _PAGE_PFN_MASK GENMASK(53, 10) >> >> +/* >> + * [63] Svnapot definitions: >> + * 0 Svnapot disabled >> + * 1 Svnapot enabled >> + */ >> +#define _PAGE_NAPOT_SHIFT 63 >> +#define _PAGE_NAPOT BIT(_PAGE_NAPOT_SHIFT) >> +#define NAPOT_CONT64KB_ORDER 4UL >> +#define NAPOT_CONT64KB_SHIFT (NAPOT_CONT64KB_ORDER + PAGE_SHIFT) >> +#define NAPOT_CONT64KB_SIZE BIT(NAPOT_CONT64KB_SHIFT) >> +#define NAPOT_CONT64KB_MASK (NAPOT_CONT64KB_SIZE - 1UL) >> +#define NAPOT_64KB_PTE_NUM BIT(NAPOT_CONT64KB_ORDER) > > I still wonder if we shouldn't future-proof a bit with something like > > /* > * Only 64KB (order 4) napot ptes supported. > */ > #define napot_cont_order(pte) 4 > > #define napot_cont_shift(order) ((order) + PAGE_SHIFT) > #define napot_cont_size(order) BIT(napot_cont_shift(order)) > #define napot_cont_mask(order) BIT(napot_cont_size(order) - 1) > #define napot_pte_num(order) BIT(order) Maybe we can declare legal napot order in a enum, and use the enum with these macros you have mentioned above. I will try to do this in the v8 patchset. > >> + >> /* >> * [62:61] Svpbmt Memory Type definitions: >> * >> diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h >> index 7ec936910a96..a8cab063fd05 100644 >> --- a/arch/riscv/include/asm/pgtable.h >> +++ b/arch/riscv/include/asm/pgtable.h >> @@ -6,10 +6,12 @@ >> #ifndef _ASM_RISCV_PGTABLE_H >> #define _ASM_RISCV_PGTABLE_H >> >> +#include <linux/jump_label.h> >> #include <linux/mmzone.h> >> #include <linux/sizes.h> >> >> #include <asm/pgtable-bits.h> >> +#include <asm/hwcap.h> >> >> #ifndef CONFIG_MMU >> #define KERNEL_LINK_ADDR PAGE_OFFSET >> @@ -264,10 +266,38 @@ static inline pte_t pud_pte(pud_t pud) >> return __pte(pud_val(pud)); >> } >> >> +static __always_inline bool has_svnapot(void) >> +{ >> + return static_branch_likely(&riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_SVNAPOT]); >> +} >> + >> +#ifdef CONFIG_RISCV_ISA_SVNAPOT >> + >> +static inline unsigned long pte_napot(pte_t pte) >> +{ >> + return pte_val(pte) & _PAGE_NAPOT; >> +} >> + >> +static inline pte_t pte_mknapot(pte_t pte, unsigned int order) >> +{ >> + int pos = order - 1 + _PAGE_PFN_SHIFT; >> + unsigned long napot_bit = BIT(pos); >> + unsigned long napot_mask = ~GENMASK(pos, _PAGE_PFN_SHIFT); >> + >> + return __pte((pte_val(pte) & napot_mask) | napot_bit | _PAGE_NAPOT); >> +} >> +#endif /* CONFIG_RISCV_ISA_SVNAPOT */ >> + >> /* Yields the page frame number (PFN) of a page table entry */ >> static inline unsigned long pte_pfn(pte_t pte) >> { >> - return __page_val_to_pfn(pte_val(pte)); >> + unsigned long val = pte_val(pte); >> + unsigned long res = __page_val_to_pfn(val); >> + >> + if (has_svnapot()) >> + res = res & (res - (val >> _PAGE_NAPOT_SHIFT)); > > nit: res &= ... Will do it in the v8 patchset. > > This is much easier to read. I presume the static key is doing its > thing and the instructions come out the same as with the errata > framework? > > A comment explaining what it's doing and how it works would be good for > new readers and for myself, since I'll probably forget by next week... > Will add a explaining comment for it. >> + >> + return res; >> } >> >> #define pte_page(x) pfn_to_page(pte_pfn(x)) >> diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c >> index 0be8a2403212..d2a61122c595 100644 >> --- a/arch/riscv/kernel/cpu.c >> +++ b/arch/riscv/kernel/cpu.c >> @@ -96,6 +96,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = { >> __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), >> __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), >> __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), >> + __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT), >> __RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX), >> }; >> >> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c >> index 553d755483ed..bc247844e42d 100644 >> --- a/arch/riscv/kernel/cpufeature.c >> +++ b/arch/riscv/kernel/cpufeature.c >> @@ -204,6 +204,7 @@ void __init riscv_fill_hwcap(void) >> SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM); >> SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE); >> SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC); >> + SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT); >> } >> #undef SET_ISA_EXT_MAP >> } >> -- >> 2.35.1 >> > > Otherwise > > Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
On Wed, Oct 05, 2022 at 10:46:36PM +0800, Qinglin Pan wrote: > On 10/5/22 10:17 PM, Andrew Jones wrote: > > On Wed, Oct 05, 2022 at 07:29:23PM +0800, panqinglin2020@iscas.ac.cn wrote: > > > From: Qinglin Pan <panqinglin2020@iscas.ac.cn> > > > diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h > > > index dc42375c2357..1cd0ffbfbdaa 100644 > > > --- a/arch/riscv/include/asm/pgtable-64.h > > > +++ b/arch/riscv/include/asm/pgtable-64.h > > > @@ -74,6 +74,19 @@ typedef struct { > > > */ > > > #define _PAGE_PFN_MASK GENMASK(53, 10) > > > +/* > > > + * [63] Svnapot definitions: > > > + * 0 Svnapot disabled > > > + * 1 Svnapot enabled > > > + */ > > > +#define _PAGE_NAPOT_SHIFT 63 > > > +#define _PAGE_NAPOT BIT(_PAGE_NAPOT_SHIFT) > > > +#define NAPOT_CONT64KB_ORDER 4UL > > > +#define NAPOT_CONT64KB_SHIFT (NAPOT_CONT64KB_ORDER + PAGE_SHIFT) > > > +#define NAPOT_CONT64KB_SIZE BIT(NAPOT_CONT64KB_SHIFT) > > > +#define NAPOT_CONT64KB_MASK (NAPOT_CONT64KB_SIZE - 1UL) > > > +#define NAPOT_64KB_PTE_NUM BIT(NAPOT_CONT64KB_ORDER) > > > > I still wonder if we shouldn't future-proof a bit with something like > > > > /* > > * Only 64KB (order 4) napot ptes supported. > > */ > > #define napot_cont_order(pte) 4 > > > > #define napot_cont_shift(order) ((order) + PAGE_SHIFT) > > #define napot_cont_size(order) BIT(napot_cont_shift(order)) > > #define napot_cont_mask(order) BIT(napot_cont_size(order) - 1) > > #define napot_pte_num(order) BIT(order) > > Maybe we can declare legal napot order in a enum, and use the enum with > these macros you have mentioned above. I will try to do this in the v8 > patchset. I'm in a bit of a "keep it simple" camp for these things, I had to run through this last time to make sure to myself that it made sense. I think Drew's version is easier to follow despite (or due to?) the "future-proofing". Whatever you do, a comment wouldn't go amiss I think. Thanks, Conor.
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index d557cc50295d..69e88ab8fafd 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -383,6 +383,20 @@ config RISCV_ISA_C If you don't know what to do here, say Y. +config RISCV_ISA_SVNAPOT + bool "SVNAPOT extension support" + depends on 64BIT && MMU + select RISCV_ALTERNATIVE + default y + help + Allow kernel to detect SVNAPOT ISA-extension dynamically in boot time + and enable its usage. + + SVNAPOT extension helps to mark contiguous PTEs as a range + of contiguous virtual-to-physical translations, with a naturally + aligned power-of-2 (NAPOT) granularity larger than the base 4KB page + size. + config RISCV_ISA_SVPBMT bool "SVPBMT extension support" depends on 64BIT && MMU diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index 6f59ec64175e..2c45cc0d5d3c 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -54,6 +54,7 @@ extern unsigned long elf_hwcap; */ enum riscv_isa_ext_id { RISCV_ISA_EXT_SSCOFPMF = RISCV_ISA_EXT_BASE, + RISCV_ISA_EXT_SVNAPOT, RISCV_ISA_EXT_SVPBMT, RISCV_ISA_EXT_ZICBOM, RISCV_ISA_EXT_ZIHINTPAUSE, @@ -68,6 +69,7 @@ enum riscv_isa_ext_id { */ enum riscv_isa_ext_key { RISCV_ISA_EXT_KEY_FPU, /* For 'F' and 'D' */ + RISCV_ISA_EXT_KEY_SVNAPOT, RISCV_ISA_EXT_KEY_ZIHINTPAUSE, RISCV_ISA_EXT_KEY_MAX, }; @@ -88,6 +90,8 @@ static __always_inline int riscv_isa_ext2key(int num) return RISCV_ISA_EXT_KEY_FPU; case RISCV_ISA_EXT_d: return RISCV_ISA_EXT_KEY_FPU; + case RISCV_ISA_EXT_SVNAPOT: + return RISCV_ISA_EXT_KEY_SVNAPOT; case RISCV_ISA_EXT_ZIHINTPAUSE: return RISCV_ISA_EXT_KEY_ZIHINTPAUSE; default: diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index dc42375c2357..1cd0ffbfbdaa 100644 --- a/arch/riscv/include/asm/pgtable-64.h +++ b/arch/riscv/include/asm/pgtable-64.h @@ -74,6 +74,19 @@ typedef struct { */ #define _PAGE_PFN_MASK GENMASK(53, 10) +/* + * [63] Svnapot definitions: + * 0 Svnapot disabled + * 1 Svnapot enabled + */ +#define _PAGE_NAPOT_SHIFT 63 +#define _PAGE_NAPOT BIT(_PAGE_NAPOT_SHIFT) +#define NAPOT_CONT64KB_ORDER 4UL +#define NAPOT_CONT64KB_SHIFT (NAPOT_CONT64KB_ORDER + PAGE_SHIFT) +#define NAPOT_CONT64KB_SIZE BIT(NAPOT_CONT64KB_SHIFT) +#define NAPOT_CONT64KB_MASK (NAPOT_CONT64KB_SIZE - 1UL) +#define NAPOT_64KB_PTE_NUM BIT(NAPOT_CONT64KB_ORDER) + /* * [62:61] Svpbmt Memory Type definitions: * diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 7ec936910a96..a8cab063fd05 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -6,10 +6,12 @@ #ifndef _ASM_RISCV_PGTABLE_H #define _ASM_RISCV_PGTABLE_H +#include <linux/jump_label.h> #include <linux/mmzone.h> #include <linux/sizes.h> #include <asm/pgtable-bits.h> +#include <asm/hwcap.h> #ifndef CONFIG_MMU #define KERNEL_LINK_ADDR PAGE_OFFSET @@ -264,10 +266,38 @@ static inline pte_t pud_pte(pud_t pud) return __pte(pud_val(pud)); } +static __always_inline bool has_svnapot(void) +{ + return static_branch_likely(&riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_SVNAPOT]); +} + +#ifdef CONFIG_RISCV_ISA_SVNAPOT + +static inline unsigned long pte_napot(pte_t pte) +{ + return pte_val(pte) & _PAGE_NAPOT; +} + +static inline pte_t pte_mknapot(pte_t pte, unsigned int order) +{ + int pos = order - 1 + _PAGE_PFN_SHIFT; + unsigned long napot_bit = BIT(pos); + unsigned long napot_mask = ~GENMASK(pos, _PAGE_PFN_SHIFT); + + return __pte((pte_val(pte) & napot_mask) | napot_bit | _PAGE_NAPOT); +} +#endif /* CONFIG_RISCV_ISA_SVNAPOT */ + /* Yields the page frame number (PFN) of a page table entry */ static inline unsigned long pte_pfn(pte_t pte) { - return __page_val_to_pfn(pte_val(pte)); + unsigned long val = pte_val(pte); + unsigned long res = __page_val_to_pfn(val); + + if (has_svnapot()) + res = res & (res - (val >> _PAGE_NAPOT_SHIFT)); + + return res; } #define pte_page(x) pfn_to_page(pte_pfn(x)) diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index 0be8a2403212..d2a61122c595 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -96,6 +96,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = { __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), + __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT), __RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX), }; diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 553d755483ed..bc247844e42d 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -204,6 +204,7 @@ void __init riscv_fill_hwcap(void) SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM); SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE); SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC); + SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT); } #undef SET_ISA_EXT_MAP }