1 /*
2  * Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <kernel_internal.h>
9 #include <zephyr/logging/log.h>
10 #include <zephyr/arch/riscv/csr.h>
11 #include <zephyr/irq_multilevel.h>
12 #include <zephyr/sw_isr_table.h>
13 
14 #ifdef CONFIG_RISCV_HAS_PLIC
15 #include <zephyr/drivers/interrupt_controller/riscv_plic.h>
16 #endif
17 
18 LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
19 
z_irq_spurious(const void * unused)20 FUNC_NORETURN void z_irq_spurious(const void *unused)
21 {
22 #ifdef CONFIG_EMPTY_IRQ_SPURIOUS
23 	while (1) {
24 	}
25 
26 	CODE_UNREACHABLE;
27 #else
28 	unsigned long mcause;
29 
30 	ARG_UNUSED(unused);
31 
32 	mcause = csr_read(mcause);
33 
34 	mcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK;
35 
36 	LOG_ERR("Spurious interrupt detected! IRQ: %ld", mcause);
37 #if defined(CONFIG_RISCV_HAS_PLIC)
38 	if (mcause == RISCV_IRQ_MEXT) {
39 		unsigned int save_irq = riscv_plic_get_irq();
40 		const struct device *save_dev = riscv_plic_get_dev();
41 
42 		LOG_ERR("PLIC interrupt line causing the IRQ: %d (%p)", save_irq, save_dev);
43 	}
44 #endif
45 	z_riscv_fatal_error(K_ERR_SPURIOUS_IRQ, NULL);
46 #endif /* CONFIG_EMPTY_IRQ_SPURIOUS */
47 }
48 
49 #ifdef CONFIG_DYNAMIC_INTERRUPTS
arch_irq_connect_dynamic(unsigned int irq,unsigned int priority,void (* routine)(const void * parameter),const void * parameter,uint32_t flags)50 int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority,
51 			     void (*routine)(const void *parameter),
52 			     const void *parameter, uint32_t flags)
53 {
54 	z_isr_install(irq + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, routine, parameter);
55 
56 #if defined(CONFIG_RISCV_HAS_PLIC) || defined(CONFIG_RISCV_HAS_CLIC)
57 	z_riscv_irq_priority_set(irq, priority, flags);
58 #else
59 	ARG_UNUSED(flags);
60 	ARG_UNUSED(priority);
61 #endif
62 	return irq;
63 }
64 
65 #ifdef CONFIG_SHARED_INTERRUPTS
arch_irq_disconnect_dynamic(unsigned int irq,unsigned int priority,void (* routine)(const void * parameter),const void * parameter,uint32_t flags)66 int arch_irq_disconnect_dynamic(unsigned int irq, unsigned int priority,
67 				void (*routine)(const void *parameter), const void *parameter,
68 				uint32_t flags)
69 {
70 	ARG_UNUSED(priority);
71 	ARG_UNUSED(flags);
72 
73 	return z_isr_uninstall(irq + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, routine,
74 			       parameter);
75 }
76 #endif /* CONFIG_SHARED_INTERRUPTS */
77 #endif /* CONFIG_DYNAMIC_INTERRUPTS */
78