123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- /*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018/10/01 Bernard The first version
- * 2018/12/27 Jesven Change irq enable/disable to cpu0
- */
- #include <rthw.h>
- #include "tick.h"
- #include <plic.h>
- #include <clint.h>
- #include <interrupt.h>
- #define CPU_NUM 2
- #define MAX_HANDLERS IRQN_MAX
- static struct rt_irq_desc irq_desc[MAX_HANDLERS];
- static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
- {
- rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
- return RT_NULL;
- }
- int rt_hw_clint_ipi_enable(void)
- {
- /* Set the Machine-Software bit in MIE */
- set_csr(mie, MIP_MSIP);
- return 0;
- }
- int rt_hw_clint_ipi_disable(void)
- {
- /* Clear the Machine-Software bit in MIE */
- clear_csr(mie, MIP_MSIP);
- return 0;
- }
- int rt_hw_plic_irq_enable(plic_irq_t irq_number)
- {
- unsigned long core_id = 0;
- /* Check parameters */
- if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
- return -1;
- /* Get current enable bit array by IRQ number */
- uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
- /* Set enable bit in enable bit array */
- current |= (uint32_t)1 << (irq_number % 32);
- /* Write back the enable bit array */
- plic->target_enables.target[core_id].enable[irq_number / 32] = current;
- return 0;
- }
- int rt_hw_plic_irq_disable(plic_irq_t irq_number)
- {
- unsigned long core_id = 0;
- /* Check parameters */
- if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
- return -1;
- /* Get current enable bit array by IRQ number */
- uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
- /* Clear enable bit in enable bit array */
- current &= ~((uint32_t)1 << (irq_number % 32));
- /* Write back the enable bit array */
- plic->target_enables.target[core_id].enable[irq_number / 32] = current;
- return 0;
- }
- /**
- * This function will initialize hardware interrupt
- */
- void rt_hw_interrupt_init(void)
- {
- int idx;
- int cpuid;
- cpuid = current_coreid();
- /* Disable all interrupts for the current core. */
- for (idx = 0; idx < ((PLIC_NUM_SOURCES + 32u) / 32u); idx ++)
- plic->target_enables.target[cpuid].enable[idx] = 0;
- /* Set priorities to zero. */
- for (idx = 0; idx < PLIC_NUM_SOURCES; idx++)
- plic->source_priorities.priority[idx] = 0;
- /* Set the threshold to zero. */
- plic->targets.target[cpuid].priority_threshold = 0;
- /* init exceptions table */
- for (idx = 0; idx < MAX_HANDLERS; idx++)
- {
- rt_hw_interrupt_mask(idx);
- irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
- irq_desc[idx].param = RT_NULL;
- #ifdef RT_USING_INTERRUPT_INFO
- rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
- irq_desc[idx].counter = 0;
- #endif
- }
- /* Enable machine external interrupts. */
- set_csr(mie, MIP_MEIP);
- }
- void rt_hw_scondary_interrupt_init(void)
- {
- int idx;
- int cpuid;
- cpuid = current_coreid();
- /* Disable all interrupts for the current core. */
- for (idx = 0; idx < ((PLIC_NUM_SOURCES + 32u) / 32u); idx ++)
- plic->target_enables.target[cpuid].enable[idx] = 0;
- /* Set the threshold to zero. */
- plic->targets.target[cpuid].priority_threshold = 0;
- /* Enable machine external interrupts. */
- set_csr(mie, MIP_MEIP);
- }
- /**
- * This function will mask a interrupt.
- * @param vector the interrupt number
- */
- void rt_hw_interrupt_mask(int vector)
- {
- rt_hw_plic_irq_disable(vector);
- }
- /**
- * This function will un-mask a interrupt.
- * @param vector the interrupt number
- */
- void rt_hw_interrupt_umask(int vector)
- {
- plic_set_priority(vector, 1);
- rt_hw_plic_irq_enable(vector);
- }
- /**
- * This function will install a interrupt service routine to a interrupt.
- * @param vector the interrupt number
- * @param new_handler the interrupt service routine to be installed
- * @param old_handler the old interrupt service routine
- */
- rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
- void *param, const char *name)
- {
- rt_isr_handler_t old_handler = RT_NULL;
- if(vector < MAX_HANDLERS)
- {
- old_handler = irq_desc[vector].handler;
- if (handler != RT_NULL)
- {
- irq_desc[vector].handler = (rt_isr_handler_t)handler;
- irq_desc[vector].param = param;
- #ifdef RT_USING_INTERRUPT_INFO
- rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
- irq_desc[vector].counter = 0;
- #endif
- }
- }
- return old_handler;
- }
- RT_WEAK
- void plic_irq_handle(plic_irq_t irq)
- {
- rt_kprintf("UN-handled interrupt %d occurred!!!\n", irq);
- return ;
- }
- uintptr_t handle_irq_m_ext(uintptr_t cause, uintptr_t epc)
- {
- /*
- * After the highest-priority pending interrupt is claimed by a target
- * and the corresponding IP bit is cleared, other lower-priority
- * pending interrupts might then become visible to the target, and so
- * the PLIC EIP bit might not be cleared after a claim. The interrupt
- * handler can check the local meip/heip/seip/ueip bits before exiting
- * the handler, to allow more efficient service of other interrupts
- * without first restoring the interrupted context and taking another
- * interrupt trap.
- */
- if (read_csr(mip) & MIP_MEIP)
- {
- /* Get current core id */
- uint64_t core_id = current_coreid();
- /* Get primitive interrupt enable flag */
- uint64_t ie_flag = read_csr(mie);
- /* Get current IRQ num */
- uint32_t int_num = plic->targets.target[core_id].claim_complete;
- /* Get primitive IRQ threshold */
- uint32_t int_threshold = plic->targets.target[core_id].priority_threshold;
- /* Set new IRQ threshold = current IRQ threshold */
- plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num];
- /* Disable software interrupt and timer interrupt */
- clear_csr(mie, MIP_MTIP | MIP_MSIP);
- if (irq_desc[int_num].handler == (rt_isr_handler_t)rt_hw_interrupt_handle)
- {
- /* default handler, route to kendryte bsp plic driver */
- plic_irq_handle(int_num);
- }
- else if (irq_desc[int_num].handler)
- {
- irq_desc[int_num].handler(int_num, irq_desc[int_num].param);
- }
- /* Perform IRQ complete */
- plic->targets.target[core_id].claim_complete = int_num;
- /* Set MPIE and MPP flag used to MRET instructions restore MIE flag */
- set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
- /* Restore primitive interrupt enable flag */
- write_csr(mie, ie_flag);
- /* Restore primitive IRQ threshold */
- plic->targets.target[core_id].priority_threshold = int_threshold;
- }
- return epc;
- }
- uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
- {
- int cause = mcause & CAUSE_MACHINE_IRQ_REASON_MASK;
- if (mcause & (1UL << 63))
- {
- switch (cause)
- {
- case IRQ_M_SOFT:
- {
- uint64_t core_id = current_coreid();
- clint_ipi_clear(core_id);
- rt_schedule();
- }
- break;
- case IRQ_M_EXT:
- handle_irq_m_ext(mcause, epc);
- break;
- case IRQ_M_TIMER:
- tick_isr();
- break;
- }
- }
- else
- {
- rt_thread_t tid;
- extern long list_thread();
- rt_hw_interrupt_disable();
- tid = rt_thread_self();
- rt_kprintf("\nException:\n");
- switch (cause)
- {
- case CAUSE_MISALIGNED_FETCH:
- rt_kprintf("Instruction address misaligned");
- break;
- case CAUSE_FAULT_FETCH:
- rt_kprintf("Instruction access fault");
- break;
- case CAUSE_ILLEGAL_INSTRUCTION:
- rt_kprintf("Illegal instruction");
- break;
- case CAUSE_BREAKPOINT:
- rt_kprintf("Breakpoint");
- break;
- case CAUSE_MISALIGNED_LOAD:
- rt_kprintf("Load address misaligned");
- break;
- case CAUSE_FAULT_LOAD:
- rt_kprintf("Load access fault");
- break;
- case CAUSE_MISALIGNED_STORE:
- rt_kprintf("Store address misaligned");
- break;
- case CAUSE_FAULT_STORE:
- rt_kprintf("Store access fault");
- break;
- case CAUSE_USER_ECALL:
- rt_kprintf("Environment call from U-mode");
- break;
- case CAUSE_SUPERVISOR_ECALL:
- rt_kprintf("Environment call from S-mode");
- break;
- case CAUSE_HYPERVISOR_ECALL:
- rt_kprintf("Environment call from H-mode");
- break;
- case CAUSE_MACHINE_ECALL:
- rt_kprintf("Environment call from M-mode");
- break;
- default:
- rt_kprintf("Uknown exception : %08lX", cause);
- break;
- }
- rt_kprintf("\n");
- rt_kprintf("exception pc => 0x%08x\n", epc);
- rt_kprintf("current thread: %.*s\n", RT_NAME_MAX, tid->name);
- #ifdef RT_USING_FINSH
- list_thread();
- #endif
- while(1);
- }
- return epc;
- }
|