Skip to content

Commit

Permalink
Merge pull request #147 from sifive/esat-40
Browse files Browse the repository at this point in the history
New APIs to better configure and manage CLIC interrupts
  • Loading branch information
bsousi5 authored Aug 9, 2019
2 parents 22d481b + 7103ab3 commit a1c1dc3
Show file tree
Hide file tree
Showing 7 changed files with 476 additions and 96 deletions.
9 changes: 2 additions & 7 deletions metal/drivers/riscv_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ typedef enum {
METAL_INTERRUPT_ID_SW = (METAL_INTERRUPT_ID_BASE + 3),
METAL_INTERRUPT_ID_TMR = (METAL_INTERRUPT_ID_BASE + 7),
METAL_INTERRUPT_ID_EXT = (METAL_INTERRUPT_ID_BASE + 11),
METAL_INTERRUPT_ID_CSW = (METAL_INTERRUPT_ID_BASE + 12),
METAL_INTERRUPT_ID_LC0 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(0)),
METAL_INTERRUPT_ID_LC1 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(1)),
METAL_INTERRUPT_ID_LC2 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(2)),
Expand Down Expand Up @@ -164,14 +165,8 @@ struct __metal_driver_vtable_riscv_cpu_intc {

void __metal_interrupt_global_enable(void);
void __metal_interrupt_global_disable(void);
metal_vector_mode __metal_controller_interrupt_vector_mode(void);
void __metal_controller_interrupt_vector(metal_vector_mode mode, void *vec_table);
__inline__ int __metal_controller_interrupt_is_selective_vectored (void)
{
uintptr_t val;

__asm__ volatile ("csrr %0, mtvec" : "=r"(val));
return ((val & METAL_MTVEC_CLIC_VECTORED) == METAL_MTVEC_CLIC);
}

__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_cpu_intc)

