Skip to content

Commit cc7f3f7

Browse files
avpatelpalmer-dabbelt
authored andcommitted
RISC-V: Add mechanism to provide custom IPI operations
We add mechanism to set custom IPI operations so that CLINT driver from drivers directory can provide custom IPI operations. Signed-off-by: Anup Patel <[email protected]> Tested-by: Emil Renner Berhing <[email protected]> Reviewed-by: Atish Patra <[email protected]> Reviewed-by: Palmer Dabbelt <[email protected]> Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 9123e3a commit cc7f3f7

File tree

6 files changed

+79
-48
lines changed

6 files changed

+79
-48
lines changed

arch/riscv/include/asm/clint.h

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,9 @@
66
#include <linux/smp.h>
77

88
#ifdef CONFIG_RISCV_M_MODE
9-
extern u32 __iomem *clint_ipi_base;
10-
119
void clint_init_boot_cpu(void);
12-
13-
static inline void clint_send_ipi_single(unsigned long hartid)
14-
{
15-
writel(1, clint_ipi_base + hartid);
16-
}
17-
18-
static inline void clint_send_ipi_mask(const struct cpumask *mask)
19-
{
20-
int cpu;
21-
22-
for_each_cpu(cpu, mask)
23-
clint_send_ipi_single(cpuid_to_hartid_map(cpu));
24-
}
25-
26-
static inline void clint_clear_ipi(unsigned long hartid)
27-
{
28-
writel(0, clint_ipi_base + hartid);
29-
}
3010
#else /* CONFIG_RISCV_M_MODE */
3111
#define clint_init_boot_cpu() do { } while (0)
32-
33-
/* stubs to for code is only reachable under IS_ENABLED(CONFIG_RISCV_M_MODE): */
34-
void clint_send_ipi_single(unsigned long hartid);
35-
void clint_send_ipi_mask(const struct cpumask *hartid_mask);
36-
void clint_clear_ipi(unsigned long hartid);
3712
#endif /* CONFIG_RISCV_M_MODE */
3813

3914
#endif /* _ASM_RISCV_CLINT_H */

arch/riscv/include/asm/smp.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
struct seq_file;
1616
extern unsigned long boot_cpu_hartid;
1717

18+
struct riscv_ipi_ops {
19+
void (*ipi_inject)(const struct cpumask *target);
20+
void (*ipi_clear)(void);
21+
};
22+
1823
#ifdef CONFIG_SMP
1924
/*
2025
* Mapping between linux logical cpu index and hartid.
@@ -40,6 +45,12 @@ void arch_send_call_function_single_ipi(int cpu);
4045
int riscv_hartid_to_cpuid(int hartid);
4146
void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out);
4247

48+
/* Set custom IPI operations */
49+
void riscv_set_ipi_ops(struct riscv_ipi_ops *ops);
50+
51+
/* Clear IPI for current CPU */
52+
void riscv_clear_ipi(void);
53+
4354
/* Secondary hart entry */
4455
asmlinkage void smp_callin(void);
4556

@@ -81,6 +92,14 @@ static inline void riscv_cpuid_to_hartid_mask(const struct cpumask *in,
8192
cpumask_set_cpu(boot_cpu_hartid, out);
8293
}
8394

95+
static inline void riscv_set_ipi_ops(struct riscv_ipi_ops *ops)
96+
{
97+
}
98+
99+
static inline void riscv_clear_ipi(void)
100+
{
101+
}
102+
84103
#endif /* CONFIG_SMP */
85104

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

arch/riscv/kernel/clint.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55

66
#include <linux/io.h>
77
#include <linux/of_address.h>
8+
#include <linux/smp.h>
89
#include <linux/types.h>
910
#include <asm/clint.h>
1011
#include <asm/csr.h>
1112
#include <asm/timex.h>
12-
#include <asm/smp.h>
1313

