Skip to content

Commit dc892fb

Browse files
SiFiveHollandpalmer-dabbelt
authored andcommitted
riscv: Use IPIs for remote cache/TLB flushes by default
An IPI backend is always required in an SMP configuration, but an SBI implementation is not. For example, SBI will be unavailable when the kernel runs in M mode. For this reason, consider IPI delivery of cache and TLB flushes to be the base case, and any other implementation (such as the SBI remote fence extension) to be an optimization. Generally, if IPIs can be delivered without firmware assistance, they are assumed to be faster than SBI calls due to the SBI context switch overhead. However, when SBI is used as the IPI backend, then the context switch cost must be paid anyway, and performing the cache/TLB flush directly in the SBI implementation is more efficient than injecting an interrupt to S-mode. This is the only existing scenario where riscv_ipi_set_virq_range() is called with use_for_rfence set to false. sbi_ipi_init() already checks riscv_ipi_have_virq_range(), so it only calls riscv_ipi_set_virq_range() when no other IPI device is available. This allows moving the static key and dropping the use_for_rfence parameter. This decouples the static key from the irqchip driver probe order. Furthermore, the static branch only makes sense when CONFIG_RISCV_SBI is enabled. Optherwise, IPIs must be used. Add a fallback definition of riscv_use_sbi_for_rfence() which handles this case and removes the need to check CONFIG_RISCV_SBI elsewhere, such as in cacheflush.c. Reviewed-by: Anup Patel <anup@brainfault.org> Signed-off-by: Samuel Holland <samuel.holland@sifive.com> Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com> Link: https://lore.kernel.org/r/20240327045035.368512-4-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
1 parent aaa56c8 commit dc892fb

8 files changed

Lines changed: 38 additions & 48 deletions

File tree

arch/riscv/include/asm/pgalloc.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#define _ASM_RISCV_PGALLOC_H
99

1010
#include <linux/mm.h>
11+
#include <asm/sbi.h>
1112
#include <asm/tlb.h>
1213

1314
#ifdef CONFIG_MMU
@@ -17,10 +18,10 @@
1718

1819
static inline void riscv_tlb_remove_ptdesc(struct mmu_gather *tlb, void *pt)
1920
{
20-
if (riscv_use_ipi_for_rfence())
21-
tlb_remove_page_ptdesc(tlb, pt);
22-
else
21+
if (riscv_use_sbi_for_rfence())
2322
tlb_remove_ptdesc(tlb, pt);
23+
else
24+
tlb_remove_page_ptdesc(tlb, pt);
2425
}
2526

2627
static inline void pmd_populate_kernel(struct mm_struct *mm,

arch/riscv/include/asm/sbi.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,12 @@ unsigned long riscv_cached_marchid(unsigned int cpu_id);
375375
unsigned long riscv_cached_mimpid(unsigned int cpu_id);
376376

377377
#if IS_ENABLED(CONFIG_SMP) && IS_ENABLED(CONFIG_RISCV_SBI)
378+
DECLARE_STATIC_KEY_FALSE(riscv_sbi_for_rfence);
379+
#define riscv_use_sbi_for_rfence() \
380+
static_branch_unlikely(&riscv_sbi_for_rfence)
378381
void sbi_ipi_init(void);
379382
#else
383+
static inline bool riscv_use_sbi_for_rfence(void) { return false; }
380384
static inline void sbi_ipi_init(void) { }
381385
#endif
382386

arch/riscv/include/asm/smp.h

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,7 @@ void riscv_ipi_disable(void);
4949
bool riscv_ipi_have_virq_range(void);
5050

5151
/* Set the IPI interrupt numbers for arch (called by irqchip drivers) */
52-
void riscv_ipi_set_virq_range(int virq, int nr, bool use_for_rfence);
53-
54-
/* Check if we can use IPIs for remote FENCEs */
55-
DECLARE_STATIC_KEY_FALSE(riscv_ipi_for_rfence);
56-
#define riscv_use_ipi_for_rfence() \
57-
static_branch_unlikely(&riscv_ipi_for_rfence)
52+
void riscv_ipi_set_virq_range(int virq, int nr);
5853

5954
/* Check other CPUs stop or not */
6055
bool smp_crash_stop_failed(void);
@@ -104,16 +99,10 @@ static inline bool riscv_ipi_have_virq_range(void)
10499
return false;
105100
}
106101

107-
static inline void riscv_ipi_set_virq_range(int virq, int nr,
108-
bool use_for_rfence)
102+
static inline void riscv_ipi_set_virq_range(int virq, int nr)
109103
{
110104
}
111105

112-
static inline bool riscv_use_ipi_for_rfence(void)
113-
{
114-
return false;
115-
}
116-
117106
#endif /* CONFIG_SMP */
118107

119108
#if defined(CONFIG_HOTPLUG_CPU) && (CONFIG_SMP)

arch/riscv/kernel/sbi-ipi.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#include <linux/irqdomain.h>
1414
#include <asm/sbi.h>
1515

16+
DEFINE_STATIC_KEY_FALSE(riscv_sbi_for_rfence);
17+
EXPORT_SYMBOL_GPL(riscv_sbi_for_rfence);
18+
1619
static int sbi_ipi_virq;
1720

1821
static void sbi_ipi_handle(struct irq_desc *desc)
@@ -72,6 +75,12 @@ void __init sbi_ipi_init(void)
7275
"irqchip/sbi-ipi:starting",
7376
sbi_ipi_starting_cpu, NULL);
7477

