* [PATCH v3 1/8] riscv: mm: Combine the SMP and UP TLB flush code
2023-11-22 1:07 [PATCH v3 0/8] riscv: ASID-related and UP-related TLB flush enhancements Samuel Holland
@ 2023-11-22 1:07 ` Samuel Holland
2023-11-22 1:07 ` [PATCH v3 2/8] riscv: Apply SiFive CIP-1200 workaround to single-ASID sfence.vma Samuel Holland
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Samuel Holland @ 2023-11-22 1:07 UTC (permalink / raw)
To: Palmer Dabbelt, linux-riscv
Cc: linux-kernel, linux-mm, Alexandre Ghiti, Samuel Holland
In SMP configurations, all TLB flushing narrower than flush_tlb_all()
goes through __flush_tlb_range(). Do the same in UP configurations.
This allows UP configurations to take advantage of recent improvements
to the code in tlbflush.c, such as support for huge pages and flushing
multiple-page ranges.
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---
(no changes since v2)
Changes in v2:
- Move the SMP/UP merge earlier in the series to avoid build issues
- Make a copy of __flush_tlb_range() instead of adding ifdefs inside
- local_flush_tlb_all() is the only function used on !MMU (smpboot.c)
arch/riscv/include/asm/tlbflush.h | 33 +++++++------------------------
arch/riscv/mm/Makefile | 5 +----
arch/riscv/mm/tlbflush.c | 13 ++++++++++++
3 files changed, 21 insertions(+), 30 deletions(-)
diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h
index 8f3418c5f172..317a1811aa51 100644
--- a/arch/riscv/include/asm/tlbflush.h
+++ b/arch/riscv/include/asm/tlbflush.h
@@ -27,13 +27,12 @@ static inline void local_flush_tlb_page(unsigned long addr)
{
ALT_FLUSH_TLB_PAGE(__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"));
}
-#else /* CONFIG_MMU */
-#define local_flush_tlb_all() do { } while (0)
-#define local_flush_tlb_page(addr) do { } while (0)
-#endif /* CONFIG_MMU */
-#if defined(CONFIG_SMP) && defined(CONFIG_MMU)
+#ifdef CONFIG_SMP
void flush_tlb_all(void);
+#else
+#define flush_tlb_all() local_flush_tlb_all()
+#endif
void flush_tlb_mm(struct mm_struct *mm);
void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
unsigned long end, unsigned int page_size);
@@ -46,26 +45,8 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end);
void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end);
#endif
-#else /* CONFIG_SMP && CONFIG_MMU */
-
-#define flush_tlb_all() local_flush_tlb_all()
-#define flush_tlb_page(vma, addr) local_flush_tlb_page(addr)
-
-static inline void flush_tlb_range(struct vm_area_struct *vma,
- unsigned long start, unsigned long end)
-{
- local_flush_tlb_all();
-}
-
-/* Flush a range of kernel pages */
-static inline void flush_tlb_kernel_range(unsigned long start,
- unsigned long end)
-{
- local_flush_tlb_all();
-}
-
-#define flush_tlb_mm(mm) flush_tlb_all()
-#define flush_tlb_mm_range(mm, start, end, page_size) flush_tlb_all()
-#endif /* !CONFIG_SMP || !CONFIG_MMU */
+#else /* CONFIG_MMU */
+#define local_flush_tlb_all() do { } while (0)
+#endif /* CONFIG_MMU */
#endif /* _ASM_RISCV_TLBFLUSH_H */
diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile
index 3a4dfc8babcf..96e65c571ce8 100644
--- a/arch/riscv/mm/Makefile
+++ b/arch/riscv/mm/Makefile
@@ -13,15 +13,12 @@ endif
KCOV_INSTRUMENT_init.o := n
obj-y += init.o
-obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o
+obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o tlbflush.o
obj-y += cacheflush.o
obj-y += context.o
obj-y += pgtable.o
obj-y += pmem.o
-ifeq ($(CONFIG_MMU),y)
-obj-$(CONFIG_SMP) += tlbflush.o
-endif
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
obj-$(CONFIG_PTDUMP_CORE) += ptdump.o
obj-$(CONFIG_KASAN) += kasan_init.o
diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
index e6659d7368b3..22d7ed5abf8e 100644
--- a/arch/riscv/mm/tlbflush.c
+++ b/arch/riscv/mm/tlbflush.c
@@ -66,6 +66,7 @@ static inline void local_flush_tlb_range_asid(unsigned long start,
local_flush_tlb_range_threshold_asid(start, size, stride, asid);
}
+#ifdef CONFIG_SMP
static void __ipi_flush_tlb_all(void *info)
{
local_flush_tlb_all();
@@ -138,6 +139,18 @@ static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
if (mm)
put_cpu();
}
+#else
+static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
+ unsigned long size, unsigned long stride)
+{
+ unsigned long asid = FLUSH_TLB_NO_ASID;
+
+ if (mm && static_branch_unlikely(&use_asid_allocator))
+ asid = atomic_long_read(&mm->context.id) & asid_mask;
+
+ local_flush_tlb_range_asid(start, size, stride, asid);
+}
+#endif
void flush_tlb_mm(struct mm_struct *mm)
{
--
2.42.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 2/8] riscv: Apply SiFive CIP-1200 workaround to single-ASID sfence.vma
2023-11-22 1:07 [PATCH v3 0/8] riscv: ASID-related and UP-related TLB flush enhancements Samuel Holland
2023-11-22 1:07 ` [PATCH v3 1/8] riscv: mm: Combine the SMP and UP TLB flush code Samuel Holland
@ 2023-11-22 1:07 ` Samuel Holland
2023-11-22 1:07 ` [PATCH v3 3/8] riscv: Avoid TLB flush loops when affected by SiFive CIP-1200 Samuel Holland
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Samuel Holland @ 2023-11-22 1:07 UTC (permalink / raw)
To: Palmer Dabbelt, linux-riscv
Cc: linux-kernel, linux-mm, Alexandre Ghiti, Samuel Holland
commit 3f1e782998cd ("riscv: add ASID-based tlbflushing methods") added
calls to the sfence.vma instruction with rs2 != x0. These single-ASID
instruction variants are also affected by SiFive errata CIP-1200.
Until now, the errata workaround was not needed for the single-ASID
sfence.vma variants, because they were only used when the ASID allocator
was enabled, and the affected SiFive platforms do not support multiple
ASIDs. However, we are going to start using those sfence.vma variants
regardless of ASID support, so now we need alternatives covering them.
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---
(no changes since v2)
Changes in v2:
- Rebase on Alexandre's "riscv: tlb flush improvements" series v5
arch/riscv/include/asm/errata_list.h | 12 +++++++++++-
arch/riscv/include/asm/tlbflush.h | 19 ++++++++++++++++++-
arch/riscv/mm/tlbflush.c | 23 -----------------------
3 files changed, 29 insertions(+), 25 deletions(-)
diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
index 83ed25e43553..6781460ae564 100644
--- a/arch/riscv/include/asm/errata_list.h
+++ b/arch/riscv/include/asm/errata_list.h
@@ -44,11 +44,21 @@ ALTERNATIVE(__stringify(RISCV_PTR do_page_fault), \
CONFIG_ERRATA_SIFIVE_CIP_453)
#else /* !__ASSEMBLY__ */
-#define ALT_FLUSH_TLB_PAGE(x) \
+#define ALT_SFENCE_VMA_ASID(asid) \
+asm(ALTERNATIVE("sfence.vma x0, %0", "sfence.vma", SIFIVE_VENDOR_ID, \
+ ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \
+ : : "r" (asid) : "memory")
+
+#define ALT_SFENCE_VMA_ADDR(addr) \
asm(ALTERNATIVE("sfence.vma %0", "sfence.vma", SIFIVE_VENDOR_ID, \
ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \
: : "r" (addr) : "memory")
+#define ALT_SFENCE_VMA_ADDR_ASID(addr, asid) \
+asm(ALTERNATIVE("sfence.vma %0, %1", "sfence.vma", SIFIVE_VENDOR_ID, \
+ ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \
+ : : "r" (addr), "r" (asid) : "memory")
+
/*
* _val is marked as "will be overwritten", so need to set it to 0
* in the default case.
diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h
index 317a1811aa51..e529a643be17 100644
--- a/arch/riscv/include/asm/tlbflush.h
+++ b/arch/riscv/include/asm/tlbflush.h
@@ -22,10 +22,27 @@ static inline void local_flush_tlb_all(void)
__asm__ __volatile__ ("sfence.vma" : : : "memory");
}
+static inline void local_flush_tlb_all_asid(unsigned long asid)
+{
+ if (asid != FLUSH_TLB_NO_ASID)
+ ALT_SFENCE_VMA_ASID(asid);
+ else
+ local_flush_tlb_all();
+}
+
/* Flush one page from local TLB */
static inline void local_flush_tlb_page(unsigned long addr)
{
- ALT_FLUSH_TLB_PAGE(__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"));
+ ALT_SFENCE_VMA_ADDR(addr);
+}
+
+static inline void local_flush_tlb_page_asid(unsigned long addr,
+ unsigned long asid)
+{
+ if (asid != FLUSH_TLB_NO_ASID)
+ ALT_SFENCE_VMA_ADDR_ASID(addr, asid);
+ else
+ local_flush_tlb_page(addr);
}
#ifdef CONFIG_SMP
diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
index 22d7ed5abf8e..0feccb8932d2 100644
--- a/arch/riscv/mm/tlbflush.c
+++ b/arch/riscv/mm/tlbflush.c
@@ -7,29 +7,6 @@
#include <asm/sbi.h>
#include <asm/mmu_context.h>
-static inline void local_flush_tlb_all_asid(unsigned long asid)
-{
- if (asid != FLUSH_TLB_NO_ASID)
- __asm__ __volatile__ ("sfence.vma x0, %0"
- :
- : "r" (asid)
- : "memory");
- else
- local_flush_tlb_all();
-}
-
-static inline void local_flush_tlb_page_asid(unsigned long addr,
- unsigned long asid)
-{
- if (asid != FLUSH_TLB_NO_ASID)
- __asm__ __volatile__ ("sfence.vma %0, %1"
- :
- : "r" (addr), "r" (asid)
- : "memory");
- else
- local_flush_tlb_page(addr);
-}
-
/*
* Flush entire TLB if number of entries to be flushed is greater
* than the threshold below.
--
2.42.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 3/8] riscv: Avoid TLB flush loops when affected by SiFive CIP-1200
2023-11-22 1:07 [PATCH v3 0/8] riscv: ASID-related and UP-related TLB flush enhancements Samuel Holland
2023-11-22 1:07 ` [PATCH v3 1/8] riscv: mm: Combine the SMP and UP TLB flush code Samuel Holland
2023-11-22 1:07 ` [PATCH v3 2/8] riscv: Apply SiFive CIP-1200 workaround to single-ASID sfence.vma Samuel Holland
@ 2023-11-22 1:07 ` Samuel Holland
2023-11-22 17:34 ` kernel test robot
2023-11-22 1:07 ` [PATCH v3 4/8] riscv: mm: Introduce cntx2asid/cntx2version helper macros Samuel Holland
` (4 subsequent siblings)
7 siblings, 1 reply; 10+ messages in thread
From: Samuel Holland @ 2023-11-22 1:07 UTC (permalink / raw)
To: Palmer Dabbelt, linux-riscv
Cc: linux-kernel, linux-mm, Alexandre Ghiti, Samuel Holland
Since implementations affected by SiFive errata CIP-1200 always use the
global variant of the sfence.vma instruction, they only need to execute
the instruction once. The range-based loop only hurts performance.
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---
Changes in v3:
- New patch for v3
arch/riscv/errata/sifive/errata.c | 3 +++
arch/riscv/include/asm/tlbflush.h | 2 ++
arch/riscv/mm/tlbflush.c | 2 +-
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
index 3d9a32d791f7..00e011d78866 100644
--- a/arch/riscv/errata/sifive/errata.c
+++ b/arch/riscv/errata/sifive/errata.c
@@ -42,6 +42,9 @@ static bool errata_cip_1200_check_func(unsigned long arch_id, unsigned long imp
return false;
if ((impid & 0xffffff) > 0x200630 || impid == 0x1200626)
return false;
+
+ tlb_flush_all_threshold = 0;
+
return true;
}
diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h
index e529a643be17..3b393f765805 100644
--- a/arch/riscv/include/asm/tlbflush.h
+++ b/arch/riscv/include/asm/tlbflush.h
@@ -62,6 +62,8 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end);
void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end);
#endif
+
+extern unsigned long tlb_flush_all_threshold;
#else /* CONFIG_MMU */
#define local_flush_tlb_all() do { } while (0)
#endif /* CONFIG_MMU */
diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
index 0feccb8932d2..27b3744b5673 100644
--- a/arch/riscv/mm/tlbflush.c
+++ b/arch/riscv/mm/tlbflush.c
@@ -11,7 +11,7 @@
* Flush entire TLB if number of entries to be flushed is greater
* than the threshold below.
*/
-static unsigned long tlb_flush_all_threshold __read_mostly = 64;
+unsigned long tlb_flush_all_threshold __read_mostly = 64;
static void local_flush_tlb_range_threshold_asid(unsigned long start,
unsigned long size,
--
2.42.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v3 3/8] riscv: Avoid TLB flush loops when affected by SiFive CIP-1200
2023-11-22 1:07 ` [PATCH v3 3/8] riscv: Avoid TLB flush loops when affected by SiFive CIP-1200 Samuel Holland
@ 2023-11-22 17:34 ` kernel test robot
0 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2023-11-22 17:34 UTC (permalink / raw)
To: Samuel Holland, Palmer Dabbelt, linux-riscv
Cc: llvm, oe-kbuild-all, linux-kernel, linux-mm, Alexandre Ghiti,
Samuel Holland
Hi Samuel,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v6.7-rc2 next-20231122]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Samuel-Holland/riscv-mm-Combine-the-SMP-and-UP-TLB-flush-code/20231122-091249
base: linus/master
patch link: https://lore.kernel.org/r/20231122010815.3545294-4-samuel.holland%40sifive.com
patch subject: [PATCH v3 3/8] riscv: Avoid TLB flush loops when affected by SiFive CIP-1200
config: riscv-randconfig-001-20231122 (https://download.01.org/0day-ci/archive/20231122/202311222306.siw2cvCj-lkp@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project.git f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231122/202311222306.siw2cvCj-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311222306.siw2cvCj-lkp@intel.com/
All errors (new ones prefixed by >>):
>> arch/riscv/errata/sifive/errata.c:46:2: error: use of undeclared identifier 'tlb_flush_all_threshold'
tlb_flush_all_threshold = 0;
^
1 error generated.
vim +/tlb_flush_all_threshold +46 arch/riscv/errata/sifive/errata.c
33
34 static bool errata_cip_1200_check_func(unsigned long arch_id, unsigned long impid)
35 {
36 /*
37 * Affected cores:
38 * Architecture ID: 0x8000000000000007 or 0x1
39 * Implement ID: mimpid[23:0] <= 0x200630 and mimpid != 0x01200626
40 */
41 if (arch_id != 0x8000000000000007 && arch_id != 0x1)
42 return false;
43 if ((impid & 0xffffff) > 0x200630 || impid == 0x1200626)
44 return false;
45
> 46 tlb_flush_all_threshold = 0;
47
48 return true;
49 }
50
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 4/8] riscv: mm: Introduce cntx2asid/cntx2version helper macros
2023-11-22 1:07 [PATCH v3 0/8] riscv: ASID-related and UP-related TLB flush enhancements Samuel Holland
` (2 preceding siblings ...)
2023-11-22 1:07 ` [PATCH v3 3/8] riscv: Avoid TLB flush loops when affected by SiFive CIP-1200 Samuel Holland
@ 2023-11-22 1:07 ` Samuel Holland
2023-11-22 1:07 ` [PATCH v3 5/8] riscv: mm: Use a fixed layout for the MM context ID Samuel Holland
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Samuel Holland @ 2023-11-22 1:07 UTC (permalink / raw)
To: Palmer Dabbelt, linux-riscv
Cc: linux-kernel, linux-mm, Alexandre Ghiti, Samuel Holland
When using the ASID allocator, the MM context ID contains two values:
the ASID in the lower bits, and the allocator version number in the
remaining bits. Use macros to make this separation more obvious.
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---
(no changes since v1)
arch/riscv/include/asm/mmu.h | 3 +++
arch/riscv/mm/context.c | 12 ++++++------
arch/riscv/mm/tlbflush.c | 4 ++--
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h
index 355504b37f8e..a550fbf770be 100644
--- a/arch/riscv/include/asm/mmu.h
+++ b/arch/riscv/include/asm/mmu.h
@@ -26,6 +26,9 @@ typedef struct {
#endif
} mm_context_t;
+#define cntx2asid(cntx) ((cntx) & asid_mask)
+#define cntx2version(cntx) ((cntx) & ~asid_mask)
+
void __init create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa,
phys_addr_t sz, pgprot_t prot);
#endif /* __ASSEMBLY__ */
diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c
index 217fd4de6134..43d005f63253 100644
--- a/arch/riscv/mm/context.c
+++ b/arch/riscv/mm/context.c
@@ -81,7 +81,7 @@ static void __flush_context(void)
if (cntx == 0)
cntx = per_cpu(reserved_context, i);
- __set_bit(cntx & asid_mask, context_asid_map);
+ __set_bit(cntx2asid(cntx), context_asid_map);
per_cpu(reserved_context, i) = cntx;
}
@@ -102,7 +102,7 @@ static unsigned long __new_context(struct mm_struct *mm)
lockdep_assert_held(&context_lock);
if (cntx != 0) {
- unsigned long newcntx = ver | (cntx & asid_mask);
+ unsigned long newcntx = ver | cntx2asid(cntx);
/*
* If our current CONTEXT was active during a rollover, we
@@ -115,7 +115,7 @@ static unsigned long __new_context(struct mm_struct *mm)
* We had a valid CONTEXT in a previous life, so try to
* re-use it if possible.
*/
- if (!__test_and_set_bit(cntx & asid_mask, context_asid_map))
+ if (!__test_and_set_bit(cntx2asid(cntx), context_asid_map))
return newcntx;
}
@@ -168,7 +168,7 @@ static void set_mm_asid(struct mm_struct *mm, unsigned int cpu)
*/
old_active_cntx = atomic_long_read(&per_cpu(active_context, cpu));
if (old_active_cntx &&
- ((cntx & ~asid_mask) == atomic_long_read(¤t_version)) &&
+ (cntx2version(cntx) == atomic_long_read(¤t_version)) &&
atomic_long_cmpxchg_relaxed(&per_cpu(active_context, cpu),
old_active_cntx, cntx))
goto switch_mm_fast;
@@ -177,7 +177,7 @@ static void set_mm_asid(struct mm_struct *mm, unsigned int cpu)
/* Check that our ASID belongs to the current_version. */
cntx = atomic_long_read(&mm->context.id);
- if ((cntx & ~asid_mask) != atomic_long_read(¤t_version)) {
+ if (cntx2version(cntx) != atomic_long_read(¤t_version)) {
cntx = __new_context(mm);
atomic_long_set(&mm->context.id, cntx);
}
@@ -191,7 +191,7 @@ static void set_mm_asid(struct mm_struct *mm, unsigned int cpu)
switch_mm_fast:
csr_write(CSR_SATP, virt_to_pfn(mm->pgd) |
- ((cntx & asid_mask) << SATP_ASID_SHIFT) |
+ (cntx2asid(cntx) << SATP_ASID_SHIFT) |
satp_mode);
if (need_flush_tlb)
diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
index 27b3744b5673..23409d70440f 100644
--- a/arch/riscv/mm/tlbflush.c
+++ b/arch/riscv/mm/tlbflush.c
@@ -91,7 +91,7 @@ static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids;
if (static_branch_unlikely(&use_asid_allocator))
- asid = atomic_long_read(&mm->context.id) & asid_mask;
+ asid = cntx2asid(atomic_long_read(&mm->context.id));
} else {
cmask = cpu_online_mask;
broadcast = true;
@@ -123,7 +123,7 @@ static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long asid = FLUSH_TLB_NO_ASID;
if (mm && static_branch_unlikely(&use_asid_allocator))
- asid = atomic_long_read(&mm->context.id) & asid_mask;
+ asid = cntx2asid(atomic_long_read(&mm->context.id));
local_flush_tlb_range_asid(start, size, stride, asid);
}
--
2.42.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 5/8] riscv: mm: Use a fixed layout for the MM context ID
2023-11-22 1:07 [PATCH v3 0/8] riscv: ASID-related and UP-related TLB flush enhancements Samuel Holland
` (3 preceding siblings ...)
2023-11-22 1:07 ` [PATCH v3 4/8] riscv: mm: Introduce cntx2asid/cntx2version helper macros Samuel Holland
@ 2023-11-22 1:07 ` Samuel Holland
2023-11-22 1:07 ` [PATCH v3 6/8] riscv: mm: Make asid_bits a local variable Samuel Holland
` (2 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Samuel Holland @ 2023-11-22 1:07 UTC (permalink / raw)
To: Palmer Dabbelt, linux-riscv
Cc: linux-kernel, linux-mm, Alexandre Ghiti, Samuel Holland
Currently, the size of the ASID field in the MM context ID dynamically
depends on the number of hardware-supported ASID bits. This requires
reading a global variable to extract either field from the context ID.
Instead, allocate the maximum possible number of bits to the ASID field,
so the layout of the context ID is known at compile-time.
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---
(no changes since v1)
arch/riscv/include/asm/mmu.h | 4 ++--
arch/riscv/include/asm/tlbflush.h | 2 --
arch/riscv/mm/context.c | 6 ++----
3 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h
index a550fbf770be..dc0273f7905f 100644
--- a/arch/riscv/include/asm/mmu.h
+++ b/arch/riscv/include/asm/mmu.h
@@ -26,8 +26,8 @@ typedef struct {
#endif
} mm_context_t;
-#define cntx2asid(cntx) ((cntx) & asid_mask)
-#define cntx2version(cntx) ((cntx) & ~asid_mask)
+#define cntx2asid(cntx) ((cntx) & SATP_ASID_MASK)
+#define cntx2version(cntx) ((cntx) & ~SATP_ASID_MASK)
void __init create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa,
phys_addr_t sz, pgprot_t prot);
diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h
index 3b393f765805..4448d907f2c9 100644
--- a/arch/riscv/include/asm/tlbflush.h
+++ b/arch/riscv/include/asm/tlbflush.h
@@ -15,8 +15,6 @@
#define FLUSH_TLB_NO_ASID ((unsigned long)-1)
#ifdef CONFIG_MMU
-extern unsigned long asid_mask;
-
static inline void local_flush_tlb_all(void)
{
__asm__ __volatile__ ("sfence.vma" : : : "memory");
diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c
index 43d005f63253..b5170ac1b742 100644
--- a/arch/riscv/mm/context.c
+++ b/arch/riscv/mm/context.c
@@ -22,7 +22,6 @@ DEFINE_STATIC_KEY_FALSE(use_asid_allocator);
static unsigned long asid_bits;
static unsigned long num_asids;
-unsigned long asid_mask;
static atomic_long_t current_version;
@@ -128,7 +127,7 @@ static unsigned long __new_context(struct mm_struct *mm)
goto set_asid;
/* We're out of ASIDs, so increment current_version */
- ver = atomic_long_add_return_relaxed(num_asids, ¤t_version);
+ ver = atomic_long_add_return_relaxed(BIT(SATP_ASID_BITS), ¤t_version);
/* Flush everything */
__flush_context();
@@ -247,7 +246,6 @@ static int __init asids_init(void)
/* Pre-compute ASID details */
if (asid_bits) {
num_asids = 1 << asid_bits;
- asid_mask = num_asids - 1;
}
/*
@@ -255,7 +253,7 @@ static int __init asids_init(void)
* at-least twice more than CPUs
*/
if (num_asids > (2 * num_possible_cpus())) {
- atomic_long_set(¤t_version, num_asids);
+ atomic_long_set(¤t_version, BIT(SATP_ASID_BITS));
context_asid_map = bitmap_zalloc(num_asids, GFP_KERNEL);
if (!context_asid_map)
--
2.42.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 6/8] riscv: mm: Make asid_bits a local variable
2023-11-22 1:07 [PATCH v3 0/8] riscv: ASID-related and UP-related TLB flush enhancements Samuel Holland
` (4 preceding siblings ...)
2023-11-22 1:07 ` [PATCH v3 5/8] riscv: mm: Use a fixed layout for the MM context ID Samuel Holland
@ 2023-11-22 1:07 ` Samuel Holland
2023-11-22 1:07 ` [PATCH v3 7/8] riscv: mm: Preserve global TLB entries when switching contexts Samuel Holland
2023-11-22 1:07 ` [PATCH v3 8/8] riscv: mm: Always use ASID to flush MM contexts Samuel Holland
7 siblings, 0 replies; 10+ messages in thread
From: Samuel Holland @ 2023-11-22 1:07 UTC (permalink / raw)
To: Palmer Dabbelt, linux-riscv
Cc: linux-kernel, linux-mm, Alexandre Ghiti, Samuel Holland
This variable is only used inside asids_init().
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---
(no changes since v1)
arch/riscv/mm/context.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c
index b5170ac1b742..43a8bc2d5af4 100644
--- a/arch/riscv/mm/context.c
+++ b/arch/riscv/mm/context.c
@@ -20,7 +20,6 @@
DEFINE_STATIC_KEY_FALSE(use_asid_allocator);
-static unsigned long asid_bits;
static unsigned long num_asids;
static atomic_long_t current_version;
@@ -226,7 +225,7 @@ static inline void set_mm(struct mm_struct *prev,
static int __init asids_init(void)
{
- unsigned long old;
+ unsigned long asid_bits, old;
/* Figure-out number of ASID bits in HW */
old = csr_read(CSR_SATP);
--
2.42.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 7/8] riscv: mm: Preserve global TLB entries when switching contexts
2023-11-22 1:07 [PATCH v3 0/8] riscv: ASID-related and UP-related TLB flush enhancements Samuel Holland
` (5 preceding siblings ...)
2023-11-22 1:07 ` [PATCH v3 6/8] riscv: mm: Make asid_bits a local variable Samuel Holland
@ 2023-11-22 1:07 ` Samuel Holland
2023-11-22 1:07 ` [PATCH v3 8/8] riscv: mm: Always use ASID to flush MM contexts Samuel Holland
7 siblings, 0 replies; 10+ messages in thread
From: Samuel Holland @ 2023-11-22 1:07 UTC (permalink / raw)
To: Palmer Dabbelt, linux-riscv
Cc: linux-kernel, linux-mm, Alexandre Ghiti, Samuel Holland
If the CPU does not support multiple ASIDs, all MM contexts use ASID 0.
In this case, it is still beneficial to flush the TLB by ASID, as the
single-ASID variant of the sfence.vma instruction preserves TLB entries
for global (kernel) pages.
This optimization is recommended by the RISC-V privileged specification:
If the implementation does not provide ASIDs, or software chooses
to always use ASID 0, then after every satp write, software should
execute SFENCE.VMA with rs1=x0. In the common case that no global
translations have been modified, rs2 should be set to a register
other than x0 but which contains the value zero, so that global
translations are not flushed.
It is not possible to apply this optimization when using the ASID
allocator, because that code must flush the TLB for all ASIDs at once
when incrementing the version number.
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---
(no changes since v1)
arch/riscv/mm/context.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c
index 43a8bc2d5af4..3ca9b653df7d 100644
--- a/arch/riscv/mm/context.c
+++ b/arch/riscv/mm/context.c
@@ -200,7 +200,7 @@ static void set_mm_noasid(struct mm_struct *mm)
{
/* Switch the page table and blindly nuke entire local TLB */
csr_write(CSR_SATP, virt_to_pfn(mm->pgd) | satp_mode);
- local_flush_tlb_all();
+ local_flush_tlb_all_asid(0);
}
static inline void set_mm(struct mm_struct *prev,
--
2.42.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 8/8] riscv: mm: Always use ASID to flush MM contexts
2023-11-22 1:07 [PATCH v3 0/8] riscv: ASID-related and UP-related TLB flush enhancements Samuel Holland
` (6 preceding siblings ...)
2023-11-22 1:07 ` [PATCH v3 7/8] riscv: mm: Preserve global TLB entries when switching contexts Samuel Holland
@ 2023-11-22 1:07 ` Samuel Holland
7 siblings, 0 replies; 10+ messages in thread
From: Samuel Holland @ 2023-11-22 1:07 UTC (permalink / raw)
To: Palmer Dabbelt, linux-riscv
Cc: linux-kernel, linux-mm, Alexandre Ghiti, Samuel Holland
Even if multiple ASIDs are not supported, using the single-ASID variant
of the sfence.vma instruction preserves TLB entries for global (kernel)
pages. So it is always more efficient to use the single-ASID code path.
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---
(no changes since v2)
Changes in v2:
- Update both copies of __flush_tlb_range()
arch/riscv/include/asm/mmu_context.h | 2 --
arch/riscv/mm/context.c | 3 +--
arch/riscv/mm/tlbflush.c | 5 ++---
3 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/arch/riscv/include/asm/mmu_context.h b/arch/riscv/include/asm/mmu_context.h
index 7030837adc1a..b0659413a080 100644
--- a/arch/riscv/include/asm/mmu_context.h
+++ b/arch/riscv/include/asm/mmu_context.h
@@ -33,8 +33,6 @@ static inline int init_new_context(struct task_struct *tsk,
return 0;
}
-DECLARE_STATIC_KEY_FALSE(use_asid_allocator);
-
#include <asm-generic/mmu_context.h>
#endif /* _ASM_RISCV_MMU_CONTEXT_H */
diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c
index 3ca9b653df7d..20057085ab8a 100644
--- a/arch/riscv/mm/context.c
+++ b/arch/riscv/mm/context.c
@@ -18,8 +18,7 @@
#ifdef CONFIG_MMU
-DEFINE_STATIC_KEY_FALSE(use_asid_allocator);
-
+static DEFINE_STATIC_KEY_FALSE(use_asid_allocator);
static unsigned long num_asids;
static atomic_long_t current_version;
diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
index 23409d70440f..d6619be10341 100644
--- a/arch/riscv/mm/tlbflush.c
+++ b/arch/riscv/mm/tlbflush.c
@@ -90,8 +90,7 @@ static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
/* check if the tlbflush needs to be sent to other CPUs */
broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids;
- if (static_branch_unlikely(&use_asid_allocator))
- asid = cntx2asid(atomic_long_read(&mm->context.id));
+ asid = cntx2asid(atomic_long_read(&mm->context.id));
} else {
cmask = cpu_online_mask;
broadcast = true;
@@ -122,7 +121,7 @@ static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
{
unsigned long asid = FLUSH_TLB_NO_ASID;
- if (mm && static_branch_unlikely(&use_asid_allocator))
+ if (mm)
asid = cntx2asid(atomic_long_read(&mm->context.id));
local_flush_tlb_range_asid(start, size, stride, asid);
--
2.42.0
^ permalink raw reply [flat|nested] 10+ messages in thread