From 09be98d9101fcf9edb5fcc9c89187798c73d3911 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 1 Jul 2021 14:45:58 +0200 Subject: sparc/irq: Implement new interrupt directives Update #3269. --- bsps/sparc/erc32/include/bsp/irq.h | 3 +- bsps/sparc/erc32/include/erc32.h | 12 ++++- bsps/sparc/leon2/include/bsp/irq.h | 3 +- bsps/sparc/leon2/include/leon.h | 16 +++++- bsps/sparc/leon3/start/eirq.c | 102 +++++++++++++++++++++++++++++++++---- bsps/sparc/shared/irq/irq-shared.c | 48 ++++++++++++++--- 6 files changed, 162 insertions(+), 22 deletions(-) (limited to 'bsps') diff --git a/bsps/sparc/erc32/include/bsp/irq.h b/bsps/sparc/erc32/include/bsp/irq.h index a61f51d6b6..83b383ba7a 100644 --- a/bsps/sparc/erc32/include/bsp/irq.h +++ b/bsps/sparc/erc32/include/bsp/irq.h @@ -23,8 +23,7 @@ #define BSP_INTERRUPT_VECTOR_MAX_STD 15 /* Standard IRQ controller */ #define BSP_INTERRUPT_VECTOR_COUNT (BSP_INTERRUPT_VECTOR_MAX_STD + 1) -/* No extra check is needed */ -#undef BSP_INTERRUPT_CUSTOM_VALID_VECTOR +#define BSP_INTERRUPT_CUSTOM_VALID_VECTOR RTEMS_INLINE_ROUTINE rtems_status_code bsp_interrupt_set_affinity( rtems_vector_number vector, diff --git a/bsps/sparc/erc32/include/erc32.h b/bsps/sparc/erc32/include/erc32.h index a677b13d25..f9cdbc960a 100644 --- a/bsps/sparc/erc32/include/erc32.h +++ b/bsps/sparc/erc32/include/erc32.h @@ -352,7 +352,7 @@ static __inline__ int bsp_irq_fixup(int irq) \ _level = sparc_disable_interrupts(); \ ERC32_MEC.Test_Control = ERC32_MEC.Test_Control | 0x80000; \ - ERC32_MEC.Interrupt_Force = (1 << (_source)); \ + ERC32_MEC.Interrupt_Force |= (1 << (_source)); \ sparc_enable_interrupts( _level ); \ } while (0) @@ -406,7 +406,17 @@ static __inline__ int bsp_irq_fixup(int irq) /* Make all SPARC BSPs have common macros for interrupt handling on local CPU */ #define BSP_Clear_interrupt(_source) ERC32_Clear_interrupt(_source) #define BSP_Force_interrupt(_source) ERC32_Force_interrupt(_source) +#define BSP_Clear_forced_interrupt( _source ) \ + do { \ + uint32_t _level; \ + \ + _level = sparc_disable_interrupts(); \ + ERC32_MEC.Interrupt_Force &= ~(1 << (_source)); \ + sparc_enable_interrupts( _level ); \ + } while (0) #define BSP_Is_interrupt_pending(_source) ERC32_Is_interrupt_pending(_source) +#define BSP_Is_interrupt_forced(_source) \ + (ERC32_MEC.Interrupt_Force & (1 << (_source))) #define BSP_Is_interrupt_masked(_source) ERC32_Is_interrupt_masked(_source) #define BSP_Unmask_interrupt(_source) ERC32_Unmask_interrupt(_source) #define BSP_Mask_interrupt(_source) ERC32_Mask_interrupt(_source) diff --git a/bsps/sparc/leon2/include/bsp/irq.h b/bsps/sparc/leon2/include/bsp/irq.h index 5f2359014a..a4ce3c55ff 100644 --- a/bsps/sparc/leon2/include/bsp/irq.h +++ b/bsps/sparc/leon2/include/bsp/irq.h @@ -21,7 +21,6 @@ #define BSP_INTERRUPT_VECTOR_MAX_STD 15 /* Standard IRQ controller */ #define BSP_INTERRUPT_VECTOR_COUNT (BSP_INTERRUPT_VECTOR_MAX_STD + 1) -/* No extra check is needed */ -#undef BSP_INTERRUPT_CUSTOM_VALID_VECTOR +#define BSP_INTERRUPT_CUSTOM_VALID_VECTOR #endif /* LIBBSP_LEON2_IRQ_CONFIG_H */ diff --git a/bsps/sparc/leon2/include/leon.h b/bsps/sparc/leon2/include/leon.h index fc90e1f7e6..11196aee6d 100644 --- a/bsps/sparc/leon2/include/leon.h +++ b/bsps/sparc/leon2/include/leon.h @@ -295,7 +295,11 @@ static __inline__ int bsp_irq_fixup(int irq) #define LEON_Force_interrupt( _source ) \ do { \ - LEON_REG.Interrupt_Force = (1 << (_source)); \ + uint32_t _level; \ + \ + _level = sparc_disable_interrupts(); \ + LEON_REG.Interrupt_Force |= (1 << (_source)); \ + sparc_enable_interrupts( _level ); \ } while (0) #define LEON_Is_interrupt_pending( _source ) \ @@ -348,7 +352,17 @@ static __inline__ int bsp_irq_fixup(int irq) /* Make all SPARC BSPs have common macros for interrupt handling */ #define BSP_Clear_interrupt(_source) LEON_Clear_interrupt(_source) #define BSP_Force_interrupt(_source) LEON_Force_interrupt(_source) +#define BSP_Clear_forced_interrupt( _source ) \ + do { \ + uint32_t _level; \ + \ + _level = sparc_disable_interrupts(); \ + LEON_REG.Interrupt_Force &= ~(1 << (_source)); \ + sparc_enable_interrupts( _level ); \ + } while (0) #define BSP_Is_interrupt_pending(_source) LEON_Is_interrupt_pending(_source) +#define BSP_Is_interrupt_forced(_source) \ + (LEON_REG.Interrupt_Force & (1 << (_source))) #define BSP_Is_interrupt_masked(_source) LEON_Is_interrupt_masked(_source) #define BSP_Unmask_interrupt(_source) LEON_Unmask_interrupt(_source) #define BSP_Mask_interrupt(_source) LEON_Mask_interrupt(_source) diff --git a/bsps/sparc/leon3/start/eirq.c b/bsps/sparc/leon3/start/eirq.c index 5519d6efe7..0d71b79f1c 100644 --- a/bsps/sparc/leon3/start/eirq.c +++ b/bsps/sparc/leon3/start/eirq.c @@ -66,6 +66,20 @@ rtems_status_code bsp_interrupt_get_attributes( rtems_interrupt_attributes *attributes ) { + bool is_standard_interrupt; + + is_standard_interrupt = (vector <= BSP_INTERRUPT_VECTOR_MAX_STD); + attributes->is_maskable = (vector != 15); + attributes->can_enable = true; + attributes->maybe_enable = true; + attributes->can_disable = true; + attributes->maybe_disable = true; + attributes->can_raise = true; + attributes->can_raise_on = is_standard_interrupt; + attributes->can_clear = true; + attributes->cleared_by_acknowledge = true; + attributes->can_get_affinity = is_standard_interrupt; + attributes->can_set_affinity = is_standard_interrupt; return RTEMS_SUCCESSFUL; } @@ -74,16 +88,56 @@ rtems_status_code bsp_interrupt_is_pending( bool *pending ) { +#if defined(RTEMS_SMP) + rtems_interrupt_level level; + uint32_t bit; + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); bsp_interrupt_assert(pending != NULL); - *pending = false; - return RTEMS_UNSATISFIED; + bit = 1U << vector; + + rtems_interrupt_local_disable(level); + *pending = (LEON3_IrqCtrl_Regs->ipend & bit) != 0 || + (LEON3_IrqCtrl_Regs->force[rtems_scheduler_get_processor()] & bit) != 0; + rtems_interrupt_local_enable(level); + return RTEMS_SUCCESSFUL; +#else + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + *pending = !BSP_Is_interrupt_pending(vector); + return RTEMS_SUCCESSFUL; +#endif } rtems_status_code bsp_interrupt_raise(rtems_vector_number vector) { + uint32_t bit; + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); - return RTEMS_UNSATISFIED; + bit = 1U << vector; + + if ( vector <= BSP_INTERRUPT_VECTOR_MAX_STD ) { + uint32_t cpu_count; + uint32_t cpu_index; + + cpu_count = rtems_scheduler_get_processor_maximum(); + + for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) { + LEON3_IrqCtrl_Regs->force[cpu_index] = bit; + } + } else { + rtems_interrupt_lock_context lock_context; + + /* + * This is a very dangerous operation and should only be used for test + * software. We may accidentally clear the pending state set by + * peripherals with this read-modify-write operation. + */ + LEON3_IRQCTRL_ACQUIRE(&lock_context); + LEON3_IrqCtrl_Regs->ipend |= bit; + LEON3_IRQCTRL_RELEASE(&lock_context); + } + + return RTEMS_SUCCESSFUL; } #if defined(RTEMS_SMP) @@ -93,14 +147,31 @@ rtems_status_code bsp_interrupt_raise_on( ) { bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); - return RTEMS_UNSATISFIED; + bsp_interrupt_assert(cpu_index < rtems_scheduler_get_processor_maximum()); + + if ( vector > BSP_INTERRUPT_VECTOR_MAX_STD ) { + return RTEMS_UNSATISFIED; + } + + LEON3_IrqCtrl_Regs->force[cpu_index] = 1U << vector; + return RTEMS_SUCCESSFUL; } #endif rtems_status_code bsp_interrupt_clear(rtems_vector_number vector) { + uint32_t bit; + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); - return RTEMS_UNSATISFIED; + bit = 1U << vector; + + LEON3_IrqCtrl_Regs->iclear = bit; + + if (vector <= BSP_INTERRUPT_VECTOR_MAX_STD) { + LEON3_IrqCtrl_Regs->force[rtems_scheduler_get_processor()] = bit << 16; + } + + return RTEMS_SUCCESSFUL; } rtems_status_code bsp_interrupt_vector_is_enabled( @@ -109,9 +180,9 @@ 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; + *enabled = + !BSP_Cpu_Is_interrupt_masked(vector, _LEON3_Get_current_processor()); + return RTEMS_SUCCESSFUL; } #if defined(RTEMS_SMP) @@ -123,8 +194,13 @@ static void leon3_interrupt_vector_enable(rtems_vector_number vector) uint32_t bit; uint32_t unmasked; + if (vector <= BSP_INTERRUPT_VECTOR_MAX_STD) { + affinity = leon3_interrupt_affinities[vector]; + } else { + affinity = leon3_interrupt_affinities[LEON3_IrqCtrl_EIrq]; + } + cpu_count = rtems_scheduler_get_processor_maximum(); - affinity = leon3_interrupt_affinities[vector]; bit = 1U << vector; unmasked = 0; @@ -206,6 +282,10 @@ rtems_status_code bsp_interrupt_set_affinity( uint32_t cpu_index; uint32_t bit; + if (vector >= RTEMS_ARRAY_SIZE(leon3_interrupt_affinities)) { + return RTEMS_UNSATISFIED; + } + cpu_count = rtems_scheduler_get_processor_maximum(); bit = 1U << vector; @@ -232,6 +312,10 @@ rtems_status_code bsp_interrupt_get_affinity( Processor_mask *affinity ) { + if (vector >= RTEMS_ARRAY_SIZE(leon3_interrupt_affinities)) { + return RTEMS_UNSATISFIED; + } + *affinity = leon3_interrupt_affinities[vector]; return RTEMS_SUCCESSFUL; } diff --git a/bsps/sparc/shared/irq/irq-shared.c b/bsps/sparc/shared/irq/irq-shared.c index 68ad57d723..8896aca761 100644 --- a/bsps/sparc/shared/irq/irq-shared.c +++ b/bsps/sparc/shared/irq/irq-shared.c @@ -26,17 +26,41 @@ static inline int bsp_irq_cpu(int irq) } #if !defined(LEON3) +bool bsp_interrupt_is_valid_vector(rtems_vector_number vector) +{ + if (vector == 0) { + return false; + } + + return vector <= BSP_INTERRUPT_VECTOR_MAX_STD; +} + rtems_status_code bsp_interrupt_facility_initialize(void) { /* Nothing to do */ return RTEMS_SUCCESSFUL; } +static bool is_maskable(rtems_vector_number vector) +{ + return vector != 15; +} + rtems_status_code bsp_interrupt_get_attributes( rtems_vector_number vector, rtems_interrupt_attributes *attributes ) { + attributes->is_maskable = is_maskable(vector); + attributes->can_enable = true; + attributes->maybe_enable = true; + attributes->can_disable = is_maskable(vector); + attributes->maybe_disable = is_maskable(vector); + attributes->can_raise = true; + attributes->can_raise_on = true; + attributes->can_clear = true; + attributes->cleared_by_acknowledge = true; + attributes->can_set_affinity = true; return RTEMS_SUCCESSFUL; } @@ -47,14 +71,16 @@ 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; + *pending = BSP_Is_interrupt_pending(vector) || + BSP_Is_interrupt_forced(vector); + return RTEMS_SUCCESSFUL; } rtems_status_code bsp_interrupt_raise(rtems_vector_number vector) { bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); - return RTEMS_UNSATISFIED; + BSP_Force_interrupt(vector); + return RTEMS_SUCCESSFUL; } #if defined(RTEMS_SMP) @@ -64,14 +90,17 @@ rtems_status_code bsp_interrupt_raise_on( ) { bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); - return RTEMS_UNSATISFIED; + BSP_Force_interrupt(vector); + return RTEMS_SUCCESSFUL; } #endif rtems_status_code bsp_interrupt_clear(rtems_vector_number vector) { bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); - return RTEMS_UNSATISFIED; + BSP_Clear_forced_interrupt(vector); + BSP_Clear_interrupt(vector); + return RTEMS_SUCCESSFUL; } rtems_status_code bsp_interrupt_vector_is_enabled( @@ -81,8 +110,8 @@ 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; + *enabled = !BSP_Cpu_Is_interrupt_masked(vector, bsp_irq_cpu(vector)); + return RTEMS_SUCCESSFUL; } rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector) @@ -95,6 +124,11 @@ rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector) rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector) { bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if (!is_maskable(vector)) { + return RTEMS_UNSATISFIED; + } + BSP_Cpu_Mask_interrupt(vector, 0); return RTEMS_SUCCESSFUL; } -- cgit v1.2.3