Skip to content

Commit ccbe80b

Browse files
atishp04Marc Zyngier
authored andcommitted
irqchip/sifive-plic: Enable/Disable external interrupts upon cpu online/offline
Currently, PLIC threshold is only initialized once in the beginning. However, threshold can be set to disabled if a CPU is marked offline with CPU hotplug feature. This will not allow to change the irq affinity to a CPU that just came online. Add PLIC specific CPU hotplug callbacks and enable the threshold when a CPU comes online. Take this opportunity to move the external interrupt enable code from trap init to PLIC driver as well. On cpu offline path, the driver performs the exact opposite operations i.e. disable the interrupt and the threshold. Signed-off-by: Atish Patra <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Reviewed-by: Anup Patel <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2ef1cb7 commit ccbe80b

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

arch/riscv/kernel/traps.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,5 +157,5 @@ void __init trap_init(void)
157157
/* Set the exception vector address */
158158
csr_write(CSR_TVEC, &handle_exception);
159159
/* Enable interrupts */
160-
csr_write(CSR_IE, IE_SIE | IE_EIE);
160+
csr_write(CSR_IE, IE_SIE);
161161
}

drivers/irqchip/irq-sifive-plic.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Copyright (C) 2018 Christoph Hellwig
55
*/
66
#define pr_fmt(fmt) "plic: " fmt
7+
#include <linux/cpu.h>
78
#include <linux/interrupt.h>
89
#include <linux/io.h>
910
#include <linux/irq.h>
@@ -55,6 +56,9 @@
5556
#define CONTEXT_THRESHOLD 0x00
5657
#define CONTEXT_CLAIM 0x04
5758

59+
#define PLIC_DISABLE_THRESHOLD 0xf
60+
#define PLIC_ENABLE_THRESHOLD 0
61+
5862
static void __iomem *plic_regs;
5963

6064
struct plic_handler {
@@ -230,6 +234,32 @@ static int plic_find_hart_id(struct device_node *node)
230234
return -1;
231235
}
232236

237+
static void plic_set_threshold(struct plic_handler *handler, u32 threshold)
238+
{
239+
/* priority must be > threshold to trigger an interrupt */
240+
writel(threshold, handler->hart_base + CONTEXT_THRESHOLD);
241+
}
242+
243+
static int plic_dying_cpu(unsigned int cpu)
244+
{
245+
struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
246+
247+
csr_clear(CSR_IE, IE_EIE);
248+
plic_set_threshold(handler, PLIC_DISABLE_THRESHOLD);
249+
250+
return 0;
251+
}
252+
253+
static int plic_starting_cpu(unsigned int cpu)
254+
{
255+
struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
256+
257+
csr_set(CSR_IE, IE_EIE);
258+
plic_set_threshold(handler, PLIC_ENABLE_THRESHOLD);
259+
260+
return 0;
261+
}
262+
233263
static int __init plic_init(struct device_node *node,
234264
struct device_node *parent)
235265
{
@@ -267,7 +297,6 @@ static int __init plic_init(struct device_node *node,
267297
struct plic_handler *handler;
268298
irq_hw_number_t hwirq;
269299
int cpu, hartid;
270-
u32 threshold = 0;
271300

272301
if (of_irq_parse_one(node, i, &parent)) {
273302
pr_err("failed to parse parent for context %d.\n", i);
@@ -301,7 +330,7 @@ static int __init plic_init(struct device_node *node,
301330
handler = per_cpu_ptr(&plic_handlers, cpu);
302331
if (handler->present) {
303332
pr_warn("handler already present for context %d.\n", i);
304-
threshold = 0xffffffff;
333+
plic_set_threshold(handler, PLIC_DISABLE_THRESHOLD);
305334
goto done;
306335
}
307336

@@ -313,13 +342,14 @@ static int __init plic_init(struct device_node *node,
313342
plic_regs + ENABLE_BASE + i * ENABLE_PER_HART;
314343

315344
done:
316-
/* priority must be > threshold to trigger an interrupt */
317-
writel(threshold, handler->hart_base + CONTEXT_THRESHOLD);
318345
for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
319346
plic_toggle(handler, hwirq, 0);
320347
nr_handlers++;
321348
}
322349

350+
cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
351+
"irqchip/sifive/plic:starting",
352+
plic_starting_cpu, plic_dying_cpu);
323353
pr_info("mapped %d interrupts with %d handlers for %d contexts.\n",
324354
nr_irqs, nr_handlers, nr_contexts);
325355
set_handle_irq(plic_handle_irq);

include/linux/cpuhotplug.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ enum cpuhp_state {
102102
CPUHP_AP_IRQ_ARMADA_XP_STARTING,
103103
CPUHP_AP_IRQ_BCM2836_STARTING,
104104
CPUHP_AP_IRQ_MIPS_GIC_STARTING,
105+
CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
105106
CPUHP_AP_ARM_MVEBU_COHERENCY,
106107
CPUHP_AP_MICROCODE_LOADER,
107108
CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,

0 commit comments

Comments
 (0)