1414
/*
1515
* This is the layout used by the SiFive clint, which is also shared by the qemu
@@ -21,6 +21,24 @@
2121

2222
u32 __iomem *clint_ipi_base;
2323

24+
static void clint_send_ipi(const struct cpumask *target)
25+
{
26+
unsigned int cpu;
27+
28+
for_each_cpu(cpu, target)
29+
writel(1, clint_ipi_base + cpuid_to_hartid_map(cpu));
30+
}
31+
32+
static void clint_clear_ipi(void)
33+
{
34+
writel(0, clint_ipi_base + cpuid_to_hartid_map(smp_processor_id()));
35+
}
36+
37+
static struct riscv_ipi_ops clint_ipi_ops = {
38+
.ipi_inject = clint_send_ipi,
39+
.ipi_clear = clint_clear_ipi,
40+
};
41+
2442
void clint_init_boot_cpu(void)
2543
{
2644
struct device_node *np;
@@ -40,5 +58,6 @@ void clint_init_boot_cpu(void)
4058
riscv_time_cmp = base + CLINT_TIME_CMP_OFF;
4159
riscv_time_val = base + CLINT_TIME_VAL_OFF;
4260

43-
clint_clear_ipi(boot_cpu_hartid);
61+
clint_clear_ipi();
62+
riscv_set_ipi_ops(&clint_ipi_ops);
4463
}

arch/riscv/kernel/sbi.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,18 @@ static inline long sbi_get_firmware_version(void)
547547
return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION);
548548
}
549549

550+
static void sbi_send_cpumask_ipi(const struct cpumask *target)
551+
{
552+
struct cpumask hartid_mask;
553+
554+
riscv_cpuid_to_hartid_mask(target, &hartid_mask);
555+
556+
sbi_send_ipi(cpumask_bits(&hartid_mask));
557+
}
558+
559+
static struct riscv_ipi_ops sbi_ipi_ops = {
560+
.ipi_inject = sbi_send_cpumask_ipi
561+
};
550562

551563
int __init sbi_init(void)
552564
{
@@ -587,5 +599,7 @@ int __init sbi_init(void)
587599
__sbi_rfence = __sbi_rfence_v01;
588600
}
589601

602+
riscv_set_ipi_ops(&sbi_ipi_ops);
603+
590604
return 0;
591605
}

arch/riscv/kernel/smp.c

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -86,43 +86,48 @@ static void ipi_stop(void)
8686
wait_for_interrupt();
8787
}
8888

89+
static struct riscv_ipi_ops *ipi_ops;
90+
91+
void riscv_set_ipi_ops(struct riscv_ipi_ops *ops)
92+
{
93+
ipi_ops = ops;
94+
}
95+
EXPORT_SYMBOL_GPL(riscv_set_ipi_ops);
96+
97+
void riscv_clear_ipi(void)
98+
{
99+
if (ipi_ops && ipi_ops->ipi_clear)
100+
ipi_ops->ipi_clear();
101+
102+
csr_clear(CSR_IP, IE_SIE);
103+
}
104+
EXPORT_SYMBOL_GPL(riscv_clear_ipi);
105+
89106
static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op)
90107
{
91-
struct cpumask hartid_mask;
92108
int cpu;
93109

94110
smp_mb__before_atomic();
95111
for_each_cpu(cpu, mask)
96112
set_bit(op, &ipi_data[cpu].bits);
97113
smp_mb__after_atomic();
98114

99-
riscv_cpuid_to_hartid_mask(mask, &hartid_mask);
100-
if (IS_ENABLED(CONFIG_RISCV_SBI))
101-
sbi_send_ipi(cpumask_bits(&hartid_mask));
115+
if (ipi_ops && ipi_ops->ipi_inject)
116+
ipi_ops->ipi_inject(mask);
102117
else
103-
clint_send_ipi_mask(mask);
118+
pr_warn("SMP: IPI inject method not available\n");
104119
}
105120

106121
static void send_ipi_single(int cpu, enum ipi_message_type op)
107122
{
108-
int hartid = cpuid_to_hartid_map(cpu);
109-
110123
smp_mb__before_atomic();
111124
set_bit(op, &ipi_data[cpu].bits);
112125
smp_mb__after_atomic();
113126

114-
if (IS_ENABLED(CONFIG_RISCV_SBI))
115-
sbi_send_ipi(cpumask_bits(cpumask_of(hartid)));
116-
else
117-
clint_send_ipi_single(hartid);
118-
}
119-
120-
static inline void clear_ipi(void)
121-
{
122-
if (IS_ENABLED(CONFIG_RISCV_SBI))
123-
csr_clear(CSR_IP, IE_SIE);
127+
if (ipi_ops && ipi_ops->ipi_inject)
128+
ipi_ops->ipi_inject(cpumask_of(cpu));
124129
else
125-
clint_clear_ipi(cpuid_to_hartid_map(smp_processor_id()));
130+
pr_warn("SMP: IPI inject method not available\n");
126131
}
127132

128133
#ifdef CONFIG_IRQ_WORK
@@ -140,7 +145,7 @@ void handle_IPI(struct pt_regs *regs)
140145

141146
irq_enter();
142147

143-
clear_ipi();
148+
riscv_clear_ipi();
144149

145150
while (true) {
146151
unsigned long ops;

arch/riscv/kernel/smpboot.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,7 @@ asmlinkage __visible void smp_callin(void)
147147
struct mm_struct *mm = &init_mm;
148148
unsigned int curr_cpuid = smp_processor_id();
149149

150-
if (!IS_ENABLED(CONFIG_RISCV_SBI))
151-
clint_clear_ipi(cpuid_to_hartid_map(smp_processor_id()));
150+
riscv_clear_ipi();
152151

153152
/* All kernel threads share the same mm context. */
154153
mmgrab(mm);

0 commit comments

Comments
 (0)