diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-05-28 10:58:19 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-05-29 11:06:07 +0200 |
commit | 2f6108f93b3ee4dcc85b236593d4c57c7652bf1b (patch) | |
tree | 841e4daad0d7f0e1dcd7a6eb91271731662c77e4 /cpukit/score/src | |
parent | smp: Delete bsp_smp_secondary_cpu_initialize() (diff) | |
download | rtems-2f6108f93b3ee4dcc85b236593d4c57c7652bf1b.tar.bz2 |
smp: Simplify SMP initialization sequence
Delete bsp_smp_wait_for(). Other parts of the system work without
timeout, e.g. the spinlocks. Using a timeout here does not make the
system more robust.
Delete bsp_smp_cpu_state and replace it with Per_CPU_State. The
Per_CPU_State follows the Score naming conventions. Add
_Per_CPU_Change_state() and _Per_CPU_Wait_for_state() functions to
change and observe states.
Use Per_CPU_State in Per_CPU_Control instead of the anonymous integer.
Add _CPU_Processor_event_broadcast() and _CPU_Processor_event_receive()
functions provided by the CPU port. Use these functions in
_Per_CPU_Change_state() and _Per_CPU_Wait_for_state().
Add prototype for _SMP_Send_message().
Delete RTEMS_BSP_SMP_FIRST_TASK message. The first context switch is
now performed in rtems_smp_secondary_cpu_initialize(). Issuing the
first context switch in the context of the inter-processor interrupt is
not possible on systems with a modern interrupt controller. Such an
interrupt controler usually requires a handshake protocol with interrupt
acknowledge and end of interrupt signals. A direct context switch in an
interrupt handler circumvents the interrupt processing epilogue and may
leave the system in an inconsistent state.
Release lock in rtems_smp_process_interrupt() even if no message was
delivered. This prevents deadlock of the system.
Simplify and format _SMP_Send_message(),
_SMP_Request_other_cores_to_perform_first_context_switch(),
_SMP_Request_other_cores_to_dispatch() and
_SMP_Request_other_cores_to_shutdown().
Diffstat (limited to '')
-rw-r--r-- | cpukit/score/src/percpu.c | 29 | ||||
-rw-r--r-- | cpukit/score/src/smp.c | 249 |
2 files changed, 119 insertions, 159 deletions
diff --git a/cpukit/score/src/percpu.c b/cpukit/score/src/percpu.c index f01d933cfe..a957053e18 100644 --- a/cpukit/score/src/percpu.c +++ b/cpukit/score/src/percpu.c @@ -56,9 +56,6 @@ p->interrupt_stack_high = (void *)ptr; } #endif - - p->state = RTEMS_BSP_SMP_CPU_INITIAL_STATE; - RTEMS_COMPILER_MEMORY_BARRIER(); } /* @@ -67,6 +64,32 @@ max_cpus = bsp_smp_initialize( max_cpus ); _SMP_Processor_count = max_cpus; + + for ( cpu = 1 ; cpu < max_cpus; ++cpu ) { + _Per_CPU_Wait_for_state( + &_Per_CPU_Information[ cpu ], + PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING + ); + } + } + + void _Per_CPU_Change_state( + Per_CPU_Control *per_cpu, + Per_CPU_State new_state + ) + { + per_cpu->state = new_state; + _CPU_Processor_event_broadcast(); + } + + void _Per_CPU_Wait_for_state( + const Per_CPU_Control *per_cpu, + Per_CPU_State desired_state + ) + { + while ( per_cpu->state != desired_state ) { + _CPU_Processor_event_receive(); + } } #else /* diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c index a06db5ef84..aee1c4584f 100644 --- a/cpukit/score/src/smp.c +++ b/cpukit/score/src/smp.c @@ -27,142 +27,87 @@ #include <rtems/bspIo.h> #endif -/* - * Process request to switch to the first task on a secondary core. - */ -void rtems_smp_run_first_task(int cpu) +void rtems_smp_secondary_cpu_initialize( void ) { - Thread_Control *heir; - ISR_Level level; + int self = bsp_smp_processor_id(); + Per_CPU_Control *per_cpu = &_Per_CPU_Information[ self ]; + Thread_Control *heir; + + #if defined(RTEMS_DEBUG) + printk( "Made it to %d -- ", self ); + #endif + + _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING ); + + _Per_CPU_Wait_for_state( per_cpu, PER_CPU_STATE_BEGIN_MULTITASKING ); - _ISR_Disable_on_this_core( level ); + _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_UP ); /* * The Scheduler will have selected the heir thread for each CPU core. * Now we have been requested to perform the first context switch. So - * force a switch to the designated heir and make it executing on + * force a switch to the designated heir and make it executing on * THIS core. */ - heir = _Thread_Heir; - _Thread_Executing = heir; - - _CPU_Context_switch_to_first_task_smp( &heir->Registers ); -} - -void rtems_smp_secondary_cpu_initialize(void) -{ - int cpu; - ISR_Level level; - - cpu = bsp_smp_processor_id(); + heir = per_cpu->heir; + per_cpu->executing = heir; /* - * Inform the primary CPU that this secondary CPU is initialized - * and ready to dispatch to the first thread it is supposed to - * execute when the primary CPU is ready. + * Threads begin execution in the _Thread_Handler() function. This function + * will call _Thread_Enable_dispatch(). */ - _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_INITIALIZED; - - #if defined(RTEMS_DEBUG) - printk( "Made it to %d -- ", cpu ); - #endif + _Thread_Disable_dispatch(); - /* - * With this secondary core out of reset, we can wait for the - * request to switch to the first task. - */ - while(1) { - uint32_t message; - - bsp_smp_wait_for( - (volatile unsigned int *)&_Per_CPU_Information[cpu].message, - RTEMS_BSP_SMP_FIRST_TASK, - 10000 - ); - - level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock ); - message = _Per_CPU_Information[cpu].message; - if ( message & RTEMS_BSP_SMP_FIRST_TASK ) { - _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level ); - _ISR_Set_level( 0 ); - } - - _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level ); - } + _CPU_Context_switch_to_first_task_smp( &heir->Registers ); } -void rtems_smp_process_interrupt(void) +void rtems_smp_process_interrupt( void ) { - int cpu; - uint32_t message; - ISR_Level level; + int self = bsp_smp_processor_id(); + Per_CPU_Control *per_cpu = &_Per_CPU_Information[ self ]; + uint32_t message; + ISR_Level level; - cpu = bsp_smp_processor_id(); - level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock ); - message = _Per_CPU_Information[cpu].message; + level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock ); + message = per_cpu->message; + per_cpu->message = 0; + _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level ); #if defined(RTEMS_DEBUG) { void *sp = __builtin_frame_address(0); if ( !(message & RTEMS_BSP_SMP_SHUTDOWN) ) { - printk( "ISR on CPU %d -- (0x%02x) (0x%p)\n", cpu, message, sp ); + printk( "ISR on CPU %d -- (0x%02x) (0x%p)\n", self, message, sp ); if ( message & RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY ) printk( "context switch necessary\n" ); if ( message & RTEMS_BSP_SMP_SIGNAL_TO_SELF ) printk( "signal to self\n" ); if ( message & RTEMS_BSP_SMP_SHUTDOWN ) printk( "shutdown\n" ); - if ( message & RTEMS_BSP_SMP_FIRST_TASK ) - printk( "switch to first task\n" ); } printk( "Dispatch level %d\n", _Thread_Dispatch_get_disable_level() ); } #endif - if ( message & RTEMS_BSP_SMP_FIRST_TASK ) { - _Per_CPU_Information[cpu].isr_nest_level = 0; - _Per_CPU_Information[cpu].message &= ~message; - _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_UP; - - _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level ); - - rtems_smp_run_first_task(cpu); - /* does not return */ - } - if ( message & RTEMS_BSP_SMP_SHUTDOWN ) { - _Per_CPU_Information[cpu].message &= ~message; + _ISR_Disable_on_this_core( level ); - _Per_CPU_Information[cpu].isr_nest_level = 0; - _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_SHUTDOWN; - _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level ); + while ( _Thread_Dispatch_decrement_disable_level() != 0 ) { + /* Release completely */ + } - _Thread_Enable_dispatch(); /* undo ISR code */ - _ISR_Disable_on_this_core( level ); + _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_SHUTDOWN ); while(1) ; /* does not continue past here */ } - - if ( message & RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY ) { - #if defined(RTEMS_DEBUG) - printk( "switch needed\n" ); - #endif - _Per_CPU_Information[cpu].message &= ~message; - _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level ); - } } -/* - * Send an interrupt processor request to another cpu. - */ -void _SMP_Send_message( - int cpu, - uint32_t message -) +void _SMP_Send_message( int cpu, uint32_t message ) { + Per_CPU_Control *per_cpu = &_Per_CPU_Information[ cpu ]; ISR_Level level; #if defined(RTEMS_DEBUG) @@ -170,90 +115,82 @@ void _SMP_Send_message( printk( "Send 0x%x to %d\n", message, cpu ); #endif - level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock ); - _Per_CPU_Information[cpu].message |= message; - _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level ); + level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock ); + per_cpu->message |= message; + _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level ); + bsp_smp_interrupt_cpu( cpu ); } -void _SMP_Broadcast_message( - uint32_t message -) +void _SMP_Broadcast_message( uint32_t message ) { - int dest_cpu; - int cpu; - ISR_Level level; - - cpu = bsp_smp_processor_id(); - - for ( dest_cpu=0 ; dest_cpu < _SMP_Processor_count; dest_cpu++ ) { - if ( cpu == dest_cpu ) - continue; - level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock ); - _Per_CPU_Information[dest_cpu].message |= message; - _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level ); + int self = bsp_smp_processor_id(); + int ncpus = _SMP_Processor_count; + int cpu; + + for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { + if ( cpu != self ) { + Per_CPU_Control *per_cpu = &_Per_CPU_Information[ cpu ]; + ISR_Level level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock ); + per_cpu->message |= message; + _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level ); + } } + bsp_smp_broadcast_interrupt(); } -void _SMP_Request_other_cores_to_perform_first_context_switch(void) +void _SMP_Request_other_cores_to_perform_first_context_switch( void ) { - int cpu; + int self = bsp_smp_processor_id(); + int ncpus = _SMP_Processor_count; + int cpu; - _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_UP; - for (cpu=1 ; cpu < _SMP_Processor_count ; cpu++ ) { - _SMP_Send_message( cpu, RTEMS_BSP_SMP_FIRST_TASK ); + for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { + if ( cpu != self ) { + _Per_CPU_Change_state( + &_Per_CPU_Information[ cpu ], + PER_CPU_STATE_BEGIN_MULTITASKING + ); + } } } -void _SMP_Request_other_cores_to_dispatch(void) +void _SMP_Request_other_cores_to_dispatch( void ) { - int i; - int cpu; - - cpu = bsp_smp_processor_id(); - - if ( !_System_state_Is_up (_System_state_Current) ) - return; - for (i=1 ; i < _SMP_Processor_count ; i++ ) { - if ( cpu == i ) - continue; - if ( _Per_CPU_Information[i].state != RTEMS_BSP_SMP_CPU_UP ) - continue; - if ( !_Per_CPU_Information[i].dispatch_necessary ) - continue; - _SMP_Send_message( i, RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY ); + if ( _System_state_Is_up( _System_state_Get() ) ) { + int self = bsp_smp_processor_id(); + int ncpus = _SMP_Processor_count; + int cpu; + + for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { + const Per_CPU_Control *per_cpu = &_Per_CPU_Information[ cpu ]; + + if ( + cpu != self + && per_cpu->state == PER_CPU_STATE_UP + && per_cpu->dispatch_necessary + ) { + _SMP_Send_message( cpu, RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY ); + } + } } } -void _SMP_Request_other_cores_to_shutdown(void) +void _SMP_Request_other_cores_to_shutdown( void ) { - bool allDown; - int ncpus; - int n; - int cpu; - - cpu = bsp_smp_processor_id(); - ncpus = _SMP_Processor_count; + int self = bsp_smp_processor_id(); + int ncpus = _SMP_Processor_count; + int cpu; _SMP_Broadcast_message( RTEMS_BSP_SMP_SHUTDOWN ); - allDown = true; - for (n=0 ; n<ncpus ; n++ ) { - if ( n == cpu ) - continue; - bsp_smp_wait_for( - (unsigned int *)&_Per_CPU_Information[n].state, - RTEMS_BSP_SMP_CPU_SHUTDOWN, - 10000 - ); - if ( _Per_CPU_Information[n].state != RTEMS_BSP_SMP_CPU_SHUTDOWN ) - allDown = false; + for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { + if ( cpu != self ) { + _Per_CPU_Wait_for_state( + &_Per_CPU_Information[ cpu ], + PER_CPU_STATE_SHUTDOWN + ); + } } - if ( !allDown ) - printk( "not all down -- timed out\n" ); - #if defined(RTEMS_DEBUG) - else - printk( "All CPUs shutdown successfully\n" ); - #endif } |