Expand Down
3 changes: 2 additions & 1 deletion metal/drivers/sifive_clic0.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0)
struct __metal_driver_sifive_clic0 {
struct metal_interrupt controller;
int init_done;
metal_interrupt_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
int pad[14];
metal_interrupt_vector_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
__metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS];
};
#undef __METAL_MACHINE_MACROS
Expand Down
153 changes: 136 additions & 17 deletions metal/interrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,43 @@ typedef enum metal_interrupt_controller_ {
typedef enum metal_vector_mode_ {
METAL_DIRECT_MODE = 0,
METAL_VECTOR_MODE = 1,
METAL_SELECTIVE_VECTOR_MODE = 2,
METAL_HARDWARE_VECTOR_MODE = 3
METAL_SELECTIVE_NONVECTOR_MODE = 2,
METAL_SELECTIVE_VECTOR_MODE = 3,
METAL_HARDWARE_VECTOR_MODE = 4
} metal_vector_mode;

/*!
* @brief Possible mode of privilege interrupts to operate
*/
typedef enum metal_intr_priv_mode_ {
METAL_INTR_PRIV_M_MODE = 0,
METAL_INTR_PRIV_MU_MODE = 1,
METAL_INTR_PRIV_MSU_MODE = 2
} metal_intr_priv_mode;

/*!
* @brief Function signature for interrupt callback handlers
*/
typedef void (*metal_interrupt_handler_t) (int, void *);
typedef void (*metal_interrupt_vector_handler_t) (void);

struct metal_interrupt;

struct metal_interrupt_vtable {
void (*interrupt_init)(struct metal_interrupt *controller);
int (*interrupt_set_vector_mode)(struct metal_interrupt *controller, metal_vector_mode mode);
metal_vector_mode (*interrupt_get_vector_mode)(struct metal_interrupt *controller);
int (*interrupt_set_privilege)(struct metal_interrupt *controller, metal_intr_priv_mode priv);
metal_intr_priv_mode (*interrupt_get_privilege)(struct metal_interrupt *controller);
int (*interrupt_clear)(struct metal_interrupt *controller, int id);
int (*interrupt_set)(struct metal_interrupt *controller, int id);
int (*interrupt_register)(struct metal_interrupt *controller, int id,
metal_interrupt_handler_t isr, void *priv_data);
int (*interrupt_vector_register)(struct metal_interrupt *controller, int id,
metal_interrupt_vector_handler_t isr, void *priv_data);
int (*interrupt_enable)(struct metal_interrupt *controller, int id);
int (*interrupt_disable)(struct metal_interrupt *controller, int id);
int (*interrupt_vector_enable)(struct metal_interrupt *controller,
int id, metal_vector_mode mode);
int (*interrupt_vector_enable)(struct metal_interrupt *controller, int id);
int (*interrupt_vector_disable)(struct metal_interrupt *controller, int id);
unsigned int (*interrupt_get_threshold)(struct metal_interrupt *controller);
int (*interrupt_set_threshold)(struct metal_interrupt *controller, unsigned int threshold);
Expand Down Expand Up @@ -85,6 +103,93 @@ __inline__ void metal_interrupt_init(struct metal_interrupt *controller)
struct metal_interrupt* metal_interrupt_get_controller(metal_intr_cntrl_type cntrl,
int id);

/*!
* @brief Configure vector mode for an interrupt controller
*
* Configure vector mode for an interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @param mode The vector mode of the interrupt controller.
* @return 0 upon success
*/
__inline__ int metal_interrupt_set_vector_mode(struct metal_interrupt *controller,
metal_vector_mode mode)
{
return controller->vtable->interrupt_set_vector_mode(controller, mode);
}

/*!
* @brief Get vector mode of a given an interrupt controller
*
* Configure vector mode for an interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @param mode The vector mode of the interrupt controller.
* @return The interrupt vector mode
*/
__inline__ metal_vector_mode metal_interrupt_get_vector_mode(struct metal_interrupt *controller)
{
return controller->vtable->interrupt_get_vector_mode(controller);
}

/*!
* @brief Configure privilege mode a of given interrupt controller
*
* Configure privilege mode for a given interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @param privilege The privilege mode of the interrupt controller.
* @return 0 upon success
*/
__inline__ int metal_interrupt_set_privilege(struct metal_interrupt *controller,
metal_intr_priv_mode privilege)
{
return controller->vtable->interrupt_set_privilege(controller, privilege);
}

/*!
* @brief Get privilege mode a of given interrupt controller
*
* Get privilege mode for a given interrupt controller.
* This function must be called after initialization and before
* configuring individual interrupts, registering ISR.
*
* @param controller The handle for the interrupt controller
* @return The interrupt privilege mode
*/
__inline__ metal_intr_priv_mode metal_interrupt_get_privilege(struct metal_interrupt *controller)
{
return controller->vtable->interrupt_get_privilege(controller);
}

/*!
* @brief clear an interrupt
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to trigger
* @return 0 upon success
*/
__inline__ int metal_interrupt_clear(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_clear(controller, id);
}

/*!
* @brief Set an interrupt
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to trigger
* @return 0 upon success
*/
__inline__ int metal_interrupt_set(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_set(controller, id);
}

/*!
* @brief Register an interrupt handler
* @param controller The handle for the interrupt controller
Expand All @@ -101,6 +206,22 @@ __inline__ int metal_interrupt_register_handler(struct metal_interrupt *controll
return controller->vtable->interrupt_register(controller, id, handler, priv_data);
}

/*!
* @brief Register an interrupt vector handler
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to register
* @param handler The interrupt vector handler callback
* @param priv_data Private data for the interrupt handler
* @return 0 upon success
*/
__inline__ int metal_interrupt_register_vector_handler(struct metal_interrupt *controller,
int id,
metal_interrupt_vector_handler_t handler,
void *priv_data)
{
return controller->vtable->interrupt_vector_register(controller, id, handler, priv_data);
}

/*!
* @brief Enable an interrupt
* @param controller The handle for the interrupt controller
Expand All @@ -123,19 +244,6 @@ __inline__ int metal_interrupt_disable(struct metal_interrupt *controller, int i
return controller->vtable->interrupt_disable(controller, id);
}

/*!
* @brief Enable an interrupt vector
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @param mode The interrupt mode type to enable
* @return 0 upon success
*/
__inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller,
int id, metal_vector_mode mode)
{
return controller->vtable->interrupt_vector_enable(controller, id, mode);
}

/*!
* @brief Set interrupt threshold level
* @param controller The handle for the interrupt controller
Expand Down Expand Up @@ -181,6 +289,17 @@ inline unsigned int metal_interrupt_get_priority(struct metal_interrupt *control
return controller->vtable->interrupt_get_priority(controller, id);
}

/*!
* @brief Enable an interrupt vector
* @param controller The handle for the interrupt controller
* @param id The interrupt ID to enable
* @return 0 upon success
*/
__inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller, int id)
{
return controller->vtable->interrupt_vector_enable(controller, id);
}

