xref: /nrf52832-nimble/rt-thread/libcpu/risc-v/k210/interrupt.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2018/10/01     Bernard      The first version
9  * 2018/12/27     Jesven       Change irq enable/disable to cpu0
10  */
11 
12 #include <rthw.h>
13 
14 #include "tick.h"
15 
16 #include <plic.h>
17 #include <clint.h>
18 #include <interrupt.h>
19 
20 #define CPU_NUM         2
21 #define MAX_HANDLERS    IRQN_MAX
22 
23 static struct rt_irq_desc irq_desc[MAX_HANDLERS];
24 
rt_hw_interrupt_handle(rt_uint32_t vector,void * param)25 static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
26 {
27     rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
28     return RT_NULL;
29 }
30 
rt_hw_clint_ipi_enable(void)31 int rt_hw_clint_ipi_enable(void)
32 {
33     /* Set the Machine-Software bit in MIE */
34     set_csr(mie, MIP_MSIP);
35     return 0;
36 }
37 
rt_hw_clint_ipi_disable(void)38 int rt_hw_clint_ipi_disable(void)
39 {
40     /* Clear the Machine-Software bit in MIE */
41     clear_csr(mie, MIP_MSIP);
42     return 0;
43 }
44 
rt_hw_plic_irq_enable(plic_irq_t irq_number)45 int rt_hw_plic_irq_enable(plic_irq_t irq_number)
46 {
47     unsigned long core_id = 0;
48 
49     /* Check parameters */
50     if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
51         return -1;
52     /* Get current enable bit array by IRQ number */
53     uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
54     /* Set enable bit in enable bit array */
55     current |= (uint32_t)1 << (irq_number % 32);
56     /* Write back the enable bit array */
57     plic->target_enables.target[core_id].enable[irq_number / 32] = current;
58     return 0;
59 }
60 
rt_hw_plic_irq_disable(plic_irq_t irq_number)61 int rt_hw_plic_irq_disable(plic_irq_t irq_number)
62 {
63     unsigned long core_id = 0;
64 
65     /* Check parameters */
66     if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
67         return -1;
68     /* Get current enable bit array by IRQ number */
69     uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
70     /* Clear enable bit in enable bit array */
71     current &= ~((uint32_t)1 << (irq_number % 32));
72     /* Write back the enable bit array */
73     plic->target_enables.target[core_id].enable[irq_number / 32] = current;
74     return 0;
75 }
76 
77 /**
78  * This function will initialize hardware interrupt
79  */
rt_hw_interrupt_init(void)80 void rt_hw_interrupt_init(void)
81 {
82     int idx;
83     int cpuid;
84 
85     cpuid = current_coreid();
86 
87     /* Disable all interrupts for the current core. */
88     for (idx = 0; idx < ((PLIC_NUM_SOURCES + 32u) / 32u); idx ++)
89         plic->target_enables.target[cpuid].enable[idx] = 0;
90 
91     /* Set priorities to zero. */
92     for (idx = 0; idx < PLIC_NUM_SOURCES; idx++)
93         plic->source_priorities.priority[idx] = 0;
94 
95     /* Set the threshold to zero. */
96     plic->targets.target[cpuid].priority_threshold = 0;
97 
98     /* init exceptions table */
99     for (idx = 0; idx < MAX_HANDLERS; idx++)
100     {
101         rt_hw_interrupt_mask(idx);
102         irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
103         irq_desc[idx].param = RT_NULL;
104 #ifdef RT_USING_INTERRUPT_INFO
105         rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
106         irq_desc[idx].counter = 0;
107 #endif
108     }
109 
110     /* Enable machine external interrupts. */
111     set_csr(mie, MIP_MEIP);
112 }
113 
rt_hw_scondary_interrupt_init(void)114 void rt_hw_scondary_interrupt_init(void)
115 {
116     int idx;
117     int cpuid;
118 
119     cpuid = current_coreid();
120 
121     /* Disable all interrupts for the current core. */
122     for (idx = 0; idx < ((PLIC_NUM_SOURCES + 32u) / 32u); idx ++)
123         plic->target_enables.target[cpuid].enable[idx] = 0;
124 
125     /* Set the threshold to zero. */
126     plic->targets.target[cpuid].priority_threshold = 0;
127 
128     /* Enable machine external interrupts. */
129     set_csr(mie, MIP_MEIP);
130 }
131 
132 /**
133  * This function will mask a interrupt.
134  * @param vector the interrupt number
135  */
rt_hw_interrupt_mask(int vector)136 void rt_hw_interrupt_mask(int vector)
137 {
138     rt_hw_plic_irq_disable(vector);
139 }
140 
141 /**
142  * This function will un-mask a interrupt.
143  * @param vector the interrupt number
144  */
rt_hw_interrupt_umask(int vector)145 void rt_hw_interrupt_umask(int vector)
146 {
147     plic_set_priority(vector, 1);
148     rt_hw_plic_irq_enable(vector);
149 }
150 
151 /**
152  * This function will install a interrupt service routine to a interrupt.
153  * @param vector the interrupt number
154  * @param new_handler the interrupt service routine to be installed
155  * @param old_handler the old interrupt service routine
156  */
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)157 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
158         void *param, const char *name)
159 {
160     rt_isr_handler_t old_handler = RT_NULL;
161 
162     if(vector < MAX_HANDLERS)
163     {
164         old_handler = irq_desc[vector].handler;
165         if (handler != RT_NULL)
166         {
167             irq_desc[vector].handler = (rt_isr_handler_t)handler;
168             irq_desc[vector].param = param;
169 #ifdef RT_USING_INTERRUPT_INFO
170             rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
171             irq_desc[vector].counter = 0;
172 #endif
173         }
174     }
175 
176     return old_handler;
177 }
178 
179 RT_WEAK
plic_irq_handle(plic_irq_t irq)180 void plic_irq_handle(plic_irq_t irq)
181 {
182     rt_kprintf("UN-handled interrupt %d occurred!!!\n", irq);
183     return ;
184 }
185 
handle_irq_m_ext(uintptr_t cause,uintptr_t epc)186 uintptr_t handle_irq_m_ext(uintptr_t cause, uintptr_t epc)
187 {
188     /*
189      * After the highest-priority pending interrupt is claimed by a target
190      * and the corresponding IP bit is cleared, other lower-priority
191      * pending interrupts might then become visible to the target, and so
192      * the PLIC EIP bit might not be cleared after a claim. The interrupt
193      * handler can check the local meip/heip/seip/ueip bits before exiting
194      * the handler, to allow more efficient service of other interrupts
195      * without first restoring the interrupted context and taking another
196      * interrupt trap.
197      */
198     if (read_csr(mip) & MIP_MEIP)
199     {
200         /* Get current core id */
201         uint64_t core_id = current_coreid();
202         /* Get primitive interrupt enable flag */
203         uint64_t ie_flag = read_csr(mie);
204         /* Get current IRQ num */
205         uint32_t int_num = plic->targets.target[core_id].claim_complete;
206         /* Get primitive IRQ threshold */
207         uint32_t int_threshold = plic->targets.target[core_id].priority_threshold;
208         /* Set new IRQ threshold = current IRQ threshold */
209         plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num];
210 
211         /* Disable software interrupt and timer interrupt */
212         clear_csr(mie, MIP_MTIP | MIP_MSIP);
213 
214         if (irq_desc[int_num].handler == (rt_isr_handler_t)rt_hw_interrupt_handle)
215         {
216             /* default handler, route to kendryte bsp plic driver */
217             plic_irq_handle(int_num);
218         }
219         else if (irq_desc[int_num].handler)
220         {
221             irq_desc[int_num].handler(int_num, irq_desc[int_num].param);
222         }
223 
224         /* Perform IRQ complete */
225         plic->targets.target[core_id].claim_complete = int_num;
226         /* Set MPIE and MPP flag used to MRET instructions restore MIE flag */
227         set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
228         /* Restore primitive interrupt enable flag */
229         write_csr(mie, ie_flag);
230         /* Restore primitive IRQ threshold */
231         plic->targets.target[core_id].priority_threshold = int_threshold;
232     }
233     else
234     {
235         rt_kprintf("unhandled trap!\n");
236     }
237 
238     return epc;
239 }
240 
handle_trap(uintptr_t mcause,uintptr_t epc)241 uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
242 {
243     int cause = mcause & CAUSE_MACHINE_IRQ_REASON_MASK;
244 
245     if (mcause & (1UL << 63))
246     {
247         switch (cause)
248         {
249             case IRQ_M_SOFT:
250                 {
251                     uint64_t core_id = current_coreid();
252 
253                     clint_ipi_clear(core_id);
254                     rt_schedule();
255                 }
256                 break;
257             case IRQ_M_EXT:
258                 handle_irq_m_ext(mcause, epc);
259                 break;
260             case IRQ_M_TIMER:
261                 tick_isr();
262                 break;
263         }
264     }
265     else
266     {
267         rt_thread_t tid;
268         extern long list_thread();
269 
270         rt_hw_interrupt_disable();
271 
272         tid = rt_thread_self();
273         rt_kprintf("\n");
274         rt_kprintf("unhandled trap, epc => 0x%08x, INT[%d]\n", epc, rt_interrupt_get_nest());
275         rt_kprintf("current thread: %.*s\n", RT_NAME_MAX, tid->name);
276 #ifdef RT_USING_FINSH
277         list_thread();
278 #endif
279         while(1);
280     }
281 
282     return epc;
283 }
284