From 2f6108f93b3ee4dcc85b236593d4c57c7652bf1b Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 28 May 2013 10:58:19 +0200 Subject: 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(). --- cpukit/score/src/smp.c | 249 ++++++++++++++++++------------------------------- 1 file changed, 93 insertions(+), 156 deletions(-) (limited to 'cpukit/score/src/smp.c') 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 #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