/*!
* @brief Disable an interrupt vector
* @param controller The handle for the interrupt controller
Expand Down
56 changes: 47 additions & 9 deletions src/drivers/riscv_cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ void __metal_exception_handler (void) {
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
id = mcause & METAL_MCAUSE_CAUSE;
if (mcause & METAL_MCAUSE_INTR) {
if ((id < METAL_INTERRUPT_ID_LC0) ||
if ((id < METAL_INTERRUPT_ID_CSW) ||
((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_DIRECT)) {
priv = intc->metal_int_table[id].exint_data;
intc->metal_int_table[id].handler(id, priv);
Expand All @@ -143,7 +143,7 @@ void __metal_exception_handler (void) {

__asm__ volatile ("csrr %0, 0x307" : "=r"(mtvt));
priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
mtvt_handler = (metal_interrupt_handler_t)mtvt;
mtvt_handler = (metal_interrupt_handler_t)*(uintptr_t *)mtvt;
mtvt_handler(id, priv);
return;
}
Expand All @@ -153,6 +153,24 @@ void __metal_exception_handler (void) {
}
}

metal_vector_mode __metal_controller_interrupt_vector_mode (void)
{
uintptr_t val;

asm volatile ("csrr %0, mtvec" : "=r"(val));
val &= METAL_MTVEC_MASK;

switch (val) {
case METAL_MTVEC_CLIC:
return METAL_SELECTIVE_VECTOR_MODE;
case METAL_MTVEC_CLIC_VECTORED:
return METAL_HARDWARE_VECTOR_MODE;
case METAL_MTVEC_VECTORED:
return METAL_VECTOR_MODE;
}
return METAL_DIRECT_MODE;
}

void __metal_controller_interrupt_vector (metal_vector_mode mode, void *vec_table)
{
uintptr_t trap_entry, val;
Expand All @@ -162,12 +180,13 @@ void __metal_controller_interrupt_vector (metal_vector_mode mode, void *vec_tabl
trap_entry = (uintptr_t)vec_table;

switch (mode) {
case METAL_SELECTIVE_NONVECTOR_MODE:
case METAL_SELECTIVE_VECTOR_MODE:
__asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC));
__asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry));
__asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC));
break;
case METAL_HARDWARE_VECTOR_MODE:
__asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC_VECTORED));
__asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry));
__asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED));
break;
case METAL_VECTOR_MODE:
Expand Down Expand Up @@ -427,15 +446,34 @@ int __metal_driver_riscv_cpu_controller_interrupt_disable_vector(struct metal_in
return -1;
}

metal_vector_mode __metal_driver_riscv_cpu_controller_get_vector_mode (struct metal_interrupt *controller)
{
return __metal_controller_interrupt_vector_mode();
}

int __metal_driver_riscv_cpu_controller_set_vector_mode (struct metal_interrupt *controller,
metal_vector_mode mode)
{
struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);

if (mode == METAL_DIRECT_MODE) {
__metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler);
return 0;
}
if (mode == METAL_VECTOR_MODE) {
__metal_controller_interrupt_vector(mode, (void *)&intc->metal_mtvec_table);
return 0;
}
return -1;
}

int __metal_driver_riscv_cpu_controller_command_request (struct metal_interrupt *controller,
int cmd, void *data)
{
/* NOP for now, unless local interrupt lines the like of clic, clint, plic */
return 0;
}

extern __inline__ int __metal_controller_interrupt_is_selective_vectored(void);

/* CPU driver !!! */

unsigned long long __metal_driver_cpu_mcycle_get(struct metal_cpu *cpu)
Expand Down Expand Up @@ -658,12 +696,12 @@ int __metal_driver_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t mepc)
}

__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_cpu_intc) = {
.controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init,
.controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init,
.controller_vtable.interrupt_register = __metal_driver_riscv_cpu_controller_interrupt_register,
.controller_vtable.interrupt_enable = __metal_driver_riscv_cpu_controller_interrupt_enable,
.controller_vtable.interrupt_disable = __metal_driver_riscv_cpu_controller_interrupt_disable,
.controller_vtable.interrupt_vector_enable = __metal_driver_riscv_cpu_controller_interrupt_enable_vector,
.controller_vtable.interrupt_vector_disable = __metal_driver_riscv_cpu_controller_interrupt_disable_vector,
.controller_vtable.interrupt_get_vector_mode = __metal_driver_riscv_cpu_controller_get_vector_mode,
.controller_vtable.interrupt_set_vector_mode = __metal_driver_riscv_cpu_controller_set_vector_mode,
.controller_vtable.command_request = __metal_driver_riscv_cpu_controller_command_request,
};

Expand Down
Loading

0 comments on commit a1c1dc3

Please sign in to comment.