summaryrefslogtreecommitdiffstats
path: root/bsps/riscv/riscv/irq/irq.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bsps/riscv/riscv/irq/irq.c355
1 files changed, 306 insertions, 49 deletions
diff --git a/bsps/riscv/riscv/irq/irq.c b/bsps/riscv/riscv/irq/irq.c
index 1b632289a6..4679d5a624 100644
--- a/bsps/riscv/riscv/irq/irq.c
+++ b/bsps/riscv/riscv/irq/irq.c
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
@@ -7,7 +9,7 @@
*/
/*
- * Copyright (c) 2018 embedded brains GmbH
+ * Copyright (C) 2018, 2022 embedded brains GmbH & Co. KG
*
* Copyright (c) 2015 University of York.
* Hesham Almatary <hesham@alumni.york.ac.uk>
@@ -42,12 +44,16 @@
#include <rtems/score/percpu.h>
#include <rtems/score/riscv-utility.h>
+#include <rtems/score/scheduler.h>
#include <rtems/score/smpimpl.h>
#include <libfdt.h>
+static volatile RISCV_PLIC_regs *riscv_plic;
+
volatile RISCV_CLINT_regs *riscv_clint;
+#ifdef RTEMS_SMP
/*
* The lovely PLIC has an interrupt enable bit per hart for each interrupt
* source. This makes the interrupt enable/disable a bit difficult. We have
@@ -61,6 +67,7 @@ volatile RISCV_CLINT_regs *riscv_clint;
*/
static volatile uint32_t *
riscv_plic_irq_to_cpu[RISCV_MAXIMUM_EXTERNAL_INTERRUPTS];
+#endif
RTEMS_INTERRUPT_LOCK_DEFINE(static, riscv_plic_lock, "PLIC")
@@ -73,7 +80,7 @@ void _RISCV_Interrupt_dispatch(uintptr_t mcause, Per_CPU_Control *cpu_self)
mcause <<= 1;
if (mcause == (RISCV_INTERRUPT_TIMER_MACHINE << 1)) {
- bsp_interrupt_handler_dispatch(RISCV_INTERRUPT_VECTOR_TIMER);
+ bsp_interrupt_handler_dispatch_unchecked(RISCV_INTERRUPT_VECTOR_TIMER);
} else if (mcause == (RISCV_INTERRUPT_EXTERNAL_MACHINE << 1)) {
volatile RISCV_PLIC_hart_regs *plic_hart_regs;
uint32_t interrupt_index;
@@ -95,7 +102,6 @@ void _RISCV_Interrupt_dispatch(uintptr_t mcause, Per_CPU_Control *cpu_self)
__asm__ volatile ("fence o, i" : : : "memory");
}
} else if (mcause == (RISCV_INTERRUPT_SOFTWARE_MACHINE << 1)) {
-#ifdef RTEMS_SMP
/*
* Clear the software interrupt on this processor. Synchronization of
* inter-processor interrupts is done via Per_CPU_Control::message in
@@ -103,15 +109,76 @@ void _RISCV_Interrupt_dispatch(uintptr_t mcause, Per_CPU_Control *cpu_self)
*/
*cpu_self->cpu_per_cpu.clint_msip = 0;
+#ifdef RTEMS_SMP
_SMP_Inter_processor_interrupt_handler(cpu_self);
+ bsp_interrupt_handler_dispatch_unlikely(RISCV_INTERRUPT_VECTOR_SOFTWARE);
#else
- bsp_interrupt_handler_dispatch(RISCV_INTERRUPT_VECTOR_SOFTWARE);
+ bsp_interrupt_handler_dispatch_unchecked(RISCV_INTERRUPT_VECTOR_SOFTWARE);
#endif
} else {
bsp_fatal(RISCV_FATAL_UNEXPECTED_INTERRUPT_EXCEPTION);
}
}
+static void riscv_clint_per_cpu_init(
+ volatile RISCV_CLINT_regs *clint,
+ Per_CPU_Control *cpu,
+ uint32_t index
+)
+{
+ cpu->cpu_per_cpu.clint_msip = &clint->msip[index];
+ cpu->cpu_per_cpu.clint_mtimecmp = &clint->mtimecmp[index];
+}
+
+static void riscv_plic_per_cpu_init(
+ volatile RISCV_PLIC_regs *plic,
+ uint32_t enable_register_count,
+ Per_CPU_Control *cpu,
+ uint32_t index
+)
+{
+ volatile uint32_t *enable;
+ uint32_t i;
+
+ plic->harts[index].priority_threshold = 0;
+
+ enable = &plic->enable[index][0];
+ cpu->cpu_per_cpu.plic_m_ie = enable;
+ cpu->cpu_per_cpu.plic_hart_regs = &plic->harts[index];
+
+ for (i = 0; i < enable_register_count; ++i) {
+ enable[i] = 0;
+ }
+}
+
+static void riscv_plic_cpu_0_init(
+ volatile RISCV_PLIC_regs *plic,
+ uint32_t interrupt_last
+)
+{
+#ifdef RTEMS_SMP
+ Per_CPU_Control *cpu;
+#endif
+ uint32_t i;
+
+#ifdef RTEMS_SMP
+ cpu = _Per_CPU_Get_by_index(0);
+#endif
+
+ for (i = 1; i <= interrupt_last; ++i) {
+ plic->priority[i] = 1;
+#ifdef RTEMS_SMP
+ riscv_plic_irq_to_cpu[i - 1] = cpu->cpu_per_cpu.plic_m_ie;
+#endif
+ }
+
+ /*
+ * External M-mode interrupts on secondary processors are enabled in
+ * bsp_start_on_secondary_processor().
+ */
+ set_csr(mie, MIP_MEIP);
+}
+
static void riscv_clint_init(const void *fdt)
{
volatile RISCV_CLINT_regs *clint;
@@ -133,16 +200,37 @@ static void riscv_clint_init(const void *fdt)
for (i = 0; i < len; i += 16) {
uint32_t hart_index;
- Per_CPU_Control *cpu;
+ uint32_t cpu_index;
hart_index = riscv_get_hart_index_by_phandle(fdt32_to_cpu(val[i / 4]));
- if (hart_index >= rtems_configuration_get_maximum_processors()) {
+
+#ifdef RTEMS_SMP
+ cpu_index = _RISCV_Map_hardid_to_cpu_index(hart_index);
+ if (cpu_index >= rtems_configuration_get_maximum_processors()) {
+ continue;
+ }
+
+ if ( _Scheduler_Initial_assignments[ cpu_index ].scheduler == NULL ) {
+ /* Skip not configured processor */
+ continue;
+ }
+#else
+ if (hart_index != RISCV_BOOT_HARTID) {
continue;
}
- cpu = _Per_CPU_Get_by_index(hart_index);
- cpu->cpu_per_cpu.clint_msip = &clint->msip[i / 16];
- cpu->cpu_per_cpu.clint_mtimecmp = &clint->mtimecmp[i / 16];
+ cpu_index = 0;
+#endif
+
+ riscv_clint_per_cpu_init(
+ clint,
+ _Per_CPU_Get_by_index(cpu_index),
+ (uint32_t) (i / 16)
+ );
+
+#ifndef RTEMS_SMP
+ break;
+#endif
}
}
@@ -155,20 +243,28 @@ static void riscv_plic_init(const void *fdt)
int len;
uint32_t interrupt_index;
uint32_t ndev;
- Per_CPU_Control *cpu;
node = fdt_node_offset_by_compatible(fdt, -1, "riscv,plic0");
plic = riscv_fdt_get_address(fdt, node);
+
if (plic == NULL) {
-#if RISCV_ENABLE_HTIF_SUPPORT != 0
+#ifdef RISCV_ENABLE_HTIF_SUPPORT
+ node = fdt_node_offset_by_compatible(fdt, -1, "ucb,htif0");
+
/* Spike platform has HTIF and does not have a PLIC */
- return;
+ if (node >= 0) {
+ return;
+ } else {
+ bsp_fatal(RISCV_FATAL_NO_PLIC_REG_IN_DEVICE_TREE);
+ }
#else
bsp_fatal(RISCV_FATAL_NO_PLIC_REG_IN_DEVICE_TREE);
#endif
}
+ riscv_plic = plic;
+
val = fdt_getprop(fdt, node, "riscv,ndev", &len);
if (val == NULL || len != 4) {
bsp_fatal(RISCV_FATAL_INVALID_PLIC_NDEV_IN_DEVICE_TREE);
@@ -183,36 +279,55 @@ static void riscv_plic_init(const void *fdt)
for (i = 0; i < len; i += 8) {
uint32_t hart_index;
+ uint32_t enable_register_count;
+ uint32_t cpu_index;
+
+ /*
+ * Each interrupt enable register contains exactly 32 enable bits.
+ * Calculate the enable register count based on the number of interrupts
+ * supported by the PLIC. Take the reserved interrupt ID zero into
+ * account.
+ */
+ enable_register_count = RTEMS_ALIGN_UP(ndev + 1, 32) / 32;
hart_index = riscv_get_hart_index_by_phandle(fdt32_to_cpu(val[i / 4]));
- if (hart_index >= rtems_configuration_get_maximum_processors()) {
+
+#ifdef RTEMS_SMP
+ cpu_index = _RISCV_Map_hardid_to_cpu_index(hart_index);
+ if (cpu_index >= rtems_configuration_get_maximum_processors()) {
continue;
}
- interrupt_index = fdt32_to_cpu(val[i / 4 + 1]);
- if (interrupt_index != RISCV_INTERRUPT_EXTERNAL_MACHINE) {
+ if ( _Scheduler_Initial_assignments[ cpu_index ].scheduler == NULL ) {
+ /* Skip not configured processor */
+ continue;
+ }
+#else
+ if (hart_index != RISCV_BOOT_HARTID) {
continue;
}
- plic->harts[i / 8].priority_threshold = 0;
+ cpu_index = 0;
+#endif
- cpu = _Per_CPU_Get_by_index(hart_index);
- cpu->cpu_per_cpu.plic_hart_regs = &plic->harts[i / 8];
- cpu->cpu_per_cpu.plic_m_ie = &plic->enable[i / 8][0];
- }
+ interrupt_index = fdt32_to_cpu(val[i / 4 + 1]);
+ if (interrupt_index != RISCV_INTERRUPT_EXTERNAL_MACHINE) {
+ continue;
+ }
- cpu = _Per_CPU_Get_by_index(0);
+ riscv_plic_per_cpu_init(
+ plic,
+ enable_register_count,
+ _Per_CPU_Get_by_index(cpu_index),
+ (uint32_t) (i / 8)
+ );
- for (interrupt_index = 1; interrupt_index <= ndev; ++interrupt_index) {
- plic->priority[interrupt_index] = 1;
- riscv_plic_irq_to_cpu[interrupt_index - 1] = cpu->cpu_per_cpu.plic_m_ie;
+#ifndef RTEMS_SMP
+ break;
+#endif
}
- /*
- * External M-mode interrupts on secondary processors are enabled in
- * bsp_start_on_secondary_processor().
- */
- set_csr(mie, MIP_MEIP);
+ riscv_plic_cpu_0_init(plic, ndev);
}
void bsp_interrupt_facility_initialize(void)
@@ -224,11 +339,39 @@ void bsp_interrupt_facility_initialize(void)
riscv_plic_init(fdt);
}
+bool bsp_interrupt_is_valid_vector(rtems_vector_number vector)
+{
+ /*
+ * The PLIC interrupt ID of zero is reserved. For example, this ID is used
+ * to indicate that no interrupt was claimed.
+ */
+ if (vector == RISCV_INTERRUPT_VECTOR_EXTERNAL(0)) {
+ return false;
+ }
+
+ return vector < (rtems_vector_number) BSP_INTERRUPT_VECTOR_COUNT;
+}
+
rtems_status_code bsp_interrupt_get_attributes(
rtems_vector_number vector,
rtems_interrupt_attributes *attributes
)
{
+ attributes->is_maskable = true;
+ attributes->can_enable = true;
+ attributes->maybe_enable = true;
+ attributes->can_disable = true;
+ attributes->maybe_disable = true;
+ attributes->can_raise = (vector == RISCV_INTERRUPT_VECTOR_SOFTWARE);
+ attributes->can_raise_on = attributes->can_raise;
+ attributes->cleared_by_acknowledge = true;
+ attributes->can_get_affinity = RISCV_INTERRUPT_VECTOR_IS_EXTERNAL(vector);
+ attributes->can_set_affinity = attributes->can_get_affinity;
+
+ if (vector == RISCV_INTERRUPT_VECTOR_SOFTWARE) {
+ attributes->trigger_signal = RTEMS_INTERRUPT_NO_SIGNAL;
+ }
+
return RTEMS_SUCCESSFUL;
}
@@ -239,14 +382,50 @@ rtems_status_code bsp_interrupt_is_pending(
{
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
bsp_interrupt_assert(pending != NULL);
- *pending = false;
- return RTEMS_UNSATISFIED;
+
+ if (RISCV_INTERRUPT_VECTOR_IS_EXTERNAL(vector)) {
+ uint32_t interrupt_index;
+ uint32_t group;
+ uint32_t bit;
+
+ interrupt_index = RISCV_INTERRUPT_VECTOR_EXTERNAL_TO_INDEX(vector);
+ group = interrupt_index / 32;
+ bit = UINT32_C(1) << (interrupt_index % 32);
+ *pending = ((riscv_plic->pending[group] & bit) != 0);
+ return RTEMS_SUCCESSFUL;
+ }
+
+ if (vector == RISCV_INTERRUPT_VECTOR_TIMER) {
+ *pending = (read_csr(mip) & MIP_MTIP) != 0;
+ return RTEMS_SUCCESSFUL;
+ }
+
+ _Assert(vector == RISCV_INTERRUPT_VECTOR_SOFTWARE);
+ *pending = (read_csr(mip) & MIP_MSIP) != 0;
+ return RTEMS_SUCCESSFUL;
}
-rtems_status_code bsp_interrupt_raise(rtems_vector_number vector)
+static inline rtems_status_code riscv_raise_on(
+ rtems_vector_number vector,
+ uint32_t cpu_index
+)
{
+ Per_CPU_Control *cpu;
+
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
- return RTEMS_UNSATISFIED;
+
+ if (vector != RISCV_INTERRUPT_VECTOR_SOFTWARE) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ cpu = _Per_CPU_Get_by_index(cpu_index);
+ *cpu->cpu_per_cpu.clint_msip = 0x1;
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code bsp_interrupt_raise(rtems_vector_number vector)
+{
+ return riscv_raise_on(vector, rtems_scheduler_get_processor());
}
#if defined(RTEMS_SMP)
@@ -255,8 +434,7 @@ rtems_status_code bsp_interrupt_raise_on(
uint32_t cpu_index
)
{
- bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
- return RTEMS_UNSATISFIED;
+ return riscv_raise_on(vector, cpu_index);
}
#endif
@@ -273,8 +451,53 @@ rtems_status_code bsp_interrupt_vector_is_enabled(
{
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
bsp_interrupt_assert(enabled != NULL);
- *enabled = false;
- return RTEMS_UNSATISFIED;
+
+ if (RISCV_INTERRUPT_VECTOR_IS_EXTERNAL(vector)) {
+ uint32_t interrupt_index;
+ uint32_t group;
+ uint32_t bit;
+ Per_CPU_Control *cpu;
+#ifdef RTEMS_SMP
+ uint32_t cpu_max;
+ uint32_t cpu_index;
+#endif
+
+ interrupt_index = RISCV_INTERRUPT_VECTOR_EXTERNAL_TO_INDEX(vector);
+ group = interrupt_index / 32;
+ bit = UINT32_C(1) << (interrupt_index % 32);
+
+#ifdef RTEMS_SMP
+ cpu_max = _SMP_Get_processor_maximum();
+
+ for (cpu_index = 0; cpu_index < cpu_max; ++cpu_index) {
+ volatile uint32_t *enable;
+
+ cpu = _Per_CPU_Get_by_index(cpu_index);
+ enable = cpu->cpu_per_cpu.plic_m_ie;
+
+ if (enable != NULL && (enable[group] & bit) != 0) {
+ *enabled = true;
+ return RTEMS_SUCCESSFUL;
+ }
+ }
+
+ *enabled = false;
+#else
+ cpu = _Per_CPU_Get_by_index(0);
+ *enabled = (cpu->cpu_per_cpu.plic_m_ie[group] & bit) != 0;
+#endif
+
+ return RTEMS_SUCCESSFUL;
+ }
+
+ if (vector == RISCV_INTERRUPT_VECTOR_TIMER) {
+ *enabled = (read_csr(mie) & MIP_MTIP) != 0;
+ return RTEMS_SUCCESSFUL;
+ }
+
+ _Assert(vector == RISCV_INTERRUPT_VECTOR_SOFTWARE);
+ *enabled = (read_csr(mie) & MIP_MSIP) != 0;
+ return RTEMS_SUCCESSFUL;
}
rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
@@ -283,18 +506,24 @@ rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
if (RISCV_INTERRUPT_VECTOR_IS_EXTERNAL(vector)) {
uint32_t interrupt_index;
- volatile uint32_t *enable;
uint32_t group;
uint32_t bit;
rtems_interrupt_lock_context lock_context;
+ Per_CPU_Control *cpu;
+#ifdef RTEMS_SMP
+ volatile uint32_t *enable;
+#endif
interrupt_index = RISCV_INTERRUPT_VECTOR_EXTERNAL_TO_INDEX(vector);
- enable = riscv_plic_irq_to_cpu[interrupt_index - 1];
group = interrupt_index / 32;
bit = UINT32_C(1) << (interrupt_index % 32);
+#ifdef RTEMS_SMP
+ enable = riscv_plic_irq_to_cpu[interrupt_index - 1];
+#endif
rtems_interrupt_lock_acquire(&riscv_plic_lock, &lock_context);
+#ifdef RTEMS_SMP
if (enable != NULL) {
enable[group] |= bit;
} else {
@@ -304,8 +533,6 @@ rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
cpu_max = _SMP_Get_processor_maximum();
for (cpu_index = 0; cpu_index < cpu_max; ++cpu_index) {
- Per_CPU_Control *cpu;
-
cpu = _Per_CPU_Get_by_index(cpu_index);
enable = cpu->cpu_per_cpu.plic_m_ie;
@@ -314,10 +541,22 @@ rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
}
}
}
+#else
+ cpu = _Per_CPU_Get_by_index(0);
+ cpu->cpu_per_cpu.plic_m_ie[group] |= bit;
+#endif
rtems_interrupt_lock_release(&riscv_plic_lock, &lock_context);
+ return RTEMS_SUCCESSFUL;
}
+ if (vector == RISCV_INTERRUPT_VECTOR_TIMER) {
+ set_csr(mie, MIP_MTIP);
+ return RTEMS_SUCCESSFUL;
+ }
+
+ _Assert(vector == RISCV_INTERRUPT_VECTOR_SOFTWARE);
+ set_csr(mie, MIP_MSIP);
return RTEMS_SUCCESSFUL;
}
@@ -327,18 +566,24 @@ rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
if (RISCV_INTERRUPT_VECTOR_IS_EXTERNAL(vector)) {
uint32_t interrupt_index;
- volatile uint32_t *enable;
uint32_t group;
uint32_t bit;
rtems_interrupt_lock_context lock_context;
+ Per_CPU_Control *cpu;
+#ifdef RTEMS_SMP
+ volatile uint32_t *enable;
+#endif
interrupt_index = RISCV_INTERRUPT_VECTOR_EXTERNAL_TO_INDEX(vector);
- enable = riscv_plic_irq_to_cpu[interrupt_index - 1];
group = interrupt_index / 32;
bit = UINT32_C(1) << (interrupt_index % 32);
+#ifdef RTEMS_SMP
+ enable = riscv_plic_irq_to_cpu[interrupt_index - 1];
+#endif
rtems_interrupt_lock_acquire(&riscv_plic_lock, &lock_context);
+#ifdef RTEMS_SMP
if (enable != NULL) {
enable[group] &= ~bit;
} else {
@@ -348,8 +593,6 @@ rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
cpu_max = _SMP_Get_processor_maximum();
for (cpu_index = 0; cpu_index < cpu_max; ++cpu_index) {
- Per_CPU_Control *cpu;
-
cpu = _Per_CPU_Get_by_index(cpu_index);
enable = cpu->cpu_per_cpu.plic_m_ie;
@@ -358,13 +601,26 @@ rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
}
}
}
+#else
+ cpu = _Per_CPU_Get_by_index(0);
+ cpu->cpu_per_cpu.plic_m_ie[group] &= ~bit;
+#endif
rtems_interrupt_lock_release(&riscv_plic_lock, &lock_context);
+ return RTEMS_SUCCESSFUL;
}
+ if (vector == RISCV_INTERRUPT_VECTOR_TIMER) {
+ clear_csr(mie, MIP_MTIP);
+ return RTEMS_SUCCESSFUL;
+ }
+
+ _Assert(vector == RISCV_INTERRUPT_VECTOR_SOFTWARE);
+ clear_csr(mie, MIP_MSIP);
return RTEMS_SUCCESSFUL;
}
+#ifdef RTEMS_SMP
rtems_status_code bsp_interrupt_set_affinity(
rtems_vector_number vector,
const Processor_mask *affinity
@@ -393,7 +649,7 @@ rtems_status_code bsp_interrupt_set_affinity(
return RTEMS_SUCCESSFUL;
}
- bsp_fatal(RISCV_FATAL_INVALID_INTERRUPT_AFFINITY);
+ return RTEMS_INVALID_NUMBER;
}
return RTEMS_UNSATISFIED;
@@ -404,8 +660,6 @@ rtems_status_code bsp_interrupt_get_affinity(
Processor_mask *affinity
)
{
- _Processor_mask_Zero(affinity);
-
if (RISCV_INTERRUPT_VECTOR_IS_EXTERNAL(vector)) {
uint32_t interrupt_index;
volatile uint32_t *enable;
@@ -432,7 +686,10 @@ rtems_status_code bsp_interrupt_get_affinity(
} else {
_Processor_mask_Assign(affinity, _SMP_Get_online_processors());
}
+
+ return RTEMS_SUCCESSFUL;
}
- return RTEMS_SUCCESSFUL;
+ return RTEMS_UNSATISFIED;
}
+#endif