Message ID | 20221128022719.328770-2-panqinglin2020@iscas.ac.cn (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | riscv, mm: detect svnapot cpu support at runtime | expand |
Context | Check | Description |
---|---|---|
conchuod/patch_count | success | Link |
conchuod/cover_letter | success | Series has a cover letter |
conchuod/tree_selection | success | Guessed tree name to be for-next |
conchuod/fixes_present | success | Fixes tag not required for -next series |
conchuod/verify_signedoff | success | Signed-off-by tag matches author and committer |
conchuod/kdoc | success | Errors and warnings before: 0 this patch: 0 |
conchuod/module_param | success | Was 0 now: 0 |
conchuod/build_rv32_defconfig | success | Build OK |
conchuod/build_warn_rv64 | success | Errors and warnings before: 0 this patch: 0 |
conchuod/dtb_warn_rv64 | success | Errors and warnings before: 0 this patch: 0 |
conchuod/header_inline | success | No static functions without inline keyword in header files |
conchuod/checkpatch | success | total: 0 errors, 0 warnings, 0 checks, 165 lines checked |
conchuod/source_inline | success | Was 0 now: 0 |
conchuod/build_rv64_nommu_k210_defconfig | success | Build OK |
conchuod/verify_fixes | success | No Fixes tag |
conchuod/build_rv64_nommu_virt_defconfig | success | Build OK |
On Mon, Nov 28, 2022 at 10:27:17AM +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 3b41165a8b10..1671938f2f81 100644 > --- a/arch/riscv/Kconfig > +++ b/arch/riscv/Kconfig > @@ -394,6 +394,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 b22525290073..15cda8f131aa 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, > @@ -69,6 +70,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_SVINVAL, > RISCV_ISA_EXT_KEY_MAX, > @@ -90,6 +92,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; > case RISCV_ISA_EXT_SVINVAL: > diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h > index ac70b0fd9a9a..349fad5e35de 100644 > --- a/arch/riscv/include/asm/page.h > +++ b/arch/riscv/include/asm/page.h > @@ -16,11 +16,6 @@ > #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) > #define PAGE_MASK (~(PAGE_SIZE - 1)) > > -#ifdef CONFIG_64BIT > -#define HUGE_MAX_HSTATE 2 > -#else > -#define HUGE_MAX_HSTATE 1 > -#endif > #define HPAGE_SHIFT PMD_SHIFT > #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) > #define HPAGE_MASK (~(HPAGE_SIZE - 1)) > diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h > index dc42375c2357..598958cbda50 100644 > --- a/arch/riscv/include/asm/pgtable-64.h > +++ b/arch/riscv/include/asm/pgtable-64.h > @@ -74,6 +74,40 @@ 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) > +/* > + * Only 64KB (order 4) napot ptes supported. > + */ > +#define NAPOT_CONT_ORDER_BASE 4 > +enum napot_cont_order { > + NAPOT_CONT64KB_ORDER = NAPOT_CONT_ORDER_BASE, > + NAPOT_ORDER_MAX, > +}; > + > +#define for_each_napot_order(order) \ > + for (order = NAPOT_CONT_ORDER_BASE; order < NAPOT_ORDER_MAX; order++) > +#define for_each_napot_order_rev(order) \ > + for (order = NAPOT_ORDER_MAX - 1; \ > + order >= NAPOT_CONT_ORDER_BASE; order--) > +#define napot_cont_order(val) (__builtin_ctzl((val.pte >> _PAGE_PFN_SHIFT) << 1)) > + > +#define napot_cont_shift(order) ((order) + PAGE_SHIFT) > +#define napot_cont_size(order) BIT(napot_cont_shift(order)) > +#define napot_cont_mask(order) (napot_cont_size(order) - 1UL) > +#define napot_pte_num(order) BIT(order) > + > +#ifdef CONFIG_RISCV_ISA_SVNAPOT > +#define HUGE_MAX_HSTATE (2 + (NAPOT_ORDER_MAX - NAPOT_CONT_ORDER_BASE)) > +#else > +#define HUGE_MAX_HSTATE 2 > +#endif > + > /* > * [62:61] Svpbmt Memory Type definitions: > * > diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h > index c61ae83aadee..af6174e3fd97 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,45 @@ 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]); I'm not sure if this should be likely or unlikely. > +} > + > +#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); > +} > + > +#else > + > +static inline unsigned long pte_napot(pte_t pte) > +{ > + return 0; > +} > + > +#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 res = __page_val_to_pfn(pte_val(pte)); > + > + if (has_svnapot() && pte_napot(pte)) We've been burned with static branches inside heavily used inline functions before (see [1]). There's a series[2] that was meant to help with this. I haven't seen a refresh of that though. [1] https://lore.kernel.org/linux-riscv/20220922060958.44203-1-samuel@sholland.org/ [2] https://lore.kernel.org/all/20221006070818.3616-1-jszhang@kernel.org/ > + res = res & (res - 1UL); > + > + 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 bf9dd6764bad..88495f5fcafd 100644 > --- a/arch/riscv/kernel/cpu.c > +++ b/arch/riscv/kernel/cpu.c > @@ -165,6 +165,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = { > __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), > __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), > __RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL), > + __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT), > __RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT), > __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), > __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c > index 694267d1fe81..ad12fb5363c3 100644 > --- a/arch/riscv/kernel/cpufeature.c > +++ b/arch/riscv/kernel/cpufeature.c > @@ -205,6 +205,7 @@ void __init riscv_fill_hwcap(void) > SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE); > SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC); > SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL); > + SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT); > } > #undef SET_ISA_EXT_MAP > } > -- > 2.37.4 > Besides the static branch questions, this looks good to me Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Thanks, drew
On Mon, Nov 28, 2022 at 10:27:17AM +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 3b41165a8b10..1671938f2f81 100644 > --- a/arch/riscv/Kconfig > +++ b/arch/riscv/Kconfig > @@ -394,6 +394,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 b22525290073..15cda8f131aa 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, > @@ -69,6 +70,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_SVINVAL, > RISCV_ISA_EXT_KEY_MAX, > @@ -90,6 +92,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; BTW, while you're touching this, can you make this opportunistic cleanup? @@ -87,7 +87,6 @@ static __always_inline int riscv_isa_ext2key(int num) { switch (num) { case RISCV_ISA_EXT_f: - return RISCV_ISA_EXT_KEY_FPU; case RISCV_ISA_EXT_d: return RISCV_ISA_EXT_KEY_FPU; case RISCV_ISA_EXT_ZIHINTPAUSE: Thanks, drew > case RISCV_ISA_EXT_ZIHINTPAUSE: > return RISCV_ISA_EXT_KEY_ZIHINTPAUSE; > case RISCV_ISA_EXT_SVINVAL: > diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h > index ac70b0fd9a9a..349fad5e35de 100644 > --- a/arch/riscv/include/asm/page.h > +++ b/arch/riscv/include/asm/page.h > @@ -16,11 +16,6 @@ > #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) > #define PAGE_MASK (~(PAGE_SIZE - 1)) > > -#ifdef CONFIG_64BIT > -#define HUGE_MAX_HSTATE 2 > -#else > -#define HUGE_MAX_HSTATE 1 > -#endif > #define HPAGE_SHIFT PMD_SHIFT > #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) > #define HPAGE_MASK (~(HPAGE_SIZE - 1)) > diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h > index dc42375c2357..598958cbda50 100644 > --- a/arch/riscv/include/asm/pgtable-64.h > +++ b/arch/riscv/include/asm/pgtable-64.h > @@ -74,6 +74,40 @@ 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) > +/* > + * Only 64KB (order 4) napot ptes supported. > + */ > +#define NAPOT_CONT_ORDER_BASE 4 > +enum napot_cont_order { > + NAPOT_CONT64KB_ORDER = NAPOT_CONT_ORDER_BASE, > + NAPOT_ORDER_MAX, > +}; > + > +#define for_each_napot_order(order) \ > + for (order = NAPOT_CONT_ORDER_BASE; order < NAPOT_ORDER_MAX; order++) > +#define for_each_napot_order_rev(order) \ > + for (order = NAPOT_ORDER_MAX - 1; \ > + order >= NAPOT_CONT_ORDER_BASE; order--) > +#define napot_cont_order(val) (__builtin_ctzl((val.pte >> _PAGE_PFN_SHIFT) << 1)) > + > +#define napot_cont_shift(order) ((order) + PAGE_SHIFT) > +#define napot_cont_size(order) BIT(napot_cont_shift(order)) > +#define napot_cont_mask(order) (napot_cont_size(order) - 1UL) > +#define napot_pte_num(order) BIT(order) > + > +#ifdef CONFIG_RISCV_ISA_SVNAPOT > +#define HUGE_MAX_HSTATE (2 + (NAPOT_ORDER_MAX - NAPOT_CONT_ORDER_BASE)) > +#else > +#define HUGE_MAX_HSTATE 2 > +#endif > + > /* > * [62:61] Svpbmt Memory Type definitions: > * > diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h > index c61ae83aadee..af6174e3fd97 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,45 @@ 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); > +} > + > +#else > + > +static inline unsigned long pte_napot(pte_t pte) > +{ > + return 0; > +} > + > +#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 res = __page_val_to_pfn(pte_val(pte)); > + > + if (has_svnapot() && pte_napot(pte)) > + res = res & (res - 1UL); > + > + 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 bf9dd6764bad..88495f5fcafd 100644 > --- a/arch/riscv/kernel/cpu.c > +++ b/arch/riscv/kernel/cpu.c > @@ -165,6 +165,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = { > __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), > __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), > __RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL), > + __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT), > __RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT), > __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), > __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c > index 694267d1fe81..ad12fb5363c3 100644 > --- a/arch/riscv/kernel/cpufeature.c > +++ b/arch/riscv/kernel/cpufeature.c > @@ -205,6 +205,7 @@ void __init riscv_fill_hwcap(void) > SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE); > SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC); > SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL); > + SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT); > } > #undef SET_ISA_EXT_MAP > } > -- > 2.37.4 >
On Tue, Nov 29, 2022 at 10:49:46AM +0100, Andrew Jones wrote: > On Mon, Nov 28, 2022 at 10:27:17AM +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 3b41165a8b10..1671938f2f81 100644 > > --- a/arch/riscv/Kconfig > > +++ b/arch/riscv/Kconfig > > @@ -394,6 +394,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 b22525290073..15cda8f131aa 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, > > @@ -69,6 +70,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_SVINVAL, > > RISCV_ISA_EXT_KEY_MAX, > > @@ -90,6 +92,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; > > case RISCV_ISA_EXT_SVINVAL: > > diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h > > index ac70b0fd9a9a..349fad5e35de 100644 > > --- a/arch/riscv/include/asm/page.h > > +++ b/arch/riscv/include/asm/page.h > > @@ -16,11 +16,6 @@ > > #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) > > #define PAGE_MASK (~(PAGE_SIZE - 1)) > > > > -#ifdef CONFIG_64BIT > > -#define HUGE_MAX_HSTATE 2 > > -#else > > -#define HUGE_MAX_HSTATE 1 > > -#endif > > #define HPAGE_SHIFT PMD_SHIFT > > #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) > > #define HPAGE_MASK (~(HPAGE_SIZE - 1)) > > diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h > > index dc42375c2357..598958cbda50 100644 > > --- a/arch/riscv/include/asm/pgtable-64.h > > +++ b/arch/riscv/include/asm/pgtable-64.h > > @@ -74,6 +74,40 @@ 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) > > +/* > > + * Only 64KB (order 4) napot ptes supported. > > + */ > > +#define NAPOT_CONT_ORDER_BASE 4 > > +enum napot_cont_order { > > + NAPOT_CONT64KB_ORDER = NAPOT_CONT_ORDER_BASE, > > + NAPOT_ORDER_MAX, > > +}; > > + > > +#define for_each_napot_order(order) \ > > + for (order = NAPOT_CONT_ORDER_BASE; order < NAPOT_ORDER_MAX; order++) > > +#define for_each_napot_order_rev(order) \ > > + for (order = NAPOT_ORDER_MAX - 1; \ > > + order >= NAPOT_CONT_ORDER_BASE; order--) > > +#define napot_cont_order(val) (__builtin_ctzl((val.pte >> _PAGE_PFN_SHIFT) << 1)) > > + > > +#define napot_cont_shift(order) ((order) + PAGE_SHIFT) > > +#define napot_cont_size(order) BIT(napot_cont_shift(order)) > > +#define napot_cont_mask(order) (napot_cont_size(order) - 1UL) > > +#define napot_pte_num(order) BIT(order) > > + > > +#ifdef CONFIG_RISCV_ISA_SVNAPOT > > +#define HUGE_MAX_HSTATE (2 + (NAPOT_ORDER_MAX - NAPOT_CONT_ORDER_BASE)) > > +#else > > +#define HUGE_MAX_HSTATE 2 > > +#endif > > + > > /* > > * [62:61] Svpbmt Memory Type definitions: > > * > > diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h > > index c61ae83aadee..af6174e3fd97 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,45 @@ 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]); > > I'm not sure if this should be likely or unlikely. > > > +} > > + > > +#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); > > +} > > + > > +#else > > + > > +static inline unsigned long pte_napot(pte_t pte) > > +{ > > + return 0; > > +} > > + > > +#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 res = __page_val_to_pfn(pte_val(pte)); > > + > > + if (has_svnapot() && pte_napot(pte)) > > We've been burned with static branches inside heavily used inline > functions before (see [1]). There's a series[2] that was meant to > help with this. I haven't seen a refresh of that though. > > [1] https://lore.kernel.org/linux-riscv/20220922060958.44203-1-samuel@sholland.org/ > [2] https://lore.kernel.org/all/20221006070818.3616-1-jszhang@kernel.org/ I will send a refresh of [2] tomorrow. Thanks
On 2022/11/29 17:49, Andrew Jones wrote: > On Mon, Nov 28, 2022 at 10:27:17AM +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 3b41165a8b10..1671938f2f81 100644 >> --- a/arch/riscv/Kconfig >> +++ b/arch/riscv/Kconfig >> @@ -394,6 +394,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 b22525290073..15cda8f131aa 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, >> @@ -69,6 +70,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_SVINVAL, >> RISCV_ISA_EXT_KEY_MAX, >> @@ -90,6 +92,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; >> case RISCV_ISA_EXT_SVINVAL: >> diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h >> index ac70b0fd9a9a..349fad5e35de 100644 >> --- a/arch/riscv/include/asm/page.h >> +++ b/arch/riscv/include/asm/page.h >> @@ -16,11 +16,6 @@ >> #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) >> #define PAGE_MASK (~(PAGE_SIZE - 1)) >> >> -#ifdef CONFIG_64BIT >> -#define HUGE_MAX_HSTATE 2 >> -#else >> -#define HUGE_MAX_HSTATE 1 >> -#endif >> #define HPAGE_SHIFT PMD_SHIFT >> #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) >> #define HPAGE_MASK (~(HPAGE_SIZE - 1)) >> diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h >> index dc42375c2357..598958cbda50 100644 >> --- a/arch/riscv/include/asm/pgtable-64.h >> +++ b/arch/riscv/include/asm/pgtable-64.h >> @@ -74,6 +74,40 @@ 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) >> +/* >> + * Only 64KB (order 4) napot ptes supported. >> + */ >> +#define NAPOT_CONT_ORDER_BASE 4 >> +enum napot_cont_order { >> + NAPOT_CONT64KB_ORDER = NAPOT_CONT_ORDER_BASE, >> + NAPOT_ORDER_MAX, >> +}; >> + >> +#define for_each_napot_order(order) \ >> + for (order = NAPOT_CONT_ORDER_BASE; order < NAPOT_ORDER_MAX; order++) >> +#define for_each_napot_order_rev(order) \ >> + for (order = NAPOT_ORDER_MAX - 1; \ >> + order >= NAPOT_CONT_ORDER_BASE; order--) >> +#define napot_cont_order(val) (__builtin_ctzl((val.pte >> _PAGE_PFN_SHIFT) << 1)) >> + >> +#define napot_cont_shift(order) ((order) + PAGE_SHIFT) >> +#define napot_cont_size(order) BIT(napot_cont_shift(order)) >> +#define napot_cont_mask(order) (napot_cont_size(order) - 1UL) >> +#define napot_pte_num(order) BIT(order) >> + >> +#ifdef CONFIG_RISCV_ISA_SVNAPOT >> +#define HUGE_MAX_HSTATE (2 + (NAPOT_ORDER_MAX - NAPOT_CONT_ORDER_BASE)) >> +#else >> +#define HUGE_MAX_HSTATE 2 >> +#endif >> + >> /* >> * [62:61] Svpbmt Memory Type definitions: >> * >> diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h >> index c61ae83aadee..af6174e3fd97 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,45 @@ 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]); > > I'm not sure if this should be likely or unlikely. > >> +} >> + >> +#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); >> +} >> + >> +#else >> + >> +static inline unsigned long pte_napot(pte_t pte) >> +{ >> + return 0; >> +} >> + >> +#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 res = __page_val_to_pfn(pte_val(pte)); >> + >> + if (has_svnapot() && pte_napot(pte)) > > We've been burned with static branches inside heavily used inline > functions before (see [1]). There's a series[2] that was meant to > help with this. I haven't seen a refresh of that though. > > [1] https://lore.kernel.org/linux-riscv/20220922060958.44203-1-samuel@sholland.org/ > [2] https://lore.kernel.org/all/20221006070818.3616-1-jszhang@kernel.org/ Hi Andrew, I will reimplement has_svnapot with alternative in next version patchset (as I did in previous versions) :-( And we can replace has_svnapot with riscv_has_extension_{likely, unlikely} from [2] in the future. Thanks, Qinglin > >> + res = res & (res - 1UL); >> + >> + 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 bf9dd6764bad..88495f5fcafd 100644 >> --- a/arch/riscv/kernel/cpu.c >> +++ b/arch/riscv/kernel/cpu.c >> @@ -165,6 +165,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = { >> __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), >> __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), >> __RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL), >> + __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT), >> __RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT), >> __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), >> __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), >> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c >> index 694267d1fe81..ad12fb5363c3 100644 >> --- a/arch/riscv/kernel/cpufeature.c >> +++ b/arch/riscv/kernel/cpufeature.c >> @@ -205,6 +205,7 @@ void __init riscv_fill_hwcap(void) >> SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE); >> SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC); >> SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL); >> + SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT); >> } >> #undef SET_ISA_EXT_MAP >> } >> -- >> 2.37.4 >> > > Besides the static branch questions, this looks good to me > > Reviewed-by: Andrew Jones <ajones@ventanamicro.com> > > Thanks, > drew
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 3b41165a8b10..1671938f2f81 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -394,6 +394,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 b22525290073..15cda8f131aa 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, @@ -69,6 +70,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_SVINVAL, RISCV_ISA_EXT_KEY_MAX, @@ -90,6 +92,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; case RISCV_ISA_EXT_SVINVAL: diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h index ac70b0fd9a9a..349fad5e35de 100644 --- a/arch/riscv/include/asm/page.h +++ b/arch/riscv/include/asm/page.h @@ -16,11 +16,6 @@ #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE - 1)) -#ifdef CONFIG_64BIT -#define HUGE_MAX_HSTATE 2 -#else -#define HUGE_MAX_HSTATE 1 -#endif #define HPAGE_SHIFT PMD_SHIFT #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) #define HPAGE_MASK (~(HPAGE_SIZE - 1)) diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index dc42375c2357..598958cbda50 100644 --- a/arch/riscv/include/asm/pgtable-64.h +++ b/arch/riscv/include/asm/pgtable-64.h @@ -74,6 +74,40 @@ 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) +/* + * Only 64KB (order 4) napot ptes supported. + */ +#define NAPOT_CONT_ORDER_BASE 4 +enum napot_cont_order { + NAPOT_CONT64KB_ORDER = NAPOT_CONT_ORDER_BASE, + NAPOT_ORDER_MAX, +}; + +#define for_each_napot_order(order) \ + for (order = NAPOT_CONT_ORDER_BASE; order < NAPOT_ORDER_MAX; order++) +#define for_each_napot_order_rev(order) \ + for (order = NAPOT_ORDER_MAX - 1; \ + order >= NAPOT_CONT_ORDER_BASE; order--) +#define napot_cont_order(val) (__builtin_ctzl((val.pte >> _PAGE_PFN_SHIFT) << 1)) + +#define napot_cont_shift(order) ((order) + PAGE_SHIFT) +#define napot_cont_size(order) BIT(napot_cont_shift(order)) +#define napot_cont_mask(order) (napot_cont_size(order) - 1UL) +#define napot_pte_num(order) BIT(order) + +#ifdef CONFIG_RISCV_ISA_SVNAPOT +#define HUGE_MAX_HSTATE (2 + (NAPOT_ORDER_MAX - NAPOT_CONT_ORDER_BASE)) +#else +#define HUGE_MAX_HSTATE 2 +#endif + /* * [62:61] Svpbmt Memory Type definitions: * diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index c61ae83aadee..af6174e3fd97 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,45 @@ 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); +} + +#else + +static inline unsigned long pte_napot(pte_t pte) +{ + return 0; +} + +#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 res = __page_val_to_pfn(pte_val(pte)); + + if (has_svnapot() && pte_napot(pte)) + res = res & (res - 1UL); + + 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 bf9dd6764bad..88495f5fcafd 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -165,6 +165,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = { __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), __RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL), + __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT), __RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT), __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 694267d1fe81..ad12fb5363c3 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -205,6 +205,7 @@ void __init riscv_fill_hwcap(void) SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE); SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC); SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL); + SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT); } #undef SET_ISA_EXT_MAP }