Add test which ensures that a cache invalidate executed by one processor is seen by another processor --- testsuites/sptests/spcache01/init.c | 209 +++++++++++++++++++++++++++++++---- 1 Datei geändert, 185 Zeilen hinzugefügt(+), 24 Zeilen entfernt(-)
diff --git a/testsuites/sptests/spcache01/init.c b/testsuites/sptests/spcache01/init.c index 303f7f6..99f5ec4 100644 --- a/testsuites/sptests/spcache01/init.c +++ b/testsuites/sptests/spcache01/init.c @@ -21,6 +21,8 @@ #include <rtems.h> #include <rtems/counter.h> +#include <rtems/score/smpbarrier.h> +#include <rtems/rtems/smp.h> #define TESTS_USE_PRINTF #include "tmacros.h" @@ -35,7 +37,145 @@ const char rtems_test_name[] = "SPCACHE 1"; #define I512() I64(); I64(); I64(); I64(); I64(); I64(); I64(); I64() -CPU_STRUCTURE_ALIGNMENT static int data[1024]; +#if defined( RTEMS_SMP ) + #define TEST_SMP_TASK_COUNT 1 +#else + #define TEST_SMP_TASK_COUNT 0 +#endif /* defined( RTEMS_SMP ) */ + +#define TEST_SMP_PROCESSOR_COUNT 2 + +#define TASK_PRIORITY 1 + +typedef struct { +#if defined( RTEMS_SMP ) + SMP_barrier_Control barrier; +#endif /* defined( RTEMS_SMP ) */ + CPU_STRUCTURE_ALIGNMENT int data[1024]; +} test_context; + +static test_context test_instance; + +#if defined( RTEMS_SMP ) +static rtems_task test_multiprocessor_extensions_task( rtems_task_argument arg ) +{ + SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER; + rtems_interrupt_lock lock; + rtems_interrupt_lock_context lock_context; + int *data = &test_instance.data[0]; + + (void)arg; + + + rtems_interrupt_lock_initialize(&lock, "test"); + rtems_interrupt_lock_acquire(&lock, &lock_context); + + /* Wait for the other task to start it's initialization */ + _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT); + + /* Make sure we don't have the cache line cached */ + rtems_cache_invalidate_multiple_data_lines( + &data[0], + sizeof(data[0]) + ); + + /* Wait for the other task to complete it's initialization */ + _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT); + + /* Wait for the other task to complete preparations for the invalidation */ + _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT); + + /* Now the other task should also get the cache line invalidated */ + rtems_cache_invalidate_multiple_data_lines( + &data[0], + sizeof(data[0]) + ); + + /* Signal that we have completed the invalidation */ + _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT); + + rtems_interrupt_lock_release(&lock, &lock_context); + rtems_interrupt_lock_destroy(&lock); + + rtems_task_delete(RTEMS_SELF); +} +#endif /* defined( RTEMS_SMP ) */ + +static void test_multiprocessor_extensions( const bool write_through ) +{ +#if defined( RTEMS_SMP ) + if( ( ! write_through ) && ( rtems_get_processor_count() > 1 ) ) { + rtems_interrupt_lock lock; + rtems_interrupt_lock_context lock_context; + SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER; + rtems_id id_work1 = RTEMS_ID_NONE; + int *tdata = &test_instance.data[0]; + volatile int *vdata = &test_instance.data[0]; + rtems_status_code sc; + const int PATTERN = 0x89ABCDEF; + + printf("test for multiprocessor extensions handling\n"); + + _SMP_barrier_Control_initialize( &test_instance.barrier ); + + rtems_interrupt_lock_initialize(&lock, "test"); + rtems_interrupt_lock_acquire(&lock, &lock_context); + + /* Create and start another task for our test. As we are under SMP conditions, + * this new task will be operating on another processor */ + sc = rtems_task_create( + rtems_build_name('W', 'R', 'K', '1'), + TASK_PRIORITY, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &id_work1 + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(id_work1, test_multiprocessor_extensions_task, 0); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + /* Permit the other task to start it's initialization */ + _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT); + + /* Make sure we don't have the cache line cached */ + rtems_cache_invalidate_multiple_data_lines( + &tdata[0], + sizeof(tdata[0]) + ); + + /* Wait for the other task to complete it's initialization */ + _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT); + + /* Initialize */ + vdata[0] = PATTERN; + + /* Flush initialized cache line to RAM */ + rtems_cache_flush_multiple_data_lines( + &tdata[0], + sizeof(tdata[0]) + ); + + /* Modify cache line in cache only */ + vdata[0] = ~PATTERN; + + /* Have the other task invalidate the cache line */ + _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT); + + /* Wait for the complation of the invalidation by the other task */ + _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT); + + /* The other task has invalidated the cache, thus we should read what was flushed to RAM */ + rtems_test_assert(vdata[0] == PATTERN); + + rtems_interrupt_lock_release(&lock, &lock_context); + rtems_interrupt_lock_destroy(&lock); + + printf("test for multiprocessor extensions passed\n"); + } +#endif /* defined( RTEMS_SMP ) */ +} static void test_misalignment( const bool write_through ) { @@ -43,12 +183,20 @@ static void test_misalignment( const bool write_through ) rtems_interrupt_lock lock; rtems_interrupt_lock_context lock_context; const uint32_t LINE_SIZE = rtems_cache_get_data_line_size(); - volatile int *vdata = &data[0]; /* Verification start address */ - int *tdata = &data[LINE_SIZE / sizeof(data[0])]; /* test start address (first word in second cache line) */ + int *data = &data[0]; + /* Verification start address */ + volatile int *vdata = data; + /* test start address (first word in second cache line) */ + int *tdata = &data[LINE_SIZE / sizeof(data[0])]; int tcount = 1; /* Words to be tested */ - size_t tdata_bytes = tcount * sizeof(data[0]); /* Bytes to be tested */ - size_t vdata_bytes = LINE_SIZE; /* Bytes expected to be affected by cache maintenance */ - int vcount = (vdata_bytes / sizeof(data[0])) + (2 * LINE_SIZE / sizeof(data[0])); /* Words to be verified (Words affected + 2 adjacent cache lines) */ + /* Bytes to be tested */ + size_t tdata_bytes = tcount * sizeof(data[0]); + /* Bytes expected to be affected by cache maintenance */ + size_t vdata_bytes = LINE_SIZE; + /* Words to be verified (Words affected + 2 adjacent cache lines) */ + int vcount = + (vdata_bytes / sizeof(data[0])) + + (2 * LINE_SIZE / sizeof(data[0])); int i; int end; @@ -174,7 +322,8 @@ static void test_misalignment( const bool write_through ) * The modified line shall get invalidated/flushed entirely, * adjacent cache lines shall remain unchanged. */ - tdata = &data[(LINE_SIZE / sizeof(data[0])) + ((LINE_SIZE / sizeof(data[0])) -1)]; + tdata = &data[(LINE_SIZE / sizeof(data[0])) + + ((LINE_SIZE / sizeof(data[0])) -1)]; for (i = 0; i < vcount; ++i) { vdata[i] = i; @@ -232,10 +381,12 @@ static void test_misalignment( const bool write_through ) * The modified lines shall get invalidated/flushed entirely, * adjacent cache lines shall remain unchanged. */ - tdata = &data[(LINE_SIZE / sizeof(data[0])) + ((LINE_SIZE / sizeof(data[0])) -1)]; + tdata = &data[(LINE_SIZE / sizeof(data[0])) + + ((LINE_SIZE / sizeof(data[0])) -1)]; vdata_bytes = LINE_SIZE * 2; tcount = 2; - vcount = (vdata_bytes / sizeof(data[0])) + (2 * LINE_SIZE / sizeof(data[0])); + vcount = (vdata_bytes / sizeof(data[0])) + + (2 * LINE_SIZE / sizeof(data[0])); tdata_bytes = tcount * sizeof(data[0]); for (i = 0; i < vcount; ++i) { @@ -292,13 +443,14 @@ static void test_misalignment( const bool write_through ) rtems_interrupt_lock_destroy(&lock); printf( - "data cache operations with misaligned addresses passed the test (%s cache detected)\n", - write_through ? "write-through" : "copy-back" + "data cache operations with misaligned addresses passed the test " + "(%s cache detected)\n", + write_through ? "write-through" : "copy-back" ); } else { printf( - "skip data cache flush and invalidate test with misaligned addresses" - " due to cache line size of zero\n" + "skip data cache flush and invalidate test with " + "misaligned addresses due to cache line size of zero\n" ); } } @@ -309,7 +461,8 @@ static bool test_data_flush_and_invalidate(void) if (rtems_cache_get_data_line_size() > 0) { rtems_interrupt_lock lock; rtems_interrupt_lock_context lock_context; - volatile int *vdata = &data[0]; + int *data = &test_instance.data[0]; + volatile int *vdata = data; int n = 32; int i; size_t data_size = n * sizeof(data[0]); @@ -397,7 +550,8 @@ static uint64_t load(void) rtems_counter_ticks b; rtems_counter_ticks d; size_t i; - volatile int *vdata = &data[0]; + int *data = &test_instance.data[0]; + volatile int *vdata = data; a = rtems_counter_read(); for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) { @@ -416,10 +570,10 @@ static uint64_t store(void) rtems_counter_ticks b; rtems_counter_ticks d; size_t i; - volatile int *vdata = &data[0]; + volatile int *vdata = &test_instance.data[0]; a = rtems_counter_read(); - for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) { + for (i = 0; i < RTEMS_ARRAY_SIZE(test_instance.data); ++i) { vdata[i] = 0; } b = rtems_counter_read(); @@ -433,7 +587,8 @@ static void test_timing(void) { rtems_interrupt_lock lock; rtems_interrupt_lock_context lock_context; - size_t data_size = sizeof(data); + int *data = &test_instance.data[0]; + size_t data_size = sizeof(test_instance.data); uint64_t d[3]; uint32_t cache_level; size_t cache_size; @@ -483,7 +638,7 @@ static void test_timing(void) d[0] = load(); d[1] = load(); - rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data)); + rtems_cache_flush_multiple_data_lines(data, sizeof(test_instance.data)); d[2] = load(); rtems_interrupt_lock_release(&lock, &lock_context); @@ -503,7 +658,7 @@ static void test_timing(void) d[0] = load(); d[1] = load(); - rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data)); + rtems_cache_invalidate_multiple_data_lines(data, sizeof(test_instance.data)); d[2] = load(); rtems_interrupt_lock_release(&lock, &lock_context); @@ -543,7 +698,7 @@ static void test_timing(void) d[0] = store(); d[1] = store(); - rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data)); + rtems_cache_flush_multiple_data_lines(data, sizeof(test_instance.data)); d[2] = store(); rtems_interrupt_lock_release(&lock, &lock_context); @@ -563,7 +718,7 @@ static void test_timing(void) d[0] = store(); d[1] = store(); - rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data)); + rtems_cache_invalidate_multiple_data_lines(data, sizeof(test_instance.data)); d[2] = store(); rtems_interrupt_lock_release(&lock, &lock_context); @@ -647,18 +802,24 @@ static void Init(rtems_task_argument arg) write_through = test_data_flush_and_invalidate(); test_misalignment( write_through ); test_timing(); + test_multiprocessor_extensions(write_through); TEST_END(); rtems_test_exit(0); } -#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#if defined( RTEMS_SMP ) + #define CONFIGURE_SMP_APPLICATION + #define CONFIGURE_SMP_MAXIMUM_PROCESSORS 32 +#endif /* defined( RTEMS_SMP ) */ +#define CONFIGURE_INIT_TASK_PRIORITY TASK_PRIORITY +#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER #define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM -#define CONFIGURE_MAXIMUM_TASKS 1 +#define CONFIGURE_MAXIMUM_TASKS (1 + TEST_SMP_TASK_COUNT) #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION -- 1.7.10.4 _______________________________________________ rtems-devel mailing list rtems-devel@rtems.org http://www.rtems.org/mailman/listinfo/rtems-devel