xref: /linux/arch/riscv/kernel/irq.c (revision c40fef85)
16ea0f26aSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
276d2a049SPalmer Dabbelt /*
376d2a049SPalmer Dabbelt  * Copyright (C) 2012 Regents of the University of California
476d2a049SPalmer Dabbelt  * Copyright (C) 2017 SiFive
56ea0f26aSChristoph Hellwig  * Copyright (C) 2018 Christoph Hellwig
676d2a049SPalmer Dabbelt  */
776d2a049SPalmer Dabbelt 
876d2a049SPalmer Dabbelt #include <linux/interrupt.h>
976d2a049SPalmer Dabbelt #include <linux/irqchip.h>
100c60a31cSAnup Patel #include <linux/irqdomain.h>
110c60a31cSAnup Patel #include <linux/module.h>
12*c40fef85SSami Tolvanen #include <linux/scs.h>
138b20d2dbSAnup Patel #include <linux/seq_file.h>
14832f15f4SAnup Patel #include <asm/sbi.h>
15dd69d07aSGuo Ren #include <asm/smp.h>
16dd69d07aSGuo Ren #include <asm/softirq_stack.h>
17dd69d07aSGuo Ren #include <asm/stacktrace.h>
1876d2a049SPalmer Dabbelt 
190c60a31cSAnup Patel static struct fwnode_handle *(*__get_intc_node)(void);
200c60a31cSAnup Patel 
riscv_set_intc_hwnode_fn(struct fwnode_handle * (* fn)(void))210c60a31cSAnup Patel void riscv_set_intc_hwnode_fn(struct fwnode_handle *(*fn)(void))
220c60a31cSAnup Patel {
230c60a31cSAnup Patel 	__get_intc_node = fn;
240c60a31cSAnup Patel }
250c60a31cSAnup Patel 
riscv_get_intc_hwnode(void)260c60a31cSAnup Patel struct fwnode_handle *riscv_get_intc_hwnode(void)
270c60a31cSAnup Patel {
280c60a31cSAnup Patel 	if (__get_intc_node)
290c60a31cSAnup Patel 		return __get_intc_node();
300c60a31cSAnup Patel 
310c60a31cSAnup Patel 	return NULL;
320c60a31cSAnup Patel }
330c60a31cSAnup Patel EXPORT_SYMBOL_GPL(riscv_get_intc_hwnode);
340c60a31cSAnup Patel 
35163e76ccSGuo Ren #ifdef CONFIG_IRQ_STACKS
36163e76ccSGuo Ren #include <asm/irq_stack.h>
37163e76ccSGuo Ren 
38*c40fef85SSami Tolvanen DECLARE_PER_CPU(ulong *, irq_shadow_call_stack_ptr);
39*c40fef85SSami Tolvanen 
40*c40fef85SSami Tolvanen #ifdef CONFIG_SHADOW_CALL_STACK
41*c40fef85SSami Tolvanen DEFINE_PER_CPU(ulong *, irq_shadow_call_stack_ptr);
42*c40fef85SSami Tolvanen #endif
43*c40fef85SSami Tolvanen 
init_irq_scs(void)44*c40fef85SSami Tolvanen static void init_irq_scs(void)
45*c40fef85SSami Tolvanen {
46*c40fef85SSami Tolvanen 	int cpu;
47*c40fef85SSami Tolvanen 
48*c40fef85SSami Tolvanen 	if (!scs_is_enabled())
49*c40fef85SSami Tolvanen 		return;
50*c40fef85SSami Tolvanen 
51*c40fef85SSami Tolvanen 	for_each_possible_cpu(cpu)
52*c40fef85SSami Tolvanen 		per_cpu(irq_shadow_call_stack_ptr, cpu) =
53*c40fef85SSami Tolvanen 			scs_alloc(cpu_to_node(cpu));
54*c40fef85SSami Tolvanen }
55*c40fef85SSami Tolvanen 
56163e76ccSGuo Ren DEFINE_PER_CPU(ulong *, irq_stack_ptr);
57163e76ccSGuo Ren 
58163e76ccSGuo Ren #ifdef CONFIG_VMAP_STACK
init_irq_stacks(void)59163e76ccSGuo Ren static void init_irq_stacks(void)
60163e76ccSGuo Ren {
61163e76ccSGuo Ren 	int cpu;
62163e76ccSGuo Ren 	ulong *p;
63163e76ccSGuo Ren 
64163e76ccSGuo Ren 	for_each_possible_cpu(cpu) {
65163e76ccSGuo Ren 		p = arch_alloc_vmap_stack(IRQ_STACK_SIZE, cpu_to_node(cpu));
66163e76ccSGuo Ren 		per_cpu(irq_stack_ptr, cpu) = p;
67163e76ccSGuo Ren 	}
68163e76ccSGuo Ren }
69163e76ccSGuo Ren #else
70163e76ccSGuo Ren /* irq stack only needs to be 16 byte aligned - not IRQ_STACK_SIZE aligned. */
71163e76ccSGuo Ren DEFINE_PER_CPU_ALIGNED(ulong [IRQ_STACK_SIZE/sizeof(ulong)], irq_stack);
72163e76ccSGuo Ren 
init_irq_stacks(void)73163e76ccSGuo Ren static void init_irq_stacks(void)
74163e76ccSGuo Ren {
75163e76ccSGuo Ren 	int cpu;
76163e76ccSGuo Ren 
77163e76ccSGuo Ren 	for_each_possible_cpu(cpu)
78163e76ccSGuo Ren 		per_cpu(irq_stack_ptr, cpu) = per_cpu(irq_stack, cpu);
79163e76ccSGuo Ren }
80163e76ccSGuo Ren #endif /* CONFIG_VMAP_STACK */
81dd69d07aSGuo Ren 
82dd69d07aSGuo Ren #ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
___do_softirq(struct pt_regs * regs)8382982fddSSami Tolvanen static void ___do_softirq(struct pt_regs *regs)
8482982fddSSami Tolvanen {
8582982fddSSami Tolvanen 	__do_softirq();
8682982fddSSami Tolvanen }
8782982fddSSami Tolvanen 
do_softirq_own_stack(void)88dd69d07aSGuo Ren void do_softirq_own_stack(void)
89dd69d07aSGuo Ren {
9082982fddSSami Tolvanen 	if (on_thread_stack())
9182982fddSSami Tolvanen 		call_on_irq_stack(NULL, ___do_softirq);
9282982fddSSami Tolvanen 	else
93dd69d07aSGuo Ren 		__do_softirq();
94dd69d07aSGuo Ren }
95dd69d07aSGuo Ren #endif /* CONFIG_SOFTIRQ_ON_OWN_STACK */
96dd69d07aSGuo Ren 
97163e76ccSGuo Ren #else
init_irq_scs(void)98*c40fef85SSami Tolvanen static void init_irq_scs(void) {}
init_irq_stacks(void)99163e76ccSGuo Ren static void init_irq_stacks(void) {}
100163e76ccSGuo Ren #endif /* CONFIG_IRQ_STACKS */
101163e76ccSGuo Ren 
arch_show_interrupts(struct seq_file * p,int prec)1028b20d2dbSAnup Patel int arch_show_interrupts(struct seq_file *p, int prec)
1038b20d2dbSAnup Patel {
1048b20d2dbSAnup Patel 	show_ipi_stats(p, prec);
1058b20d2dbSAnup Patel 	return 0;
1068b20d2dbSAnup Patel }
1078b20d2dbSAnup Patel 
init_IRQ(void)10876d2a049SPalmer Dabbelt void __init init_IRQ(void)
10976d2a049SPalmer Dabbelt {
110*c40fef85SSami Tolvanen 	init_irq_scs();
111163e76ccSGuo Ren 	init_irq_stacks();
11276d2a049SPalmer Dabbelt 	irqchip_init();
1136b7ce892SAnup Patel 	if (!handle_arch_irq)
1146b7ce892SAnup Patel 		panic("No interrupt controller found.");
115832f15f4SAnup Patel 	sbi_ipi_init();
11676d2a049SPalmer Dabbelt }
117