diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2014-02-18 13:40:39 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2014-03-06 09:43:57 +0100 |
commit | 7336be9d78266adfb540170e5105caf8eb003d2f (patch) | |
tree | 5dc7ab7a5c3c33c7e007a8e8e48cb1167187b0ca /cpukit/score/src | |
parent | bsp/leon3: Unmask IPI only on secondary processor (diff) | |
download | rtems-7336be9d78266adfb540170e5105caf8eb003d2f.tar.bz2 |
score: SMP initialization and shutdown changes
Rename _SMP_Request_other_cores_to_perform_first_context_switch() into
_SMP_Request_start_multitasking() since this requests now a multitasking
start on all configured and available processors. The name corresponds
_Thread_Start_multitasking() and
_SMP_Start_multitasking_on_secondary_processor() actions issued in
response to this request. Move in source file to right place.
Rename PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING into
PER_CPU_STATE_READY_TO_START_MULTITASKING.
Rename PER_CPU_STATE_BEGIN_MULTITASKING into
PER_CPU_STATE_REQUEST_START_MULTITASKING.
Rename _SMP_Request_other_cores_to_shutdown() into
_SMP_Request_shutdown().
Add a per-CPU state lock to protect all changes. This was necessary to
offer a controlled shutdown of the system (atomic read/writes alone are
not sufficient for this kind of synchronization).
Add documentation for Per_CPU_State.
Delete debug output.
New tests smptests/smpfatal01 and smptests/smpfatal02.
Diffstat (limited to 'cpukit/score/src')
-rw-r--r-- | cpukit/score/src/interr.c | 2 | ||||
-rw-r--r-- | cpukit/score/src/percpu.c | 158 | ||||
-rw-r--r-- | cpukit/score/src/smp.c | 77 | ||||
-rw-r--r-- | cpukit/score/src/threadstartmultitasking.c | 2 |
4 files changed, 169 insertions, 70 deletions
diff --git a/cpukit/score/src/interr.c b/cpukit/score/src/interr.c index c2a9fbe00f..11578a6101 100644 --- a/cpukit/score/src/interr.c +++ b/cpukit/score/src/interr.c @@ -39,7 +39,7 @@ void _Terminate( _ISR_Disable_without_giant( level ); (void) level; - _SMP_Request_other_cores_to_shutdown(); + _SMP_Request_shutdown(); _User_extensions_Fatal( the_source, is_internal, the_error ); diff --git a/cpukit/score/src/percpu.c b/cpukit/score/src/percpu.c index c68f378d1a..3a7a84518e 100644 --- a/cpukit/score/src/percpu.c +++ b/cpukit/score/src/percpu.c @@ -19,26 +19,156 @@ #endif #include <rtems/score/percpu.h> +#include <rtems/score/assert.h> +#include <rtems/score/smpimpl.h> +#include <rtems/config.h> +#include <rtems/fatal.h> #if defined(RTEMS_SMP) - void _Per_CPU_Change_state( - Per_CPU_Control *per_cpu, - Per_CPU_State new_state - ) - { - per_cpu->state = new_state; - _CPU_SMP_Processor_event_broadcast(); + +static SMP_lock_Control _Per_CPU_State_lock = SMP_LOCK_INITIALIZER; + +static ISR_Level _Per_CPU_State_acquire( void ) +{ + ISR_Level level; + + _SMP_lock_ISR_disable_and_acquire( &_Per_CPU_State_lock, level ); + + return level; +} + +static void _Per_CPU_State_release( ISR_Level level ) +{ + _SMP_lock_Release_and_ISR_enable( &_Per_CPU_State_lock, level ); +} + +static void _Per_CPU_State_busy_wait( + const Per_CPU_Control *per_cpu, + Per_CPU_State new_state +) +{ + Per_CPU_State state = per_cpu->state; + + switch ( new_state ) { + case PER_CPU_STATE_REQUEST_START_MULTITASKING: + while ( + state != PER_CPU_STATE_READY_TO_START_MULTITASKING + && state != PER_CPU_STATE_SHUTDOWN + ) { + _CPU_SMP_Processor_event_receive(); + state = per_cpu->state; + } + break; + case PER_CPU_STATE_UP: + while ( + state != PER_CPU_STATE_REQUEST_START_MULTITASKING + && state != PER_CPU_STATE_SHUTDOWN + ) { + _CPU_SMP_Processor_event_receive(); + state = per_cpu->state; + } + break; + default: + /* No need to wait */ + break; + } +} + +static Per_CPU_State _Per_CPU_State_get_next( + Per_CPU_State current_state, + Per_CPU_State new_state +) +{ + switch ( current_state ) { + case PER_CPU_STATE_INITIAL: + switch ( new_state ) { + case PER_CPU_STATE_READY_TO_START_MULTITASKING: + case PER_CPU_STATE_SHUTDOWN: + /* Change is acceptable */ + break; + default: + new_state = PER_CPU_STATE_SHUTDOWN; + break; + } + break; + case PER_CPU_STATE_READY_TO_START_MULTITASKING: + switch ( new_state ) { + case PER_CPU_STATE_REQUEST_START_MULTITASKING: + case PER_CPU_STATE_SHUTDOWN: + /* Change is acceptable */ + break; + default: + new_state = PER_CPU_STATE_SHUTDOWN; + break; + } + break; + case PER_CPU_STATE_REQUEST_START_MULTITASKING: + switch ( new_state ) { + case PER_CPU_STATE_UP: + case PER_CPU_STATE_SHUTDOWN: + /* Change is acceptable */ + break; + default: + new_state = PER_CPU_STATE_SHUTDOWN; + break; + } + break; + default: + new_state = PER_CPU_STATE_SHUTDOWN; + break; } - void _Per_CPU_Wait_for_state( - const Per_CPU_Control *per_cpu, - Per_CPU_State desired_state - ) - { - while ( per_cpu->state != desired_state ) { - _CPU_SMP_Processor_event_receive(); + return new_state; +} + +void _Per_CPU_State_change( + Per_CPU_Control *per_cpu, + Per_CPU_State new_state +) +{ + ISR_Level level; + Per_CPU_State next_state; + + _Per_CPU_State_busy_wait( per_cpu, new_state ); + + level = _Per_CPU_State_acquire(); + next_state = _Per_CPU_State_get_next( per_cpu->state, new_state ); + per_cpu->state = next_state; + + if ( next_state == PER_CPU_STATE_SHUTDOWN ) { + uint32_t ncpus = rtems_configuration_get_maximum_processors(); + uint32_t cpu; + + for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { + Per_CPU_Control *other_cpu = _Per_CPU_Get_by_index( cpu ); + + if ( per_cpu != other_cpu ) { + switch ( other_cpu->state ) { + case PER_CPU_STATE_UP: + _SMP_Send_message( cpu, SMP_MESSAGE_SHUTDOWN ); + break; + default: + /* Nothing to do */ + break; + } + + other_cpu->state = PER_CPU_STATE_SHUTDOWN; + } } } + + _CPU_SMP_Processor_event_broadcast(); + + _Per_CPU_State_release( level ); + + if ( + next_state == PER_CPU_STATE_SHUTDOWN + && new_state != PER_CPU_STATE_SHUTDOWN + ) { + rtems_fatal( RTEMS_FATAL_SOURCE_SMP, SMP_FATAL_SHUTDOWN ); + } +} + #else /* * On single core systems, we can efficiently directly access a single diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c index 59036eb466..0f632236b7 100644 --- a/cpukit/score/src/smp.c +++ b/cpukit/score/src/smp.c @@ -24,10 +24,6 @@ #include <rtems/score/threadimpl.h> #include <rtems/config.h> -#if defined(RTEMS_DEBUG) - #include <rtems/bspIo.h> -#endif - void _SMP_Handler_initialize( void ) { uint32_t max_cpus = rtems_configuration_get_maximum_processors(); @@ -47,21 +43,38 @@ void _SMP_Handler_initialize( void ) _SMP_Processor_count = max_cpus; } -void _SMP_Start_multitasking_on_secondary_processor( void ) +void _SMP_Request_start_multitasking( void ) { Per_CPU_Control *self_cpu = _Per_CPU_Get(); + uint32_t ncpus = _SMP_Get_processor_count(); + uint32_t cpu; + + _Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING ); - #if defined(RTEMS_DEBUG) - printk( "Made it to %d -- ", _Per_CPU_Get_index( self_cpu ) ); - #endif + for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { + Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); + + _Per_CPU_State_change( per_cpu, PER_CPU_STATE_REQUEST_START_MULTITASKING ); + } +} - _Per_CPU_Change_state( self_cpu, PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING ); +void _SMP_Start_multitasking_on_secondary_processor( void ) +{ + Per_CPU_Control *self_cpu = _Per_CPU_Get(); - _Per_CPU_Wait_for_state( self_cpu, PER_CPU_STATE_BEGIN_MULTITASKING ); + _Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING ); _Thread_Start_multitasking(); } +void _SMP_Request_shutdown( void ) +{ + uint32_t self = _SMP_Get_current_processor(); + Per_CPU_Control *self_cpu = _Per_CPU_Get_by_index( self ); + + _Per_CPU_State_change( self_cpu, PER_CPU_STATE_SHUTDOWN ); +} + void _SMP_Send_message( uint32_t cpu, uint32_t message ) { Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); @@ -88,47 +101,3 @@ void _SMP_Broadcast_message( uint32_t message ) } } } - -void _SMP_Request_other_cores_to_perform_first_context_switch( void ) -{ - uint32_t self = _SMP_Get_current_processor(); - uint32_t ncpus = _SMP_Get_processor_count(); - uint32_t cpu; - - for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { - Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); - - if ( cpu != self ) { - _Per_CPU_Wait_for_state( - per_cpu, - PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING - ); - - _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_BEGIN_MULTITASKING ); - } - } -} - -void _SMP_Request_other_cores_to_shutdown( void ) -{ - uint32_t self = _SMP_Get_current_processor(); - - /* - * Do not use _SMP_Get_processor_count() since this value might be not - * initialized yet. For example due to a fatal error in the middle of - * _CPU_SMP_Initialize(). - */ - uint32_t ncpus = rtems_configuration_get_maximum_processors(); - - uint32_t cpu; - - for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { - if ( cpu != self ) { - const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); - - if ( per_cpu->state != PER_CPU_STATE_BEFORE_INITIALIZATION ) { - _SMP_Send_message( cpu, SMP_MESSAGE_SHUTDOWN ); - } - } - } -} diff --git a/cpukit/score/src/threadstartmultitasking.c b/cpukit/score/src/threadstartmultitasking.c index d73e5b4194..2c40170f36 100644 --- a/cpukit/score/src/threadstartmultitasking.c +++ b/cpukit/score/src/threadstartmultitasking.c @@ -26,7 +26,7 @@ void _Thread_Start_multitasking( void ) Thread_Control *heir; #if defined(RTEMS_SMP) - _Per_CPU_Change_state( self_cpu, PER_CPU_STATE_UP ); + _Per_CPU_State_change( self_cpu, PER_CPU_STATE_UP ); /* * Threads begin execution in the _Thread_Handler() function. This |