75-
riscv_ipi_set_virq_range(virq, BITS_PER_BYTE, false);
78+
riscv_ipi_set_virq_range(virq, BITS_PER_BYTE);
7679
pr_info("providing IPIs using SBI IPI extension\n");
80+
81+
/*
82+
* Use the SBI remote fence extension to avoid
83+
* the extra context switch needed to handle IPIs.
84+
*/
85+
static_branch_enable(&riscv_sbi_for_rfence);
7786
}

arch/riscv/kernel/smp.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,7 @@ bool riscv_ipi_have_virq_range(void)
171171
return (ipi_virq_base) ? true : false;
172172
}
173173

174-
DEFINE_STATIC_KEY_FALSE(riscv_ipi_for_rfence);
175-
EXPORT_SYMBOL_GPL(riscv_ipi_for_rfence);
176-
177-
void riscv_ipi_set_virq_range(int virq, int nr, bool use_for_rfence)
174+
void riscv_ipi_set_virq_range(int virq, int nr)
178175
{
179176
int i, err;
180177

@@ -197,12 +194,6 @@ void riscv_ipi_set_virq_range(int virq, int nr, bool use_for_rfence)
197194

198195
/* Enabled IPIs for boot CPU immediately */
199196
riscv_ipi_enable();
200-
201-
/* Update RFENCE static key */
202-
if (use_for_rfence)
203-
static_branch_enable(&riscv_ipi_for_rfence);
204-
else
205-
static_branch_disable(&riscv_ipi_for_rfence);
206197
}
207198

208199
static const char * const ipi_names[] = {

arch/riscv/mm/cacheflush.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ void flush_icache_all(void)
2121
{
2222
local_flush_icache_all();
2323

24-
if (IS_ENABLED(CONFIG_RISCV_SBI) && !riscv_use_ipi_for_rfence())
24+
if (riscv_use_sbi_for_rfence())
2525
sbi_remote_fence_i(NULL);
2626
else
2727
on_each_cpu(ipi_remote_fence_i, NULL, 1);
@@ -69,8 +69,7 @@ void flush_icache_mm(struct mm_struct *mm, bool local)
6969
* with flush_icache_deferred().
7070
*/
7171
smp_mb();
72-
} else if (IS_ENABLED(CONFIG_RISCV_SBI) &&
73-
!riscv_use_ipi_for_rfence()) {
72+
} else if (riscv_use_sbi_for_rfence()) {
7473
sbi_remote_fence_i(&others);
7574
} else {
7675
on_each_cpu_mask(&others, ipi_remote_fence_i, NULL, 1);

arch/riscv/mm/tlbflush.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ static void __ipi_flush_tlb_all(void *info)
7979

8080
void flush_tlb_all(void)
8181
{
82-
if (riscv_use_ipi_for_rfence())
83-
on_each_cpu(__ipi_flush_tlb_all, NULL, 1);
84-
else
82+
if (riscv_use_sbi_for_rfence())
8583
sbi_remote_sfence_vma_asid(NULL, 0, FLUSH_TLB_MAX_SIZE, FLUSH_TLB_NO_ASID);
84+
else
85+
on_each_cpu(__ipi_flush_tlb_all, NULL, 1);
8686
}
8787

8888
struct flush_tlb_range_data {
@@ -103,7 +103,6 @@ static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid,
103103
unsigned long start, unsigned long size,
104104
unsigned long stride)
105105
{
106-
struct flush_tlb_range_data ftd;
107106
bool broadcast;
108107

109108
if (cpumask_empty(cmask))
@@ -119,20 +118,18 @@ static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid,
119118
broadcast = true;
120119
}
121120

122-
if (broadcast) {
123-
if (riscv_use_ipi_for_rfence()) {
124-
ftd.asid = asid;
125-
ftd.start = start;
126-
ftd.size = size;
127-
ftd.stride = stride;
128-
on_each_cpu_mask(cmask,
129-
__ipi_flush_tlb_range_asid,
130-
&ftd, 1);
131-
} else
132-
sbi_remote_sfence_vma_asid(cmask,
133-
start, size, asid);
134-
} else {
121+
if (!broadcast) {
135122
local_flush_tlb_range_asid(start, size, stride, asid);
123+
} else if (riscv_use_sbi_for_rfence()) {
124+
sbi_remote_sfence_vma_asid(cmask, start, size, asid);
125+
} else {
126+
struct flush_tlb_range_data ftd;
127+
128+
ftd.asid = asid;
129+
ftd.start = start;
130+
ftd.size = size;
131+
ftd.stride = stride;
132+
on_each_cpu_mask(cmask, __ipi_flush_tlb_range_asid, &ftd, 1);
136133
}
137134

138135
if (cmask != cpu_online_mask)

drivers/clocksource/timer-clint.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ static int __init clint_timer_init_dt(struct device_node *np)
251251
}
252252

253253
irq_set_chained_handler(clint_ipi_irq, clint_ipi_interrupt);
254-
riscv_ipi_set_virq_range(rc, BITS_PER_BYTE, true);
254+
riscv_ipi_set_virq_range(rc, BITS_PER_BYTE);
255255
clint_clear_ipi();
256256
#endif
257257

0 commit comments

Comments
 (0)