From 145becf0759d39d7779760af8f1e11d623997938 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 2 May 2014 15:33:23 +0200 Subject: score: Add SMP test message handler This handler can be used to test the inter-processor interrupt implementation. --- cpukit/score/include/rtems/score/smpimpl.h | 28 ++++ cpukit/score/src/smp.c | 8 ++ testsuites/smptests/Makefile.am | 1 + testsuites/smptests/configure.ac | 1 + testsuites/smptests/smpipi01/Makefile.am | 19 +++ testsuites/smptests/smpipi01/init.c | 207 +++++++++++++++++++++++++++++ testsuites/smptests/smpipi01/smpipi01.doc | 11 ++ testsuites/smptests/smpipi01/smpipi01.scn | 6 + 8 files changed, 281 insertions(+) create mode 100644 testsuites/smptests/smpipi01/Makefile.am create mode 100644 testsuites/smptests/smpipi01/init.c create mode 100644 testsuites/smptests/smpipi01/smpipi01.doc create mode 100644 testsuites/smptests/smpipi01/smpipi01.scn diff --git a/cpukit/score/include/rtems/score/smpimpl.h b/cpukit/score/include/rtems/score/smpimpl.h index 27cf188131..1868546996 100644 --- a/cpukit/score/include/rtems/score/smpimpl.h +++ b/cpukit/score/include/rtems/score/smpimpl.h @@ -43,6 +43,13 @@ extern "C" { */ #define SMP_MESSAGE_SHUTDOWN UINT32_C(0x1) +/** + * @brief SMP message to request a test handler invocation. + * + * @see _SMP_Send_message(). + */ +#define SMP_MESSAGE_TEST UINT32_C(0x2) + /** * @brief SMP fatal codes. */ @@ -101,6 +108,23 @@ static inline void _SMP_Fatal( SMP_Fatal_code code ) void _SMP_Start_multitasking_on_secondary_processor( void ) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE; +typedef void ( *SMP_Test_message_handler )( Per_CPU_Control *cpu_self ); + +extern SMP_Test_message_handler _SMP_Test_message_handler; + +/** + * @brief Sets the handler for test messages. + * + * This handler can be used to test the inter-processor interrupt + * implementation. + */ +static inline void _SMP_Set_test_message_handler( + SMP_Test_message_handler handler +) +{ + _SMP_Test_message_handler = handler; +} + /** * @brief Interrupt handler for inter-processor interrupts. */ @@ -121,6 +145,10 @@ static inline void _SMP_Inter_processor_interrupt_handler( void ) rtems_fatal( RTEMS_FATAL_SOURCE_SMP, SMP_FATAL_SHUTDOWN ); /* does not continue past here */ } + + if ( ( message & SMP_MESSAGE_TEST ) != 0 ) { + ( *_SMP_Test_message_handler )( cpu_self ); + } } } diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c index 34db46ad1e..3094fe31f8 100644 --- a/cpukit/score/src/smp.c +++ b/cpukit/score/src/smp.c @@ -166,3 +166,11 @@ void _SMP_Broadcast_message( uint32_t message ) } } } + +static void _SMP_Test_message_default_handler( Per_CPU_Control *cpu_self ) +{ + (void) cpu_self; +} + +SMP_Test_message_handler _SMP_Test_message_handler = + _SMP_Test_message_default_handler; diff --git a/testsuites/smptests/Makefile.am b/testsuites/smptests/Makefile.am index f16d39664d..d82503a17c 100644 --- a/testsuites/smptests/Makefile.am +++ b/testsuites/smptests/Makefile.am @@ -18,6 +18,7 @@ SUBDIRS += smpfatal04 SUBDIRS += smpfatal05 SUBDIRS += smpfatal07 SUBDIRS += smpfatal08 +SUBDIRS += smpipi01 SUBDIRS += smpload01 SUBDIRS += smplock01 SUBDIRS += smpmigration01 diff --git a/testsuites/smptests/configure.ac b/testsuites/smptests/configure.ac index e3857f1e0f..27f7f542b3 100644 --- a/testsuites/smptests/configure.ac +++ b/testsuites/smptests/configure.ac @@ -73,6 +73,7 @@ smpfatal04/Makefile smpfatal05/Makefile smpfatal07/Makefile smpfatal08/Makefile +smpipi01/Makefile smpload01/Makefile smplock01/Makefile smpmigration01/Makefile diff --git a/testsuites/smptests/smpipi01/Makefile.am b/testsuites/smptests/smpipi01/Makefile.am new file mode 100644 index 0000000000..a00f1076ca --- /dev/null +++ b/testsuites/smptests/smpipi01/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = smpipi01 +smpipi01_SOURCES = init.c + +dist_rtems_tests_DATA = smpipi01.scn smpipi01.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include + +LINK_OBJS = $(smpipi01_OBJECTS) +LINK_LIBS = $(smpipi01_LDLIBS) + +smpipi01$(EXEEXT): $(smpipi01_OBJECTS) $(smpipi01_DEPENDENCIES) + @rm -f smpipi01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/smptests/smpipi01/init.c b/testsuites/smptests/smpipi01/init.c new file mode 100644 index 0000000000..db0688c5ee --- /dev/null +++ b/testsuites/smptests/smpipi01/init.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include + +#include + +#include "tmacros.h" + +const char rtems_test_name[] = "SMPIPI 1"; + +#define CPU_COUNT 32 + +typedef struct { + uint32_t value; + uint32_t cache_line_separation[31]; +} test_counter; + +typedef struct { + test_counter counters[CPU_COUNT]; + uint32_t copy_counters[CPU_COUNT]; + SMP_barrier_Control barrier; + SMP_barrier_State main_barrier_state; + SMP_barrier_State worker_barrier_state; +} test_context; + +static test_context test_instance = { + .barrier = SMP_BARRIER_CONTROL_INITIALIZER, + .main_barrier_state = SMP_BARRIER_STATE_INITIALIZER, + .worker_barrier_state = SMP_BARRIER_STATE_INITIALIZER +}; + +static void barrier( + test_context *ctx, + SMP_barrier_State *state +) +{ + _SMP_barrier_Wait(&ctx->barrier, state, 2); +} + +static void barrier_handler(Per_CPU_Control *cpu_self) +{ + test_context *ctx = &test_instance; + uint32_t cpu_index_self = _Per_CPU_Get_index(cpu_self); + SMP_barrier_State *bs = &ctx->worker_barrier_state; + + ++ctx->counters[cpu_index_self].value; + + /* (A) */ + barrier(ctx, bs); + + /* (B) */ + barrier(ctx, bs); + + /* (C) */ + barrier(ctx, bs); +} + +static void test_send_message_while_processing_a_message( + test_context *ctx +) +{ + uint32_t cpu_count = rtems_get_processor_count(); + uint32_t cpu_index_self = rtems_get_current_processor(); + uint32_t cpu_index; + SMP_barrier_State *bs = &ctx->main_barrier_state; + + _SMP_Set_test_message_handler(barrier_handler); + + for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) { + if (cpu_index != cpu_index_self) { + _SMP_Send_message(cpu_index, SMP_MESSAGE_TEST); + + /* (A) */ + barrier(ctx, bs); + + rtems_test_assert(ctx->counters[cpu_index].value == 1); + _SMP_Send_message(cpu_index, SMP_MESSAGE_TEST); + + /* (B) */ + barrier(ctx, bs); + + rtems_test_assert(ctx->counters[cpu_index].value == 1); + + /* (C) */ + barrier(ctx, bs); + + /* (A) */ + barrier(ctx, bs); + + rtems_test_assert(ctx->counters[cpu_index].value == 2); + + /* (B) */ + barrier(ctx, bs); + + /* (C) */ + barrier(ctx, bs); + + ctx->counters[cpu_index].value = 0; + } + } +} + +static void counter_handler(Per_CPU_Control *cpu_self) +{ + test_context *ctx = &test_instance; + uint32_t cpu_index_self = _Per_CPU_Get_index(cpu_self); + + ++ctx->counters[cpu_index_self].value; +} + +static void test_send_message_flood( + test_context *ctx +) +{ + uint32_t cpu_count = rtems_get_processor_count(); + uint32_t cpu_index_self = rtems_get_current_processor(); + uint32_t cpu_index; + + _SMP_Set_test_message_handler(counter_handler); + + for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) { + uint32_t i; + + /* Wait 1us so that all outstanding messages have been processed */ + rtems_counter_delay_nanoseconds(1000000); + + for (i = 0; i < cpu_count; ++i) { + if (i != cpu_index) { + ctx->copy_counters[i] = ctx->counters[i].value; + } + } + + for (i = 0; i < 100000; ++i) { + _SMP_Send_message(cpu_index, SMP_MESSAGE_TEST); + } + + for (i = 0; i < cpu_count; ++i) { + if (i != cpu_index) { + rtems_test_assert(ctx->copy_counters[i] == ctx->counters[i].value); + } + } + } + + for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) { + printf( + "inter-processor interrupts for processor %" + PRIu32 "%s: %" PRIu32 "\n", + cpu_index, + cpu_index == cpu_index_self ? " (main)" : "", + ctx->counters[cpu_index].value + ); + } +} + +static void test(void) +{ + test_context *ctx = &test_instance; + + test_send_message_while_processing_a_message(ctx); + test_send_message_flood(ctx); +} + +static void Init(rtems_task_argument arg) +{ + TEST_BEGIN(); + + test(); + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_SMP_APPLICATION + +#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT + +#define CONFIGURE_MAXIMUM_TASKS 1 + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/smptests/smpipi01/smpipi01.doc b/testsuites/smptests/smpipi01/smpipi01.doc new file mode 100644 index 0000000000..72fe5d23e2 --- /dev/null +++ b/testsuites/smptests/smpipi01/smpipi01.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: smpipi01 + +directives: + + - _SMP_Send_message() + +concepts: + + - Ensure that inter-processor interrupts work as expected. diff --git a/testsuites/smptests/smpipi01/smpipi01.scn b/testsuites/smptests/smpipi01/smpipi01.scn new file mode 100644 index 0000000000..255e9519d9 --- /dev/null +++ b/testsuites/smptests/smpipi01/smpipi01.scn @@ -0,0 +1,6 @@ +*** BEGIN OF TEST SMPIPI 1 *** +inter-processor interrupts for processor 0: 12502 +inter-processor interrupts for processor 1: 12502 +inter-processor interrupts for processor 2: 12502 +inter-processor interrupts for processor 3 (main): 99987 +*** END OF TEST SMPIPI 1 *** -- cgit v1.2.3