From c9206587aceafcc6265eccc42522634b3c5281a9 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 29 Sep 2026 03:08:10 +0200 Subject: [PATCH] bsps/leon3: Size the interrupt map per chip The BSP assumed 64 bus lines for every chip with an interrupt map. The GR740 has 32 bus lines in eight map registers. The BSP read the undefined offsets 0x320 to 0x33C, and vector 32 passed as valid, so ts-validation-intr failed on the GR740. The GR765 has 64 bus lines. A map field is eight bits wide. A field value above 31 indexed past the dispatch table of 32 entries and made the bit shifts undefined. Replace the option LEON3_IRQAMP_IRQMAP by LEON3_IRQMAP_BUS_LINE_COUNT, which is 32 for the GR740 and 64 for the GR765. With an interrupt map, an interrupt vector is a bus line. The vector count is then the bus line count, and the dispatch table keeps one entry for each controller line. Bound each map entry by the dispatch table, so that a hardware fault cannot index past it. The description of LEON3_IRQAMP_EXTENDED_INTERRUPT named an interrupt line and did not say which kind. Call it a controller line, the term which the other options use. The extended interrupt raise test took a vector for its controller line. It raised 1U << vector for vectors up to the count, which is undefined from 32 on. Its specification item did not exist. Regenerate the test from the new item. It raises the mapped controller line of each vector which maps to an extended controller line. It checks that it exercised each extended controller line. Close #5786. Assisted-by: Claude:claude-opus-5-5 claude-code Signed-off-by: Sebastian Huber --- bsps/sparc/leon3/include/bsp/irq.h | 18 +- bsps/sparc/leon3/include/bsp/irqimpl.h | 2 +- bsps/sparc/leon3/start/bspsmp.c | 2 +- bsps/sparc/leon3/start/eirq.c | 66 ++--- spec/build/bsps/sparc/leon3/grp.yml | 2 +- .../bsps/sparc/leon3/optirqampextirq.yml | 3 +- .../bsps/sparc/leon3/optirqampirqmap.yml | 20 -- .../sparc/leon3/optirqmapbuslinecount.yml | 28 ++ .../bsps/tc-sparc-leon3-ext-irq-raise.c | 244 ++++++++++++------ 9 files changed, 249 insertions(+), 136 deletions(-) delete mode 100644 spec/build/bsps/sparc/leon3/optirqampirqmap.yml create mode 100644 spec/build/bsps/sparc/leon3/optirqmapbuslinecount.yml diff --git a/bsps/sparc/leon3/include/bsp/irq.h b/bsps/sparc/leon3/include/bsp/irq.h index 3b8ce260ec..7b0617a27f 100644 --- a/bsps/sparc/leon3/include/bsp/irq.h +++ b/bsps/sparc/leon3/include/bsp/irq.h @@ -42,10 +42,19 @@ #define BSP_INTERRUPT_VECTOR_MAX_STD 15 /* Standard IRQ controller */ #define BSP_INTERRUPT_VECTOR_MAX_EXT 31 /* Extended IRQ controller */ -#define BSP_INTERRUPT_VECTOR_MAX_MAP \ - 63 /* Extended IRQ controller with mapping registers */ +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 +/* + * A bus line is an interrupt line of the system interrupt bus. A controller + * line is an interrupt line of the IRQ(A)MP. With an interrupt map, an + * interrupt vector is a bus line. The dispatch table has one entry for each + * controller line. + */ +#define BSP_INTERRUPT_VECTOR_COUNT LEON3_IRQMAP_BUS_LINE_COUNT +#define BSP_INTERRUPT_DISPATCH_TABLE_SIZE ( BSP_INTERRUPT_VECTOR_MAX_EXT + 1 ) +#else #define BSP_INTERRUPT_VECTOR_COUNT ( BSP_INTERRUPT_VECTOR_MAX_EXT + 1 ) +#endif /* The check is different depending on IRQ controller, runtime detected */ #define BSP_INTERRUPT_CUSTOM_VALID_VECTOR @@ -97,9 +106,8 @@ rtems_status_code leon3_irqmap_get( rtems_vector_number *controller_line ); -#ifdef LEON3_IRQAMP_IRQMAP -extern rtems_vector_number - LEON3_IrqCtrl_Mapping[ BSP_INTERRUPT_VECTOR_MAX_MAP + 1 ]; +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 +extern uint8_t LEON3_IrqCtrl_Mapping[ BSP_INTERRUPT_VECTOR_COUNT ]; #define bsp_interrupt_vector_modify( v ) LEON3_IrqCtrl_Mapping[ ( v ) ] #endif diff --git a/bsps/sparc/leon3/include/bsp/irqimpl.h b/bsps/sparc/leon3/include/bsp/irqimpl.h index 362caf7d7e..af39705814 100644 --- a/bsps/sparc/leon3/include/bsp/irqimpl.h +++ b/bsps/sparc/leon3/include/bsp/irqimpl.h @@ -159,7 +159,7 @@ static inline rtems_vector_number leon3_irqmap_get_unchecked( rtems_vector_number bus_line ) { -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 return LEON3_IrqCtrl_Mapping[ bus_line ]; #else return bus_line; diff --git a/bsps/sparc/leon3/start/bspsmp.c b/bsps/sparc/leon3/start/bspsmp.c index 29d194b86d..91358ac903 100644 --- a/bsps/sparc/leon3/start/bspsmp.c +++ b/bsps/sparc/leon3/start/bspsmp.c @@ -114,7 +114,7 @@ void _CPU_SMP_Send_interrupt( uint32_t target_processor_index ) /* send interrupt to destination CPU */ grlib_store_32( &LEON3_IrqCtrl_Regs->piforce[ target_processor_index ], -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 1U << leon3_irqmap_get_unchecked( LEON3_mp_irq ) #else 1U << LEON3_mp_irq diff --git a/bsps/sparc/leon3/start/eirq.c b/bsps/sparc/leon3/start/eirq.c index ba20e8f418..2359b766d4 100644 --- a/bsps/sparc/leon3/start/eirq.c +++ b/bsps/sparc/leon3/start/eirq.c @@ -49,9 +49,20 @@ uint32_t LEON3_IrqCtrl_EIrq; #endif -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 /* Mapping from bus interrupt lines to IRQ(A)MP interrupt lines */ -rtems_vector_number LEON3_IrqCtrl_Mapping[ BSP_INTERRUPT_VECTOR_MAX_MAP + 1 ]; +uint8_t LEON3_IrqCtrl_Mapping[ BSP_INTERRUPT_VECTOR_COUNT ]; + +/* + * A map field is eight bits wide. A field value outside the dispatch table is + * a hardware fault. The mask keeps the controller line inside the dispatch + * table also in this case. + */ +static uint8_t leon3_irqmap_controller_line( uint32_t field ) +{ + return (uint8_t) ( field & ( BSP_INTERRUPT_DISPATCH_TABLE_SIZE - 1 ) ); +} + #endif rtems_status_code leon3_irqmap_get( @@ -63,11 +74,7 @@ rtems_status_code leon3_irqmap_get( return RTEMS_INVALID_ADDRESS; } -#ifdef LEON3_IRQAMP_IRQMAP - if ( bus_line > BSP_INTERRUPT_VECTOR_MAX_MAP ) { -#else if ( bus_line >= BSP_INTERRUPT_VECTOR_COUNT ) { -#endif *controller_line = UINT32_MAX; return RTEMS_INVALID_NUMBER; } @@ -91,25 +98,25 @@ void leon3_ext_irq_init( irqamp *regs ) grlib_load_32( ®s->mpstat ) ); #endif -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 for ( - rtems_vector_number bus_line = 0; bus_line <= BSP_INTERRUPT_VECTOR_MAX_MAP; + rtems_vector_number bus_line = 0; bus_line < BSP_INTERRUPT_VECTOR_COUNT; bus_line += 4 ) { uint32_t n = bus_line / 4; uint32_t irqmap_n = grlib_load_32( &LEON3_IrqCtrl_Regs->irqmap[ n ] ); - LEON3_IrqCtrl_Mapping[ bus_line + 0 ] = IRQAMP_IRQMAP_IRQMAP_4_N_0_GET( - irqmap_n + LEON3_IrqCtrl_Mapping[ bus_line + 0 ] = leon3_irqmap_controller_line( + IRQAMP_IRQMAP_IRQMAP_4_N_0_GET( irqmap_n ) ); - LEON3_IrqCtrl_Mapping[ bus_line + 1 ] = IRQAMP_IRQMAP_IRQMAP_4_N_1_GET( - irqmap_n + LEON3_IrqCtrl_Mapping[ bus_line + 1 ] = leon3_irqmap_controller_line( + IRQAMP_IRQMAP_IRQMAP_4_N_1_GET( irqmap_n ) ); - LEON3_IrqCtrl_Mapping[ bus_line + 2 ] = IRQAMP_IRQMAP_IRQMAP_4_N_2_GET( - irqmap_n + LEON3_IrqCtrl_Mapping[ bus_line + 2 ] = leon3_irqmap_controller_line( + IRQAMP_IRQMAP_IRQMAP_4_N_2_GET( irqmap_n ) ); - LEON3_IrqCtrl_Mapping[ bus_line + 3 ] = IRQAMP_IRQMAP_IRQMAP_4_N_3_GET( - irqmap_n + LEON3_IrqCtrl_Mapping[ bus_line + 3 ] = leon3_irqmap_controller_line( + IRQAMP_IRQMAP_IRQMAP_4_N_3_GET( irqmap_n ) ); } #endif @@ -121,8 +128,9 @@ bool bsp_interrupt_is_valid_vector( rtems_vector_number vector ) return false; } -#if defined( LEON3_IRQAMP_IRQMAP ) - return vector <= BSP_INTERRUPT_VECTOR_MAX_MAP; +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 + return vector < BSP_INTERRUPT_VECTOR_COUNT && + leon3_irqmap_get_unchecked( vector ) != 0; #elif defined( LEON3_IRQAMP_EXTENDED_INTERRUPT ) return vector <= BSP_INTERRUPT_VECTOR_MAX_EXT; #else @@ -184,7 +192,7 @@ rtems_status_code bsp_interrupt_get_attributes( bool is_standard_interrupt; bool is_maskable; -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 vector = leon3_irqmap_get_unchecked( vector ); #endif @@ -216,7 +224,7 @@ rtems_status_code bsp_interrupt_is_pending( bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); bsp_interrupt_assert( pending != NULL ); -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 vector = leon3_irqmap_get_unchecked( vector ); #endif @@ -242,7 +250,7 @@ rtems_status_code bsp_interrupt_raise( rtems_vector_number vector ) bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 vector = leon3_irqmap_get_unchecked( vector ); #endif @@ -272,7 +280,7 @@ rtems_status_code bsp_interrupt_raise_on( bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); bsp_interrupt_assert( cpu_index < rtems_scheduler_get_processor_maximum() ); -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 vector = leon3_irqmap_get_unchecked( vector ); #endif @@ -293,7 +301,7 @@ rtems_status_code bsp_interrupt_clear( rtems_vector_number vector ) bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 vector = leon3_irqmap_get_unchecked( vector ); #endif @@ -323,7 +331,7 @@ rtems_status_code bsp_interrupt_vector_is_enabled( bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 vector = leon3_irqmap_get_unchecked( vector ); #endif @@ -345,7 +353,7 @@ static void leon3_interrupt_vector_enable( rtems_vector_number vector ) uint32_t brdcst; irqamp *regs; -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 vector = leon3_irqmap_get_unchecked( vector ); #endif @@ -399,7 +407,7 @@ rtems_status_code bsp_interrupt_vector_enable( rtems_vector_number vector ) bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 vector = leon3_irqmap_get_unchecked( vector ); #endif @@ -435,7 +443,7 @@ rtems_status_code bsp_interrupt_vector_disable( rtems_vector_number vector ) bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 vector = leon3_irqmap_get_unchecked( vector ); #endif @@ -508,7 +516,7 @@ rtems_status_code bsp_interrupt_set_affinity( uint32_t bit; irqamp *regs; -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 rtems_vector_number irq_vector; if ( leon3_irqmap_get( vector, &irq_vector ) != RTEMS_SUCCESSFUL ) { @@ -549,7 +557,7 @@ rtems_status_code bsp_interrupt_get_affinity( Processor_mask *affinity ) { -#ifdef LEON3_IRQAMP_IRQMAP +#if LEON3_IRQMAP_BUS_LINE_COUNT != 0 rtems_vector_number irq_vector; if ( leon3_irqmap_get( vector, &irq_vector ) != RTEMS_SUCCESSFUL ) { diff --git a/spec/build/bsps/sparc/leon3/grp.yml b/spec/build/bsps/sparc/leon3/grp.yml index e390a87653..acaf3680a5 100644 --- a/spec/build/bsps/sparc/leon3/grp.yml +++ b/spec/build/bsps/sparc/leon3/grp.yml @@ -47,7 +47,7 @@ links: - role: build-dependency uid: optirqampextirq - role: build-dependency - uid: optirqampirqmap + uid: optirqmapbuslinecount - role: build-dependency uid: optirqampts - role: build-dependency diff --git a/spec/build/bsps/sparc/leon3/optirqampextirq.yml b/spec/build/bsps/sparc/leon3/optirqampextirq.yml index a8defbf606..1819d26711 100644 --- a/spec/build/bsps/sparc/leon3/optirqampextirq.yml +++ b/spec/build/bsps/sparc/leon3/optirqampextirq.yml @@ -17,5 +17,6 @@ format: '{}' links: [] name: LEON3_IRQAMP_EXTENDED_INTERRUPT description: | - This option specifies the interrupt line of the IRQ(A)MP extended interrupt. + This option specifies the controller line of the IRQ(A)MP extended + interrupt. type: build diff --git a/spec/build/bsps/sparc/leon3/optirqampirqmap.yml b/spec/build/bsps/sparc/leon3/optirqampirqmap.yml deleted file mode 100644 index 855b8f1702..0000000000 --- a/spec/build/bsps/sparc/leon3/optirqampirqmap.yml +++ /dev/null @@ -1,20 +0,0 @@ -SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause -copyrights: -- Copyright (C) 2026 Frontgrade Gaisler -actions: -- get-boolean: null -- define-condition: null -build-type: option -default: -- enabled-by: - - sparc/gr740 - - sparc/gr765 - value: true -- enabled-by: true - value: false -enabled-by: true -links: [] -name: LEON3_IRQAMP_IRQMAP -description: | - This option specifies if the IRQ(A)MP interrupt (re-)map registers are available. -type: build diff --git a/spec/build/bsps/sparc/leon3/optirqmapbuslinecount.yml b/spec/build/bsps/sparc/leon3/optirqmapbuslinecount.yml new file mode 100644 index 0000000000..bea165825f --- /dev/null +++ b/spec/build/bsps/sparc/leon3/optirqmapbuslinecount.yml @@ -0,0 +1,28 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-integer: null +- assert-in-set: + - 0 + - 32 + - 64 +- format-and-define: null +build-type: option +copyrights: +- Copyright (C) 2026 Frontgrade Gaisler +- Copyright (C) 2026 embedded brains GmbH & Co. KG +default: +- enabled-by: sparc/gr740 + value: 32 +- enabled-by: sparc/gr765 + value: 64 +- enabled-by: true + value: 0 +description: | + This option defines the count of bus lines of the IRQ(A)MP interrupt map. + The GR740 has 32 bus lines, and the GR765 has 64. A value of zero specifies + that the BSP uses no interrupt map. +enabled-by: true +format: '{}' +links: [] +name: LEON3_IRQMAP_BUS_LINE_COUNT +type: build diff --git a/testsuites/validation/bsps/tc-sparc-leon3-ext-irq-raise.c b/testsuites/validation/bsps/tc-sparc-leon3-ext-irq-raise.c index 9b64f9c2b3..d434d4528b 100644 --- a/testsuites/validation/bsps/tc-sparc-leon3-ext-irq-raise.c +++ b/testsuites/validation/bsps/tc-sparc-leon3-ext-irq-raise.c @@ -8,6 +8,7 @@ /* * Copyright (C) 2026 Critical Software S.A + * Copyright (C) 2026 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,9 +40,7 @@ #include #include #include - #include - #include #include "tx-support.h" @@ -57,142 +56,205 @@ * @brief This test case validates the extended interrupt raise path for LEON3 * BSPs. * + * The test raises an extended controller line through a read-modify-write of + * the pending register. This is safe only in the test, since no peripheral + * drives the tested bus lines. + * * This test case performs the following actions: * - * - Iterate through each testable extended interrupt vector (16 to 31). + * - Iterate through each interrupt vector whose bus line maps to an extended + * controller line and which has no interrupt handler installed. Get the + * attributes of the vector and try to raise it through the directive. + * Install an interrupt handler, enable the vector, raise the extended + * controller line through the pending register and wait for the handler. + * Clear and disable the vector and remove the handler. * - * - Check that API raise operations are not available for extended vectors. + * - Check that the test exercised each extended controller line. * - * - Check that rtems_interrupt_raise() returns RTEMS_UNSATISFIED and does - * not alter the pending state. + * - Check that the attributes of each tested interrupt vector state that the + * vector can be enabled, disabled and cleared, and that it can neither be + * raised nor be raised on a processor. * - * - Raise the vector using an unsafe test-only support operation. + * - Check that the directive rejected the raise of each tested interrupt + * vector and that the pending state stayed unchanged. * - * - Check that the interrupt handler installed for the vector is called. + * - Check that the pending extended controller line called the interrupt + * handler of each tested interrupt vector exactly once. * * @{ */ +/** + * @brief Test context for spec:/bsp/sparc/leon3/val/ext-irq-raise test case. + */ typedef struct { - volatile uint32_t call_count; + /** + * @brief This member contains the count of tested interrupt vectors. + */ + uint32_t tested_vectors; + + /** + * @brief This member contains the set of the tested controller lines. + */ + uint32_t tested_controller_lines; + + /** + * @brief This member contains the count of tested interrupt vectors which + * the BSP reported as not raisable. + */ + uint32_t not_raisable; + + /** + * @brief This member contains the count of tested interrupt vectors whose + * raise the directive rejected. + */ + uint32_t raise_rejected; + + /** + * @brief This member contains the count of tested interrupt vectors whose + * interrupt handler the BSP dispatched. + */ + uint32_t dispatched; + + /** + * @brief This member contains the call count of the interrupt handler. + */ + volatile uint32_t call_count; + + /** + * @brief This member contains the interrupt vector which the test expects. + */ rtems_vector_number expected_vector; + + /** + * @brief This member contains the interrupt vector which the handler saw. + */ rtems_vector_number handled_vector; } BspSparcLeon3ValExtIrqRaise_Context; -static void BspSparcLeon3ValExtIrqRaise_Handler( void *arg ) +static BspSparcLeon3ValExtIrqRaise_Context + BspSparcLeon3ValExtIrqRaise_Instance; + +typedef BspSparcLeon3ValExtIrqRaise_Context Context; + +static void Handler( void *arg ) { - BspSparcLeon3ValExtIrqRaise_Context *ctx; + Context *ctx; ctx = arg; ctx->handled_vector = ctx->expected_vector; ++ctx->call_count; } -static rtems_status_code UnsafeRaiseExtendedInterrupt( - rtems_vector_number vector -) +static void UnsafeRaiseExtendedInterrupt( rtems_vector_number controller_line ) { rtems_interrupt_lock_context lock_context; - uint32_t bit; uint32_t ipend; irqamp *regs; regs = LEON3_IrqCtrl_Regs; - bit = 1U << vector; - - /* - * This deliberately uses an unsafe read-modify-write sequence to exercise - * the extended interrupt raise path in BSP-specific validation tests. - */ LEON3_IRQCTRL_ACQUIRE( &lock_context ); ipend = grlib_load_32( ®s->ipend ); - ipend |= bit; + ipend |= 1U << controller_line; grlib_store_32( ®s->ipend, ipend ); LEON3_IRQCTRL_RELEASE( &lock_context ); - - return RTEMS_SUCCESSFUL; } +static T_fixture BspSparcLeon3ValExtIrqRaise_Fixture = { + .setup = NULL, + .stop = NULL, + .teardown = NULL, + .scope = NULL, + .initial_context = &BspSparcLeon3ValExtIrqRaise_Instance +}; + /** - * @fn void T_case_body_BspSparcLeon3ValExtIrqRaise( void ) + * @brief Iterate through each interrupt vector whose bus line maps to an + * extended controller line and which has no interrupt handler installed. + * Get the attributes of the vector and try to raise it through the + * directive. Install an interrupt handler, enable the vector, raise the + * extended controller line through the pending register and wait for the + * handler. Clear and disable the vector and remove the handler. */ -T_TEST_CASE( BspSparcLeon3ValExtIrqRaise ) +static void BspSparcLeon3ValExtIrqRaise_Action_0( + BspSparcLeon3ValExtIrqRaise_Context *ctx +) { rtems_vector_number vector; - uint32_t tested_vectors = 0; - for ( - vector = BSP_INTERRUPT_VECTOR_MAX_STD + 1; - vector < BSP_INTERRUPT_VECTOR_COUNT; - ++vector - ) { - rtems_status_code sc; - rtems_interrupt_attributes attr; - bool pending_before; - bool pending_after; - rtems_interrupt_entry entry; - BspSparcLeon3ValExtIrqRaise_Context ctx; + for ( vector = 0; vector < BSP_INTERRUPT_VECTOR_COUNT; ++vector ) { + rtems_vector_number controller_line; + rtems_status_code sc; + rtems_interrupt_attributes attr; + bool pending_before; + bool pending_after; + rtems_interrupt_entry entry; if ( !bsp_interrupt_is_valid_vector( vector ) ) { continue; } + controller_line = leon3_irqmap_get_unchecked( vector ); + + if ( controller_line <= BSP_INTERRUPT_VECTOR_MAX_STD ) { + continue; + } + if ( HasInterruptVectorEntriesInstalled( vector ) ) { continue; } + ++ctx->tested_vectors; + ctx->tested_controller_lines |= 1U << controller_line; + attr = (rtems_interrupt_attributes) { 0 }; sc = rtems_interrupt_get_attributes( vector, &attr ); T_rsc_success( sc ); - T_false( attr.can_raise ); - T_false( attr.can_raise_on ); - T_true( attr.can_enable ); - T_true( attr.can_disable ); - T_true( attr.can_clear ); + if ( + !attr.can_raise && !attr.can_raise_on && attr.can_enable && + attr.can_disable && attr.can_clear + ) { + ++ctx->not_raisable; + } pending_before = true; sc = rtems_interrupt_is_pending( vector, &pending_before ); T_rsc_success( sc ); - /* The API must reject software raises of extended interrupt vectors. */ sc = rtems_interrupt_raise( vector ); - T_rsc( sc, RTEMS_UNSATISFIED ); pending_after = !pending_before; - sc = rtems_interrupt_is_pending( vector, &pending_after ); - T_rsc_success( sc ); - T_eq( pending_after, pending_before ); + (void) rtems_interrupt_is_pending( vector, &pending_after ); - ctx.call_count = 0; - ctx.expected_vector = vector; - ctx.handled_vector = UINT32_MAX; + if ( sc == RTEMS_UNSATISFIED && pending_after == pending_before ) { + ++ctx->raise_rejected; + } - rtems_interrupt_entry_initialize( - &entry, - BspSparcLeon3ValExtIrqRaise_Handler, - &ctx, - "Extended IRQ" + ctx->call_count = 0; + ctx->handled_vector = UINT32_MAX; + ctx->expected_vector = vector; + + rtems_interrupt_entry_initialize( &entry, Handler, ctx, "Extended IRQ" ); + sc = rtems_interrupt_entry_install( + vector, + RTEMS_INTERRUPT_UNIQUE, + &entry ); - - sc = rtems_interrupt_entry_install( vector, RTEMS_INTERRUPT_UNIQUE, &entry ); T_rsc_success( sc ); sc = rtems_interrupt_vector_enable( vector ); T_rsc_success( sc ); - /* - * Raise the extended interrupt vector using the unsafe test-only - * support operation. - */ - sc = UnsafeRaiseExtendedInterrupt( vector ); - T_rsc_success( sc ); + UnsafeRaiseExtendedInterrupt( controller_line ); - while ( ctx.call_count == 0 ) { + while ( ctx->call_count == 0 ) { /* Wait */ } - T_eq_u32( ctx.handled_vector, vector ); + if ( ctx->call_count == 1 && ctx->handled_vector == vector ) { + ++ctx->dispatched; + } sc = rtems_interrupt_clear( vector ); T_rsc_success( sc ); @@ -202,20 +264,46 @@ T_TEST_CASE( BspSparcLeon3ValExtIrqRaise ) sc = rtems_interrupt_entry_remove( vector, &entry ); T_rsc_success( sc ); - - pending_after = true; - sc = rtems_interrupt_is_pending( vector, &pending_after ); - T_rsc_success( sc ); - T_false( pending_after ); - - ++tested_vectors; } - /* Ensure that all extended vectors were effectively exercised. */ - T_eq( - tested_vectors, - BSP_INTERRUPT_VECTOR_MAX_EXT - BSP_INTERRUPT_VECTOR_MAX_STD - ); + /* + * Check that the test exercised each extended controller line. + */ + T_eq_u32( ctx->tested_controller_lines, 0xffff0000 ); + + /* + * Check that the attributes of each tested interrupt vector state that the + * vector can be enabled, disabled and cleared, and that it can neither be + * raised nor be raised on a processor. + */ + T_eq_u32( ctx->not_raisable, ctx->tested_vectors ); + + /* + * Check that the directive rejected the raise of each tested interrupt + * vector and that the pending state stayed unchanged. + */ + T_eq_u32( ctx->raise_rejected, ctx->tested_vectors ); + + /* + * Check that the pending extended controller line called the interrupt + * handler of each tested interrupt vector exactly once. + */ + T_eq_u32( ctx->dispatched, ctx->tested_vectors ); +} + +/** + * @fn void T_case_body_BspSparcLeon3ValExtIrqRaise( void ) + */ +T_TEST_CASE_FIXTURE( + BspSparcLeon3ValExtIrqRaise, + &BspSparcLeon3ValExtIrqRaise_Fixture +) +{ + BspSparcLeon3ValExtIrqRaise_Context *ctx; + + ctx = T_fixture_context(); + + BspSparcLeon3ValExtIrqRaise_Action_0( ctx ); } /** @} */