[9a9ab85] | 1 | /* |
---|
| 2 | * Copyright (c) 2014 Aeroflex Gaisler AB. All rights reserved. |
---|
[9b91c84] | 3 | * Copyright (c) 2017 embedded brains GmbH. |
---|
[9a9ab85] | 4 | * |
---|
| 5 | * The license and distribution terms for this file may be |
---|
| 6 | * found in the file LICENSE in this distribution or at |
---|
| 7 | * http://www.rtems.org/license/LICENSE. |
---|
| 8 | */ |
---|
| 9 | |
---|
| 10 | #ifdef HAVE_CONFIG_H |
---|
| 11 | #include "config.h" |
---|
| 12 | #endif |
---|
| 13 | |
---|
| 14 | #include <rtems/score/atomic.h> |
---|
| 15 | #include <rtems/score/smpbarrier.h> |
---|
[26c142e5] | 16 | #include <rtems/score/smpimpl.h> |
---|
[9a9ab85] | 17 | #include <rtems.h> |
---|
| 18 | #include <limits.h> |
---|
[9b91c84] | 19 | #include <setjmp.h> |
---|
[9a9ab85] | 20 | #include <string.h> |
---|
| 21 | |
---|
| 22 | #include "tmacros.h" |
---|
| 23 | |
---|
| 24 | const char rtems_test_name[] = "SMPCACHE 1"; |
---|
| 25 | |
---|
[6e1206a] | 26 | CPU_STRUCTURE_ALIGNMENT static int data_to_flush[1024]; |
---|
| 27 | |
---|
[9a9ab85] | 28 | #define CPU_COUNT 32 |
---|
| 29 | |
---|
| 30 | #define WORKER_PRIORITY 100 |
---|
| 31 | |
---|
| 32 | typedef struct { |
---|
| 33 | SMP_barrier_Control barrier; |
---|
| 34 | uint32_t count[CPU_COUNT]; |
---|
[9b91c84] | 35 | bool do_longjmp[CPU_COUNT]; |
---|
| 36 | jmp_buf instruction_invalidate_return_context[CPU_COUNT]; |
---|
[9a9ab85] | 37 | } test_context; |
---|
| 38 | |
---|
| 39 | static test_context ctx = { |
---|
| 40 | .barrier = SMP_BARRIER_CONTROL_INITIALIZER, |
---|
| 41 | }; |
---|
| 42 | |
---|
[6e1206a] | 43 | static void function_to_flush( void ) |
---|
| 44 | { |
---|
| 45 | /* Does nothing. Used to give a pointer to instruction address space. */ |
---|
| 46 | } |
---|
| 47 | |
---|
[b1b5ddf0] | 48 | static void test_action( void *arg ) |
---|
[9a9ab85] | 49 | { |
---|
[26c142e5] | 50 | rtems_test_assert(arg == &ctx); |
---|
[9a9ab85] | 51 | |
---|
| 52 | ctx.count[rtems_get_current_processor()]++; |
---|
| 53 | } |
---|
| 54 | |
---|
[b1b5ddf0] | 55 | typedef void ( *test_case )( |
---|
| 56 | size_t set_size, |
---|
| 57 | const cpu_set_t *cpu_set, |
---|
| 58 | SMP_barrier_State *bs |
---|
| 59 | ); |
---|
| 60 | |
---|
| 61 | static void test_cache_flush_multiple_data_lines( |
---|
| 62 | size_t set_size, |
---|
| 63 | const cpu_set_t *cpu_set, |
---|
| 64 | SMP_barrier_State *bs |
---|
| 65 | ) |
---|
[9a9ab85] | 66 | { |
---|
[6e1206a] | 67 | rtems_cache_flush_multiple_data_lines_processor_set( &data_to_flush, |
---|
| 68 | sizeof(data_to_flush), set_size, cpu_set ); |
---|
[b1b5ddf0] | 69 | } |
---|
| 70 | |
---|
| 71 | static void test_cache_invalidate_multiple_data_lines( |
---|
| 72 | size_t set_size, |
---|
| 73 | const cpu_set_t *cpu_set, |
---|
| 74 | SMP_barrier_State *bs |
---|
| 75 | ) |
---|
| 76 | { |
---|
[6e1206a] | 77 | rtems_cache_invalidate_multiple_data_lines_processor_set( &data_to_flush, |
---|
| 78 | sizeof(data_to_flush), set_size, cpu_set ); |
---|
[9a9ab85] | 79 | } |
---|
| 80 | |
---|
[b1b5ddf0] | 81 | static void test_cache_flush_entire_data( |
---|
| 82 | size_t set_size, |
---|
| 83 | const cpu_set_t *cpu_set, |
---|
| 84 | SMP_barrier_State *bs |
---|
| 85 | ) |
---|
[9a9ab85] | 86 | { |
---|
[b1b5ddf0] | 87 | rtems_cache_flush_entire_data_processor_set( set_size, cpu_set ); |
---|
[9a9ab85] | 88 | } |
---|
| 89 | |
---|
[b1b5ddf0] | 90 | static void test_cache_invalidate_entire_instruction( |
---|
| 91 | size_t set_size, |
---|
| 92 | const cpu_set_t *cpu_set, |
---|
| 93 | SMP_barrier_State *bs |
---|
| 94 | ) |
---|
[9a9ab85] | 95 | { |
---|
[b1b5ddf0] | 96 | rtems_cache_invalidate_entire_instruction(); |
---|
[9a9ab85] | 97 | } |
---|
| 98 | |
---|
[b1b5ddf0] | 99 | static void test_cache_invalidate_multiple_instruction_lines( |
---|
| 100 | size_t set_size, |
---|
| 101 | const cpu_set_t *cpu_set, |
---|
| 102 | SMP_barrier_State *bs |
---|
| 103 | ) |
---|
[9a9ab85] | 104 | { |
---|
[9b91c84] | 105 | uint32_t self = rtems_get_current_processor(); |
---|
| 106 | |
---|
| 107 | ctx.do_longjmp[self] = true; |
---|
| 108 | |
---|
| 109 | if (setjmp(ctx.instruction_invalidate_return_context[self]) == 0) { |
---|
| 110 | rtems_cache_invalidate_multiple_instruction_lines( &function_to_flush, |
---|
| 111 | 4 /* arbitrary size */ ); |
---|
| 112 | } |
---|
| 113 | |
---|
| 114 | ctx.do_longjmp[self] = false; |
---|
| 115 | } |
---|
| 116 | |
---|
| 117 | static void barrier( SMP_barrier_State *bs ) |
---|
| 118 | { |
---|
| 119 | _SMP_barrier_Wait( &ctx.barrier, bs, rtems_get_processor_count() ); |
---|
| 120 | } |
---|
| 121 | |
---|
| 122 | static void broadcast_test_init( void ) |
---|
| 123 | { |
---|
| 124 | ctx.count[rtems_get_current_processor()] = 0; |
---|
[9a9ab85] | 125 | } |
---|
| 126 | |
---|
[9b91c84] | 127 | static void broadcast_test_body( |
---|
[b1b5ddf0] | 128 | size_t set_size, |
---|
| 129 | const cpu_set_t *cpu_set, |
---|
| 130 | SMP_barrier_State *bs |
---|
| 131 | ) |
---|
[9a9ab85] | 132 | { |
---|
[b1b5ddf0] | 133 | _SMP_Multicast_action( set_size, cpu_set, test_action, &ctx ); |
---|
[9b91c84] | 134 | } |
---|
[9a9ab85] | 135 | |
---|
[9b91c84] | 136 | static void broadcast_test_fini( void ) |
---|
| 137 | { |
---|
| 138 | rtems_test_assert( |
---|
| 139 | ctx.count[rtems_get_current_processor()] == rtems_get_processor_count() |
---|
| 140 | ); |
---|
[9a9ab85] | 141 | } |
---|
| 142 | |
---|
[b1b5ddf0] | 143 | static test_case test_cases[] = { |
---|
| 144 | test_cache_flush_multiple_data_lines, |
---|
| 145 | test_cache_invalidate_multiple_data_lines, |
---|
| 146 | test_cache_flush_entire_data, |
---|
| 147 | test_cache_invalidate_entire_instruction, |
---|
| 148 | test_cache_invalidate_multiple_instruction_lines, |
---|
[9b91c84] | 149 | broadcast_test_body |
---|
[b1b5ddf0] | 150 | }; |
---|
[9a9ab85] | 151 | |
---|
[b1b5ddf0] | 152 | static void call_tests( size_t set_size, |
---|
| 153 | const cpu_set_t *cpu_set, SMP_barrier_State *bs ) |
---|
| 154 | { |
---|
| 155 | size_t i; |
---|
| 156 | |
---|
[9b91c84] | 157 | broadcast_test_init(); |
---|
| 158 | |
---|
[b1b5ddf0] | 159 | for (i = 0; i < RTEMS_ARRAY_SIZE( test_cases ); ++i) { |
---|
[9b91c84] | 160 | barrier( bs ); |
---|
| 161 | ( *test_cases[ i ] )( set_size, cpu_set, bs ); |
---|
| 162 | barrier( bs ); |
---|
[b1b5ddf0] | 163 | } |
---|
[9b91c84] | 164 | |
---|
| 165 | broadcast_test_fini(); |
---|
[9a9ab85] | 166 | } |
---|
| 167 | |
---|
[b1b5ddf0] | 168 | static void call_tests_isr_disabled( size_t set_size, |
---|
| 169 | const cpu_set_t *cpu_set, SMP_barrier_State *bs ) |
---|
[9a9ab85] | 170 | { |
---|
[b1b5ddf0] | 171 | size_t i; |
---|
[9a9ab85] | 172 | |
---|
[9b91c84] | 173 | broadcast_test_init(); |
---|
| 174 | |
---|
[b1b5ddf0] | 175 | for (i = 0; i < RTEMS_ARRAY_SIZE( test_cases ); ++i) { |
---|
| 176 | ISR_Level isr_level; |
---|
[9a9ab85] | 177 | |
---|
[4b04cb61] | 178 | _ISR_Local_disable( isr_level ); |
---|
[9b91c84] | 179 | barrier( bs ); |
---|
| 180 | ( *test_cases[ i ] )( set_size, cpu_set, bs ); |
---|
[4b04cb61] | 181 | _ISR_Local_enable( isr_level ); |
---|
[9b91c84] | 182 | barrier( bs ); |
---|
[b1b5ddf0] | 183 | } |
---|
[9b91c84] | 184 | |
---|
| 185 | broadcast_test_fini(); |
---|
[b1b5ddf0] | 186 | } |
---|
[9a9ab85] | 187 | |
---|
[dab902d5] | 188 | static void call_tests_with_thread_dispatch_disabled( size_t set_size, |
---|
[b1b5ddf0] | 189 | const cpu_set_t *cpu_set, SMP_barrier_State *bs ) |
---|
| 190 | { |
---|
| 191 | size_t i; |
---|
| 192 | |
---|
[9b91c84] | 193 | broadcast_test_init(); |
---|
| 194 | |
---|
[b1b5ddf0] | 195 | for (i = 0; i < RTEMS_ARRAY_SIZE( test_cases ); ++i) { |
---|
[dab902d5] | 196 | Per_CPU_Control *cpu_self; |
---|
| 197 | |
---|
| 198 | cpu_self = _Thread_Dispatch_disable(); |
---|
[9b91c84] | 199 | barrier( bs ); |
---|
| 200 | ( *test_cases[ i ] )( set_size, cpu_set, bs ); |
---|
| 201 | barrier( bs ); |
---|
[dab902d5] | 202 | _Thread_Dispatch_enable( cpu_self ); |
---|
[b1b5ddf0] | 203 | } |
---|
[9b91c84] | 204 | |
---|
| 205 | broadcast_test_fini(); |
---|
[9a9ab85] | 206 | } |
---|
| 207 | |
---|
| 208 | static void cmlog( const char* str ) |
---|
| 209 | { |
---|
| 210 | if ( rtems_get_current_processor() == 0 ) |
---|
| 211 | printf( "%s", str ); |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | static void all_tests( void ) |
---|
| 215 | { |
---|
| 216 | uint32_t cpu_count = rtems_get_processor_count(); |
---|
| 217 | size_t set_size = CPU_ALLOC_SIZE( rtems_get_processor_count() ); |
---|
| 218 | cpu_set_t *cpu_set = CPU_ALLOC( rtems_get_processor_count() ); |
---|
| 219 | SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER; |
---|
| 220 | |
---|
| 221 | /* Send message to all available CPUs */ |
---|
| 222 | CPU_FILL_S( set_size, cpu_set ); |
---|
| 223 | |
---|
[b1b5ddf0] | 224 | /* Call test cases */ |
---|
| 225 | cmlog( "Calling test cases. " ); |
---|
| 226 | call_tests( set_size, cpu_set, &bs ); |
---|
[9a9ab85] | 227 | cmlog( "Done!\n"); |
---|
| 228 | |
---|
[b1b5ddf0] | 229 | /* Call test cases with ISR disabled */ |
---|
| 230 | cmlog( "Calling test cases with ISR disabled. " ); |
---|
| 231 | call_tests_isr_disabled( set_size, cpu_set, &bs ); |
---|
[9a9ab85] | 232 | cmlog( "Done!\n" ); |
---|
| 233 | |
---|
[dab902d5] | 234 | /* Call test cases with thread dispatch disabled */ |
---|
| 235 | cmlog( "Calling test cases with thread_dispatch_disabled. "); |
---|
| 236 | call_tests_with_thread_dispatch_disabled( set_size, cpu_set, &bs ); |
---|
[9a9ab85] | 237 | cmlog( "Done!\n"); |
---|
| 238 | |
---|
| 239 | /* Done. Free up memory. */ |
---|
| 240 | _SMP_barrier_Wait( &ctx.barrier, &bs, cpu_count); |
---|
| 241 | CPU_FREE( cpu_set ); |
---|
| 242 | } |
---|
| 243 | |
---|
| 244 | static void worker_task(rtems_task_argument arg) |
---|
| 245 | { |
---|
| 246 | rtems_status_code sc; |
---|
| 247 | |
---|
| 248 | all_tests(); |
---|
| 249 | |
---|
| 250 | sc = rtems_task_suspend(RTEMS_SELF); |
---|
| 251 | rtems_test_assert(sc == RTEMS_SUCCESSFUL); |
---|
| 252 | } |
---|
| 253 | |
---|
| 254 | static void test_smp_cache_manager( void ) |
---|
| 255 | { |
---|
| 256 | rtems_status_code sc; |
---|
| 257 | size_t worker_index; |
---|
| 258 | uint32_t cpu_count = rtems_get_processor_count(); |
---|
| 259 | |
---|
| 260 | for (worker_index = 1; worker_index < cpu_count; ++worker_index) { |
---|
| 261 | rtems_id worker_id; |
---|
| 262 | |
---|
| 263 | sc = rtems_task_create( |
---|
| 264 | rtems_build_name('W', 'R', 'K', '0'+worker_index), |
---|
| 265 | WORKER_PRIORITY, |
---|
| 266 | RTEMS_MINIMUM_STACK_SIZE, |
---|
| 267 | RTEMS_DEFAULT_MODES, |
---|
| 268 | RTEMS_DEFAULT_ATTRIBUTES, |
---|
| 269 | &worker_id |
---|
| 270 | ); |
---|
| 271 | rtems_test_assert( sc == RTEMS_SUCCESSFUL ); |
---|
| 272 | |
---|
| 273 | sc = rtems_task_start( worker_id, worker_task, 0 ); |
---|
| 274 | rtems_test_assert( sc == RTEMS_SUCCESSFUL ); |
---|
| 275 | } |
---|
| 276 | |
---|
| 277 | all_tests(); |
---|
| 278 | } |
---|
| 279 | |
---|
| 280 | |
---|
| 281 | static void Init(rtems_task_argument arg) |
---|
| 282 | { |
---|
| 283 | TEST_BEGIN(); |
---|
| 284 | |
---|
| 285 | test_smp_cache_manager(); |
---|
| 286 | |
---|
| 287 | TEST_END(); |
---|
| 288 | rtems_test_exit(0); |
---|
| 289 | } |
---|
| 290 | |
---|
[9b91c84] | 291 | static void fatal_extension( |
---|
| 292 | rtems_fatal_source source, |
---|
| 293 | bool always_set_to_false, |
---|
| 294 | rtems_fatal_code error |
---|
| 295 | ) |
---|
| 296 | { |
---|
| 297 | uint32_t self = rtems_get_current_processor(); |
---|
| 298 | |
---|
| 299 | if (source == RTEMS_FATAL_SOURCE_EXCEPTION && ctx.do_longjmp[self]) { |
---|
| 300 | _ISR_Set_level(0); |
---|
| 301 | longjmp(ctx.instruction_invalidate_return_context[self], 1); |
---|
| 302 | } |
---|
| 303 | } |
---|
| 304 | |
---|
[9a9ab85] | 305 | #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER |
---|
| 306 | #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER |
---|
| 307 | |
---|
[54835ae] | 308 | #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT |
---|
[9a9ab85] | 309 | |
---|
| 310 | #define CONFIGURE_MAXIMUM_TASKS CPU_COUNT |
---|
| 311 | |
---|
| 312 | #define CONFIGURE_MAXIMUM_TIMERS 1 |
---|
| 313 | |
---|
[9b91c84] | 314 | #define CONFIGURE_INITIAL_EXTENSIONS \ |
---|
| 315 | { .fatal = fatal_extension }, \ |
---|
| 316 | RTEMS_TEST_INITIAL_EXTENSION |
---|
[9a9ab85] | 317 | |
---|
| 318 | #define CONFIGURE_RTEMS_INIT_TASKS_TABLE |
---|
| 319 | |
---|
| 320 | #define CONFIGURE_INIT |
---|
| 321 | |
---|
| 322 | #include <rtems/confdefs.h> |
---|