Risc-V Svinval support
v3 cover Risc-V Svinval support
This patch adds support for the Svinval extension as defined in the Risc V Privileged specification. This patchset depends on the following series from Anup:
https://patchwork.kernel.org/project/linux-riscv/list/?series=661505
Changes in v3:
- Fix incorrect vma used for sinval instructions
- Use unified static key mechanism for svinval
- Rebased on torvalds/master
Changes in v2:
- Rebased on 5.18-rc3
- update riscv_fill_hwcap to probe Svinval extension
Mayuresh Chitale (2):
riscv: enum for svinval extension
riscv: mm: use svinval instructions instead of sfence.vma
arch/riscv/include/asm/hwcap.h | 4 ++ arch/riscv/kernel/cpu.c | 1 + arch/riscv/kernel/cpufeature.c | 1 + arch/riscv/mm/tlbflush.c | 108 +++++++++++++++++++++++++++++++-- 4 files changed, 108 insertions(+), 6 deletions(-)
Signature · 7 lines
2.34.1 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
RFC PATCH v3 1/2 riscv: enum for svinval extension
Similar to the other ISA extensions, this patch enables callers to check for the presence for the svinval extension.
--- arch/riscv/include/asm/hwcap.h | 4 ++++ arch/riscv/kernel/cpu.c | 1 + arch/riscv/kernel/cpufeature.c | 1 + 3 files changed, 6 insertions(+)
arch/riscv/include/asm/hwcap.h +4 -0
@@ -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_SVPBMT , +RISCV_ISA_EXT_SVINVAL ,RISCV_ISA_EXT_ID_MAX =RISCV_ISA_EXT_MAX , };
@@ -64,6 +65,7 @@ enum riscv_isa_ext_id {*/ enum riscv_isa_ext_key {RISCV_ISA_EXT_KEY_FPU ,/* For 'F' and 'D' */ +RISCV_ISA_EXT_KEY_SVINVAL ,RISCV_ISA_EXT_KEY_MAX , };
@@ -83,6 +85,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_SVINVAL : +return RISCV_ISA_EXT_KEY_SVINVAL ;default :return -EINVAL ; }
arch/riscv/kernel/cpu.c +1 -0
@@ -93,6 +93,7 @@ int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid)static struct riscv_isa_ext_data isa_ext_arr[] = {__RISCV_ISA_EXT_DATA (sscofpmf,RISCV_ISA_EXT_SSCOFPMF ),__RISCV_ISA_EXT_DATA (svpbmt,RISCV_ISA_EXT_SVPBMT ), +__RISCV_ISA_EXT_DATA (svinval,RISCV_ISA_EXT_SVINVAL ),__RISCV_ISA_EXT_DATA ("" ,RISCV_ISA_EXT_MAX ), };
arch/riscv/kernel/cpufeature.c +1 -0
@@ -200,6 +200,7 @@ void __init riscv_fill_hwcap(void) }else {SET_ISA_EXT_MAP ("sscofpmf" ,RISCV_ISA_EXT_SSCOFPMF );SET_ISA_EXT_MAP ("svpbmt" ,RISCV_ISA_EXT_SVPBMT ); +SET_ISA_EXT_MAP ("svinval" ,RISCV_ISA_EXT_SVINVAL ); }#undef SET_ISA_EXT_MAP }
Signature · 7 lines
2.34.1 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
RFC PATCH v3 2/2 riscv: mm: use svinval instructions instead of sfence.vma
In reply to Mayuresh ChitaleWhen svinval is supported the local_flush_tlb_page* functions would prefer to use the following sequence to optimize the tlb flushes instead of a simple sfence.vma:
sfence.w.inval
svinval.vma
.
.
svinval.vma
sfence.inval.ir
The maximum number of consecutive svinval.vma instructions that can be executed in local_flush_tlb_page* functions is limited to PTRS_PER_PTE. This is required to avoid soft lockups and the approach is similar to that used in arm64.
--- arch/riscv/mm/tlbflush.c | 108 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 6 deletions(-)
arch/riscv/mm/tlbflush.c +102 -6
@@ -5,6 +5,14 @@#include <linux/sched.h> #include <asm/sbi.h> #include <asm/mmu_context.h> +#include <asm/hwcap.h> + +static unsigned long tlb_flush_all_threshold__read_mostly =PTRS_PER_PTE ; + +static __always_inline bool has_svinval(void) +{ +return static_branch_unlikely (&riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_SVINVAL ]); +}static inline void local_flush_tlb_all_asid (unsigned long asid) {
@@ -23,22 +31,110 @@ static inline void local_flush_tlb_page_asid(unsigned long addr, : "memory"); } +static inline void local_sfence_inval_ir (void ) +{ +/* +* SFENCE.INVAL.IR +* 0001100 00001 00000 000 00000 1110011 +*/ + asmvolatile (".word 0x18100073" :::"memory" ); +} + +static inline void local_sfence_w_inval (void ) +{ +/* +* SFENCE.W.INVAL +* 0001100 00000 00000 000 00000 1110011 +*/ + asmvolatile (".word 0x18000073" :::"memory" ); +} + +static inline void local_sinval_vma_asid (unsigned long vma,unsigned long asid) +{ +/* +* rs1 = a0 (VMA) +* rs2 = a1 (asid) +* SINVAL.VMA a0, a1 +* 0001011 01011 01010 000 00000 1110011 +*/ + asmvolatile ("add a0, %0, zero\n" +"add a1, %1, zero\n" +".word 0x16B50073\n" + ::"r" (vma),"r" (asid) + :"a0" ,"a1" ,"memory" ); +} + +static inline void local_sinval_vma (unsigned long vma) +{ +/* +* rs1 = a0 (VMA) +* rs2 = 0 +* SINVAL.VMA a0 +* 0001011 00000 01010 000 00000 1110011 +*/ + asmvolatile ("add a0, %0, zero\n" +".word 0x16050073\n" + ::"r" (vma) :"a0" ,"memory" ); +} +static inline void local_flush_tlb_range (unsigned long start,unsigned long size,unsigned long stride) { -if (size <= stride) -local_flush_tlb_page (start); -else +if ((size / stride) <= tlb_flush_all_threshold) { +if (has_svinval ()) { +local_sfence_w_inval (); +while (size) { +local_sinval_vma (start); + start += stride; +if (size > stride) + size -= stride; +else + size =0 ; + } +local_sfence_inval_ir (); + }else { +while (size) { +local_flush_tlb_page (start); + start += stride; +if (size > stride) + size -= stride; +else + size =0 ; + } + } + }else {local_flush_tlb_all (); + } }static inline void local_flush_tlb_range_asid (unsigned long start,unsigned long size,unsigned long stride,unsigned long asid) { -if (size <= stride) -local_flush_tlb_page_asid (start, asid); -else +if ((size / stride) <= tlb_flush_all_threshold) { +if (has_svinval ()) { +local_sfence_w_inval (); +while (size) { +local_sinval_vma_asid (start, asid); + start += stride; +if (size > stride) + size -= stride; +else + size =0 ; + } +local_sfence_inval_ir (); + }else { +while (size) { +local_flush_tlb_page_asid (start, asid); + start += stride; +if (size > stride) + size -= stride; +else + size =0 ; + } + } + }else {local_flush_tlb_all_asid (asid); + } }static void __ipi_flush_tlb_all (void *info)
Signature · 7 lines
2.34.1 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv