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 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 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 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 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 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 */ 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 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 */ 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 */ 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 */ 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 180 void plic_irq_handle(plic_irq_t irq) 181 { 182 rt_kprintf("UN-handled interrupt %d occurred!!!\n", irq); 183 return ; 184 } 185 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 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