summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/percpu.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-02-18 13:40:39 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-03-06 09:43:57 +0100
commit7336be9d78266adfb540170e5105caf8eb003d2f (patch)
tree5dc7ab7a5c3c33c7e007a8e8e48cb1167187b0ca /cpukit/score/src/percpu.c
parentbsp/leon3: Unmask IPI only on secondary processor (diff)
downloadrtems-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/percpu.c')
-rw-r--r--cpukit/score/src/percpu.c158
1 files changed, 144 insertions, 14 deletions
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