Skip to content

Commit 998cfd5

Browse files
committed
arch: riscv: smp: add PLIC-based IPI implementation
Add PLIC-based IPI implementation. Signed-off-by: Yong Cong Sin <[email protected]>
1 parent b35bcfe commit 998cfd5

File tree

5 files changed

+191
-0
lines changed

5 files changed

+191
-0
lines changed

arch/riscv/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ choice RISCV_SMP_IPI_IMPL
4141
prompt "RISC-V SMP IPI implementation"
4242
depends on SMP
4343
default RISCV_SMP_IPI_CLINT if DT_HAS_SIFIVE_CLINT0_ENABLED
44+
default RISCV_SMP_IPI_PLIC if PLIC_SUPPORTS_SOFT_INTERRUPT && PLIC_IRQ_AFFINITY
4445
default RISCV_SMP_IPI_CUSTOM
4546

4647
config RISCV_SMP_IPI_CLINT
@@ -49,6 +50,14 @@ config RISCV_SMP_IPI_CLINT
4950
help
5051
Use CLINT-based IPI implementation.
5152

53+
config RISCV_SMP_IPI_PLIC
54+
bool "PLIC-based IPI"
55+
depends on PLIC_SUPPORTS_SOFT_INTERRUPT
56+
depends on PLIC_IRQ_AFFINITY
57+
depends on !FPU_SHARING # not supported for now
58+
help
59+
Use PLIC-based IPI implementation.
60+
5261
config RISCV_SMP_IPI_CUSTOM
5362
bool "Custom IPI implementation"
5463
help

arch/riscv/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ if (CONFIG_SMP)
2121
zephyr_library_sources(ipi.c)
2222

2323
zephyr_library_sources_ifdef(CONFIG_RISCV_SMP_IPI_CLINT ipi_clint.c)
24+
zephyr_library_sources_ifdef(CONFIG_RISCV_SMP_IPI_PLIC ipi_plic.c)
2425
endif()
2526

2627
zephyr_library_sources_ifdef(CONFIG_FPU_SHARING fpu.c fpu.S)

