summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/smp.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-07-27 13:40:51 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-07-28 19:32:24 +0200
commitcbb1103a3ca9d2f42501ba373b5d559b981fb1c7 (patch)
tree8e20c863237d95390b49c82d7ee45791389b5a2a /cpukit/score/src/smp.c
parentscore: Remove processor event broadcast/receive (diff)
downloadrtems-cbb1103a3ca9d2f42501ba373b5d559b981fb1c7.tar.bz2
score: Simplify SMP processor state handling
The per-CPU states which control the SMP system initialization were added quite early during the SMP support development. Replace this initial implementation with a simplified one. There is no longer a global SMP lock required which serialized the state changes of all processors. The new implementation better integrates with the per-CPU jobs.
Diffstat (limited to '')
-rw-r--r--cpukit/score/src/smp.c142
1 files changed, 127 insertions, 15 deletions
diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c
index 0488464da0..2c37cd6884 100644
--- a/cpukit/score/src/smp.c
+++ b/cpukit/score/src/smp.c
@@ -5,11 +5,12 @@
*
* @brief This source file contains the definition of ::_SMP_Online_processors
* and ::_SMP_Processor_maximum and the implementation of
- * _SMP_Handler_initialize(), _SMP_Request_shutdown(),
- * _SMP_Request_start_multitasking(), _SMP_Send_message(),
- * _SMP_Send_message_broadcast(), _SMP_Send_message_multicast(),
- * _SMP_Should_start_processor(), and
- * _SMP_Start_multitasking_on_secondary_processor().
+ * _SMP_Handler_initialize(), _SMP_Process_message(),
+ * _SMP_Request_shutdown(), _SMP_Request_start_multitasking(),
+ * _SMP_Send_message(), _SMP_Send_message_broadcast(),
+ * _SMP_Send_message_multicast(), _SMP_Should_start_processor(),
+ * _SMP_Start_multitasking_on_secondary_processor(), and
+ * _SMP_Try_to_process_message().
*/
/*
@@ -35,6 +36,15 @@
#error "deferred FP switch not implemented for SMP"
#endif
+/**
+ * @brief Indicates if the system is ready to start multitasking.
+ *
+ * Only the boot processor is allowed to change this object. If the object has
+ * a non-zero value and no fatal error occurred, then secondary processors
+ * should call _Thread_Start_multitasking() to start multiprocessing.
+ */
+static Atomic_Uint _SMP_Ready_to_start_multitasking;
+
Processor_mask _SMP_Online_processors;
uint32_t _SMP_Processor_maximum;
@@ -159,20 +169,38 @@ void _SMP_Request_start_multitasking( void )
uint32_t cpu_max;
uint32_t cpu_index;
- cpu_self = _Per_CPU_Get();
- _Per_CPU_State_change( cpu_self, PER_CPU_STATE_READY_TO_START_MULTITASKING );
-
cpu_max = _SMP_Get_processor_maximum();
+ cpu_self = _Per_CPU_Get();
+ /*
+ * Wait until all other online processors reached the
+ * PER_CPU_STATE_READY_TO_START_MULTITASKING state. The waiting is done
+ * without a timeout. If secondary processors cannot reach this state, then
+ * it is expected that they indicate this failure with an
+ * ::SMP_MESSAGE_SHUTDOWN message or reset the system.
+ */
for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
Per_CPU_Control *cpu;
cpu = _Per_CPU_Get_by_index( cpu_index );
- if ( _Per_CPU_Is_processor_online( cpu ) ) {
- _Per_CPU_State_change( cpu, PER_CPU_STATE_REQUEST_START_MULTITASKING );
+ if ( cpu != cpu_self && _Per_CPU_Is_processor_online( cpu ) ) {
+ while (
+ _Per_CPU_Get_state( cpu ) != PER_CPU_STATE_READY_TO_START_MULTITASKING
+ ) {
+ _SMP_Try_to_process_message(
+ cpu_self,
+ _Atomic_Load_ulong( &cpu_self->message, ATOMIC_ORDER_RELAXED )
+ );
+ }
}
}
+
+ _Atomic_Store_uint(
+ &_SMP_Ready_to_start_multitasking,
+ 1U,
+ ATOMIC_ORDER_RELEASE
+ );
}
bool _SMP_Should_start_processor( uint32_t cpu_index )
@@ -183,6 +211,22 @@ bool _SMP_Should_start_processor( uint32_t cpu_index )
return _Scheduler_Should_start_processor( assignment );
}
+static void _SMP_Wait_for_start_multitasking( Per_CPU_Control *cpu_self )
+{
+ unsigned int ready;
+
+ do {
+ _SMP_Try_to_process_message(
+ cpu_self,
+ _Atomic_Load_ulong( &cpu_self->message, ATOMIC_ORDER_RELAXED )
+ );
+ ready = _Atomic_Load_uint(
+ &_SMP_Ready_to_start_multitasking,
+ ATOMIC_ORDER_ACQUIRE
+ );
+ } while ( ready == 0U );
+}
+
void _SMP_Start_multitasking_on_secondary_processor(
Per_CPU_Control *cpu_self
)
@@ -199,28 +243,96 @@ void _SMP_Start_multitasking_on_secondary_processor(
_SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR );
}
- _Per_CPU_State_change( cpu_self, PER_CPU_STATE_READY_TO_START_MULTITASKING );
-
+ _Per_CPU_Set_state( cpu_self, PER_CPU_STATE_READY_TO_START_MULTITASKING );
+ _SMP_Wait_for_start_multitasking( cpu_self );
_Thread_Start_multitasking();
}
void _SMP_Request_shutdown( void )
{
ISR_Level level;
+ uint32_t cpu_max;
+ uint32_t cpu_index_self;
+ uint32_t cpu_index;
_ISR_Local_disable( level );
(void) level;
- _Per_CPU_State_change( _Per_CPU_Get(), PER_CPU_STATE_SHUTDOWN );
+ cpu_max = _SMP_Processor_configured_maximum;
+ cpu_index_self = _SMP_Get_current_processor();
+
+ for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
+ Per_CPU_Control *cpu;
+
+ cpu = _Per_CPU_Get_by_index( cpu_index );
+
+ if ( cpu_index == cpu_index_self ) {
+ _Per_CPU_Set_state( cpu, PER_CPU_STATE_SHUTDOWN );
+ } else {
+ _Atomic_Fetch_or_ulong(
+ &cpu->message,
+ SMP_MESSAGE_SHUTDOWN,
+ ATOMIC_ORDER_RELEASE
+ );
+
+ if ( _Per_CPU_Get_state( cpu ) == PER_CPU_STATE_UP ) {
+ _CPU_SMP_Send_interrupt( cpu_index );
+ }
+ }
+ }
+}
+
+long unsigned _SMP_Process_message(
+ Per_CPU_Control *cpu_self,
+ long unsigned message
+)
+{
+ if ( ( message & SMP_MESSAGE_SHUTDOWN ) != 0 ) {
+ /* Check the state to prevent recursive shutdowns */
+ if ( _Per_CPU_Get_state( cpu_self ) != PER_CPU_STATE_SHUTDOWN ) {
+ _Per_CPU_Set_state( cpu_self, PER_CPU_STATE_SHUTDOWN );
+ _SMP_Fatal( SMP_FATAL_SHUTDOWN_RESPONSE );
+ }
+ }
+
+ if ( ( message & SMP_MESSAGE_PERFORM_JOBS ) != 0 ) {
+ _Per_CPU_Perform_jobs( cpu_self );
+ }
+}
+
+void _SMP_Try_to_process_message(
+ Per_CPU_Control *cpu_self,
+ unsigned long message
+)
+{
+ if ( message != 0 ) {
+ /*
+ * Fetch the current message. Only a read-modify-write operation
+ * guarantees that we get an up to date message. This is especially
+ * important if the function was called using SMP_MESSAGE_FORCE_PROCESSING.
+ */
+ message = _Atomic_Exchange_ulong(
+ &cpu_self->message,
+ 0,
+ ATOMIC_ORDER_ACQUIRE
+ );
+
+ _SMP_Process_message( cpu_self, message );
+ }
}
void _SMP_Send_message( uint32_t cpu_index, unsigned long message )
{
Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
- _Atomic_Fetch_or_ulong( &cpu->message, message, ATOMIC_ORDER_RELEASE );
+ (void) _Atomic_Fetch_or_ulong(
+ &cpu->message, message,
+ ATOMIC_ORDER_RELEASE
+ );
- _CPU_SMP_Send_interrupt( cpu_index );
+ if ( _Per_CPU_Get_state( cpu ) == PER_CPU_STATE_UP ) {
+ _CPU_SMP_Send_interrupt( cpu_index );
+ }
}
void _SMP_Send_message_broadcast( unsigned long message )