Skip to content

Commit 4bd1d80

Browse files
sm-scpalmer-dabbelt
authored andcommitted
riscv: mm: notify remote harts about mmu cache updates
Current implementation of update_mmu_cache function performs local TLB flush. It does not take into account ASID information. Besides, it does not take into account other harts currently running the same mm context or possible migration of the running context to other harts. Meanwhile TLB flush is not performed for every context switch if ASID support is enabled. Patch [1] proposed to add ASID support to update_mmu_cache to avoid flushing local TLB entirely. This patch takes into account other harts currently running the same mm context as well as possible migration of this context to other harts. For this purpose the approach from flush_icache_mm is reused. Remote harts currently running the same mm context are informed via SBI calls that they need to flush their local TLBs. All the other harts are marked as needing a deferred TLB flush when this mm context runs on them. [1] https://lore.kernel.org/linux-riscv/[email protected]/ Signed-off-by: Sergey Matyukevich <[email protected]> Fixes: 65d4b9c ("RISC-V: Implement ASID allocator") Cc: [email protected] Link: https://lore.kernel.org/linux-riscv/[email protected]/#t Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 7ecdadf commit 4bd1d80

File tree

5 files changed

+42
-18
lines changed

5 files changed

+42
-18
lines changed

arch/riscv/include/asm/mmu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ typedef struct {
1919
#ifdef CONFIG_SMP
2020
/* A local icache flush is needed before user execution can resume. */
2121
cpumask_t icache_stale_mask;
22+
/* A local tlb flush is needed before user execution can resume. */
23+
cpumask_t tlb_stale_mask;
2224
#endif
2325
} mm_context_t;
2426

arch/riscv/include/asm/pgtable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
415415
* Relying on flush_tlb_fix_spurious_fault would suffice, but
416416
* the extra traps reduce performance. So, eagerly SFENCE.VMA.
417417
*/
418-
local_flush_tlb_page(address);
418+
flush_tlb_page(vma, address);
419419
}
420420

421421
#define __HAVE_ARCH_UPDATE_MMU_TLB

arch/riscv/include/asm/tlbflush.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ static inline void local_flush_tlb_page(unsigned long addr)
2222
{
2323
ALT_FLUSH_TLB_PAGE(__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"));
2424
}
25+
26+
static inline void local_flush_tlb_all_asid(unsigned long asid)
27+
{
28+
__asm__ __volatile__ ("sfence.vma x0, %0"
29+
:
30+
: "r" (asid)
31+
: "memory");
32+
}
33+
34+
static inline void local_flush_tlb_page_asid(unsigned long addr,
35+
unsigned long asid)
36+
{
37+
__asm__ __volatile__ ("sfence.vma %0, %1"
38+
:
39+
: "r" (addr), "r" (asid)
40+
: "memory");
41+
}
42+
2543
#else /* CONFIG_MMU */
2644
#define local_flush_tlb_all() do { } while (0)
2745
#define local_flush_tlb_page(addr) do { } while (0)

arch/riscv/mm/context.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,16 @@ static void set_mm_asid(struct mm_struct *mm, unsigned int cpu)
196196

197197
if (need_flush_tlb)
198198
local_flush_tlb_all();
199+
#ifdef CONFIG_SMP
200+
else {
201+
cpumask_t *mask = &mm->context.tlb_stale_mask;
202+
203+
if (cpumask_test_cpu(cpu, mask)) {
204+
cpumask_clear_cpu(cpu, mask);
205+
local_flush_tlb_all_asid(cntx & asid_mask);
206+
}
207+
}
208+
#endif
199209
}
200210

201211
static void set_mm_noasid(struct mm_struct *mm)

arch/riscv/mm/tlbflush.c

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,7 @@
55
#include <linux/sched.h>
66
#include <asm/sbi.h>
77
#include <asm/mmu_context.h>
8-
9-
static inline void local_flush_tlb_all_asid(unsigned long asid)
10-
{
11-
__asm__ __volatile__ ("sfence.vma x0, %0"
12-
:
13-
: "r" (asid)
14-
: "memory");
15-
}
16-
17-
static inline void local_flush_tlb_page_asid(unsigned long addr,
18-
unsigned long asid)
19-
{
20-
__asm__ __volatile__ ("sfence.vma %0, %1"
21-
:
22-
: "r" (addr), "r" (asid)
23-
: "memory");
24-
}
8+
#include <asm/tlbflush.h>
259

2610
void flush_tlb_all(void)
2711
{
@@ -31,6 +15,7 @@ void flush_tlb_all(void)
3115
static void __sbi_tlb_flush_range(struct mm_struct *mm, unsigned long start,
3216
unsigned long size, unsigned long stride)
3317
{
18+
struct cpumask *pmask = &mm->context.tlb_stale_mask;
3419
struct cpumask *cmask = mm_cpumask(mm);
3520
unsigned int cpuid;
3621
bool broadcast;
@@ -44,6 +29,15 @@ static void __sbi_tlb_flush_range(struct mm_struct *mm, unsigned long start,
4429
if (static_branch_unlikely(&use_asid_allocator)) {
4530
unsigned long asid = atomic_long_read(&mm->context.id);
4631

32+
/*
33+
* TLB will be immediately flushed on harts concurrently
34+
* executing this MM context. TLB flush on other harts
35+
* is deferred until this MM context migrates there.
36+
*/
37+
cpumask_setall(pmask);
38+
cpumask_clear_cpu(cpuid, pmask);
39+
cpumask_andnot(pmask, pmask, cmask);
40+
4741
if (broadcast) {
4842
sbi_remote_sfence_vma_asid(cmask, start, size, asid);
4943
} else if (size <= stride) {

0 commit comments

Comments
 (0)