arch/riscv/core/ipi_plic.c

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Copyright (c) 2024 Meta Platforms
3+
* Copyright (c) 2021 Intel Corporation
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <ipi.h>
9+
10+
#include <zephyr/devicetree.h>
11+
#include <zephyr/drivers/interrupt_controller/riscv_plic.h>
12+
#include <zephyr/kernel.h>
13+
#include <zephyr/sys/util.h>
14+
15+
#ifdef CONFIG_FPU_SHARING
16+
#define FPU_IPI_NODE DT_NODELABEL(fpu_ipi)
17+
#define FPU_IPI_NUM_IRQS DT_NUM_IRQS(FPU_IPI_NODE)
18+
#define FPU_IPI_IRQ(n) DT_IRQN_BY_IDX(FPU_IPI_NODE, n + CONFIG_MP_MAX_NUM_CPUS)
19+
#define FPU_IPI_IRQS_FN(n, _) DT_IRQN_BY_IDX(FPU_IPI_NODE, n)
20+
static const uint32_t fpu_ipi_irqs[FPU_IPI_NUM_IRQS] = {
21+
LISTIFY(FPU_IPI_NUM_IRQS, FPU_IPI_IRQS_FN, (,)),
22+
};
23+
24+
static ALWAYS_INLINE void send_fpu_ipi(int cpu)
25+
{
26+
riscv_plic_irq_set_pending(fpu_ipi_irqs[cpu]);
27+
}
28+
29+
static ALWAYS_INLINE bool fpu_ipi_irq_is_pending(int cpu)
30+
{
31+
return riscv_plic_irq_is_pending(fpu_ipi_irqs[cpu]);
32+
}
33+
34+
static ALWAYS_INLINE void fpu_ipi_irq_clear_pending(int cpu)
35+
{
36+
riscv_plic_irq_clear_pending(fpu_ipi_irqs[cpu]);
37+
}
38+
39+
static void fpu_ipi_handler(const void *arg)
40+
{
41+
ARG_UNUSED(arg);
42+
43+
/* disable IRQs */
44+
csr_clear(mstatus, MSTATUS_IEN);
45+
/* perform the flush */
46+
arch_flush_local_fpu();
47+
/*
48+
* No need to re-enable IRQs here as long as
49+
* this remains the last case.
50+
*/
51+
}
52+
53+
void arch_flush_fpu_ipi(unsigned int cpu)
54+
{
55+
send_fpu_ipi(i);
56+
}
57+
58+
/*
59+
* Make sure there is no pending FPU flush request for this CPU while
60+
* waiting for a contended spinlock to become available. This prevents
61+
* a deadlock when the lock we need is already taken by another CPU
62+
* that also wants its FPU content to be reinstated while such content
63+
* is still live in this CPU's FPU.
64+
*/
65+
void arch_spin_relax(void)
66+
{
67+
int cpu = _current_cpu->id;
68+
69+
if (fpu_ipi_irq_is_pending(cpu)) {
70+
fpu_ipi_irq_clear_pending(cpu);
71+
/*
72+
* We may not be in IRQ context here hence cannot use
73+
* arch_flush_local_fpu() directly.
74+
*/
75+
arch_float_disable(_current_cpu->arch.fpu_owner);
76+
}
77+
}
78+
#define FPU_IPI_IRQ_CONNECT(n, _) \
79+
IRQ_CONNECT(FPU_IPI_IRQ(n), 1, fpu_ipi_handler, UINT_TO_POINTER(n), 0); \
80+
irq_enable(FPU_IPI_IRQ(n)); \
81+
riscv_plic_irq_set_affinity(FPU_IPI_IRQ(n), BIT(n))
82+
83+
#define fpu_ipi_irqs_setup() LISTIFY(CONFIG_MP_MAX_NUM_CPUS, FPU_IPI_IRQ_CONNECT, (;))
84+
#else
85+
#define fpu_ipi_irqs_setup()
86+
#endif /* CONFIG_FPU_SHARING */
87+
88+
#define SCHED_IPI_NODE DT_NODELABEL(sched_ipi)
89+
#define SCHED_IPI_NUM_IRQS DT_NUM_IRQS(SCHED_IPI_NODE)
90+
#define SCHED_IPI_IRQ(n) DT_IRQN_BY_IDX(SCHED_IPI_NODE, n)
91+
#define SCHED_IPI_IRQS_FN(n, _) DT_IRQN_BY_IDX(SCHED_IPI_NODE, n)
92+
static const uint32_t sched_ipi_irqs[SCHED_IPI_NUM_IRQS] = {
93+
LISTIFY(SCHED_IPI_NUM_IRQS, SCHED_IPI_IRQS_FN, (,)),
94+
};
95+
96+
static ALWAYS_INLINE void send_sched_ipi(int cpu)
97+
{
98+
riscv_plic_irq_set_pending(sched_ipi_irqs[cpu]);
99+
}
100+
101+
void arch_sched_directed_ipi(uint32_t cpu_bitmap)
102+
{
103+
unsigned int key = arch_irq_lock();
104+
unsigned int id = _current_cpu->id;
105+
unsigned int num_cpus = arch_num_cpus();
106+
107+
for (unsigned int i = 0; i < num_cpus; i++) {
108+
if ((i != id) && _kernel.cpus[i].arch.online && ((cpu_bitmap & BIT(i)) != 0)) {
109+
send_sched_ipi(i);
110+
}
111+
}
112+
113+
arch_irq_unlock(key);
114+
}
115+
116+
static void sched_ipi_handler(const void *arg)
117+
{
118+
ARG_UNUSED(arg);
119+
120+
z_sched_ipi();
121+
}
122+
123+
#define SCHED_IPI_IRQ_CONNECT(n, _) \
124+
IRQ_CONNECT(SCHED_IPI_IRQ(n), 1, sched_ipi_handler, UINT_TO_POINTER(n), 0); \
125+
irq_enable(SCHED_IPI_IRQ(n)); \
126+
riscv_plic_irq_set_affinity(SCHED_IPI_IRQ(n), BIT(n))
127+
128+
#define sched_ipi_irqs_setup() LISTIFY(CONFIG_MP_MAX_NUM_CPUS, SCHED_IPI_IRQ_CONNECT, (;))
129+
130+
int arch_smp_init(void)
131+
{
132+
sched_ipi_irqs_setup();
133+
fpu_ipi_irqs_setup();
134+
135+
return 0;
136+
}
137+

boards/andestech/adp_xc7k_ae350/adp_xc7k_ae350.dts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,35 @@
140140
zephyr,code = <INPUT_KEY_6>;
141141
};
142142
};
143+
144+
sched_ipi: sched_ipi {
145+
compatible = "zephyr,ipi-plic";
146+
interrupt-parent = <&plic_sw>;
147+
interrupts =
148+
/* sched IPI IRQs */
149+
<32 1>, /* CPU 0 */
150+
<33 1>, /* CPU 1 */
151+
<34 1>, /* CPU 2 */
152+
<35 1>, /* CPU 3 */
153+
<36 1>, /* CPU 4 */
154+
<37 1>, /* CPU 5 */
155+
<38 1>, /* CPU 6 */
156+
<39 1>; /* CPU 7 */
157+
};
158+
159+
fpu_ipi: fpu_ipi {
160+
compatible = "zephyr,ipi-plic";
161+
interrupt-parent = <&plic_sw>;
162+
interrupts =
163+
<40 1>, /* CPU 0 */
164+
<41 1>, /* CPU 1 */
165+
<42 1>, /* CPU 2 */
166+
<43 1>, /* CPU 3 */
167+
<44 1>, /* CPU 4 */
168+
<45 1>, /* CPU 5 */
169+
<46 1>, /* CPU 6 */
170+
<47 1>; /* CPU 7 */
171+
};
143172
};
144173

145174
&l2_cache {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) 2024 Meta Platforms
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: IPI PLIC pseudo device
5+
6+
compatible: "zephyr,ipi-plic"
7+
8+
include: [base.yaml]
9+
10+
properties:
11+
interrupt-parent:
12+
required: true
13+
14+
interrupts:
15+
required: true

0 commit comments

Comments
 (0)