Skip to content

Commit

Permalink
riscv: mm: Add support for Svinval extension
Browse files Browse the repository at this point in the history
The Svinval extension splits SFENCE.VMA instruction into finer-grained
invalidation and ordering operations and is mandatory for RVA23S64 profile.
When Svinval is enabled the local_flush_tlb_range_threshold_asid function
should 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_range_threshold_asid function
is limited to 64. This is required to avoid soft lockups and the
approach is similar to that used in arm64.

Signed-off-by: Mayuresh Chitale <[email protected]>
Reviewed-by: Andrew Jones <[email protected]>
Signed-off-by: Guo Ren <[email protected]>
  • Loading branch information
guoren83 authored and RevySR committed Sep 6, 2024
1 parent a9e18e5 commit 866dd2b
Showing 1 changed file with 31 additions and 0 deletions.
31 changes: 31 additions & 0 deletions arch/riscv/mm/tlbflush.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@
#include <linux/sched.h>
#include <asm/sbi.h>
#include <asm/mmu_context.h>
#include <asm/cpufeature.h>

#define has_svinval() riscv_has_extension_unlikely(RISCV_ISA_EXT_SVINVAL)

static inline void local_sfence_inval_ir(void)
{
asm volatile(SFENCE_INVAL_IR() ::: "memory");
}

static inline void local_sfence_w_inval(void)
{
asm volatile(SFENCE_W_INVAL() ::: "memory");
}

static inline void local_sinval_vma(unsigned long vma, unsigned long asid)
{
if (asid != FLUSH_TLB_NO_ASID)
asm volatile(SINVAL_VMA( %0, %1) : : "r" (vma), "r" (asid) : "memory");
else
asm volatile(SINVAL_VMA( %0, zero) : : "r" (vma) : "memory");
}

static inline void local_flush_tlb_all_asid(unsigned long asid)
{
Expand Down Expand Up @@ -48,6 +69,16 @@ static void local_flush_tlb_range_threshold_asid(unsigned long start,
return;
}

if (has_svinval()) {
local_sfence_w_inval();
for (i = 0; i < nr_ptes_in_range; ++i) {
local_sinval_vma(start, asid);
start += stride;
}
local_sfence_inval_ir();
return;
}

for (i = 0; i < nr_ptes_in_range; ++i) {
local_flush_tlb_page_asid(start, asid);
start += stride;
Expand Down

0 comments on commit 866dd2b

Please sign in to comment.