forked from Imagelibrary/rtems
score: Add SMP test message handler
This handler can be used to test the inter-processor interrupt implementation.
This commit is contained in:
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -18,6 +18,7 @@ SUBDIRS += smpfatal04
|
||||
SUBDIRS += smpfatal05
|
||||
SUBDIRS += smpfatal07
|
||||
SUBDIRS += smpfatal08
|
||||
SUBDIRS += smpipi01
|
||||
SUBDIRS += smpload01
|
||||
SUBDIRS += smplock01
|
||||
SUBDIRS += smpmigration01
|
||||
|
||||
@@ -73,6 +73,7 @@ smpfatal04/Makefile
|
||||
smpfatal05/Makefile
|
||||
smpfatal07/Makefile
|
||||
smpfatal08/Makefile
|
||||
smpipi01/Makefile
|
||||
smpload01/Makefile
|
||||
smplock01/Makefile
|
||||
smpmigration01/Makefile
|
||||
|
||||
19
testsuites/smptests/smpipi01/Makefile.am
Normal file
19
testsuites/smptests/smpipi01/Makefile.am
Normal file
@@ -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
|
||||
207
testsuites/smptests/smpipi01/init.c
Normal file
207
testsuites/smptests/smpipi01/init.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <rtems/score/smpimpl.h>
|
||||
#include <rtems/score/smpbarrier.h>
|
||||
#include <rtems/counter.h>
|
||||
#include <rtems.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#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 <rtems/confdefs.h>
|
||||
11
testsuites/smptests/smpipi01/smpipi01.doc
Normal file
11
testsuites/smptests/smpipi01/smpipi01.doc
Normal file
@@ -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.
|
||||
6
testsuites/smptests/smpipi01/smpipi01.scn
Normal file
6
testsuites/smptests/smpipi01/smpipi01.scn
Normal file
@@ -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 ***
|
||||
Reference in New Issue
Block a user