summaryrefslogblamecommitdiffstats
path: root/cpukit/score/src/smp.c
blob: 0488464da07ed594d63c0161cc3d3eebec4f54d8 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
   
        
  








                                                                              

   





                                                           
                                         

   
                    


                   
                                
                               
                                      
                                   
                         
 



                                                     

                                      
                                
 




















                                                                              
                                                     
 
                          

                     

                                                
                                                            





                                                                
 
                                        











                                                                            

                       




                                                                         
                          

                    




                                                    
 

                                                                

                                         

     

 

                                    

                          
                     
 


                                                                   
                         
 
                                             
                                                
                                                          
                                                                  
                                                              

   


                                                                  
 


                                                                
 
                                                                         


                                                                
 

                                                              


     
                                   
 
                                              

 
                                            
 
                            
                           



                                                                               
 
                                         
 
                                                             


                                             
 
                                                

                                                                             

   
 

                                                      
                                         
 
                                                              


                                                         


                                                    
 


                                                  
 



                                                                         
                                                         


                                                                       
                                                                               
 
                               

 

                                  



                              
 
                                                                  

 
                                                                   
 
                                                            
 
                                                                         
 
                                       

 
                                                         
 

                          
                     
 
                                                    

                                                
 
                                                             

                                 
                                                                       
       
                                              
     
   
 
 
                                 

                                

 
                   

                     


                                                             
                                                         



                                              
/**
 * @file
 *
 * @ingroup RTEMSScoreSMP
 *
 * @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().
 */

/*
 *  COPYRIGHT (c) 1989-2011.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.org/license/LICENSE.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/score/smpimpl.h>
#include <rtems/score/assert.h>
#include <rtems/score/schedulerimpl.h>
#include <rtems/score/threadimpl.h>
#include <rtems/config.h>

#if CPU_USE_DEFERRED_FP_SWITCH == TRUE
  #error "deferred FP switch not implemented for SMP"
#endif

Processor_mask _SMP_Online_processors;

uint32_t _SMP_Processor_maximum;

static const Scheduler_Assignment *_Scheduler_Get_initial_assignment(
  uint32_t cpu_index
)
{
  return &_Scheduler_Initial_assignments[ cpu_index ];
}

static bool _Scheduler_Is_mandatory_processor(
  const Scheduler_Assignment *assignment
)
{
  return (assignment->attributes & SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) != 0;
}

static bool _Scheduler_Should_start_processor(
  const Scheduler_Assignment *assignment
)
{
  return assignment->scheduler != NULL;
}

static void _SMP_Start_processors( uint32_t cpu_max )
{
  uint32_t cpu_index_self;
  uint32_t cpu_index;

  cpu_index_self = _SMP_Get_current_processor();

  for ( cpu_index = 0 ; cpu_index < cpu_max; ++cpu_index ) {
    const Scheduler_Assignment *assignment;
    Per_CPU_Control            *cpu;
    bool                        started;

    assignment = _Scheduler_Get_initial_assignment( cpu_index );
    cpu = _Per_CPU_Get_by_index( cpu_index );

    if ( cpu_index != cpu_index_self ) {
      if ( _Scheduler_Should_start_processor( assignment ) ) {
        started = _CPU_SMP_Start_processor( cpu_index );

        if ( !started && _Scheduler_Is_mandatory_processor( assignment ) ) {
          _SMP_Fatal( SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED );
        }
      } else {
        started = false;
      }
    } else {
      started = true;

      cpu->boot = true;

      if ( !_Scheduler_Should_start_processor( assignment ) ) {
        _SMP_Fatal( SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER );
      }
    }

    cpu->online = started;

    if ( started ) {
      const Scheduler_Control *scheduler;
      Scheduler_Context       *context;

      scheduler = assignment->scheduler;
      context = _Scheduler_Get_context( scheduler );

      _Processor_mask_Set( &_SMP_Online_processors, cpu_index );
      _Processor_mask_Set( &context->Processors, cpu_index );
      cpu->Scheduler.control = scheduler;
      cpu->Scheduler.context = context;
    }
  }
}

void _SMP_Handler_initialize( void )
{
  uint32_t cpu_config_max;
  uint32_t cpu_max;
  uint32_t cpu_index;

  cpu_config_max = rtems_configuration_get_maximum_processors();

  for ( cpu_index = 0 ; cpu_index < cpu_config_max; ++cpu_index ) {
    Per_CPU_Control *cpu;

    cpu = _Per_CPU_Get_by_index( cpu_index );
    _ISR_lock_Set_name( &cpu->Lock, "Per-CPU" );
    _ISR_lock_Set_name( &cpu->Jobs.Lock, "Per-CPU Jobs" );
    _ISR_lock_Set_name( &cpu->Watchdog.Lock, "Per-CPU Watchdog" );
    _Chain_Initialize_empty( &cpu->Threads_in_need_for_help );
  }

  /*
   * Discover and initialize the secondary cores in an SMP system.
   */

  cpu_max = _CPU_SMP_Initialize();
  cpu_max = cpu_max < cpu_config_max ? cpu_max : cpu_config_max;
  _SMP_Processor_maximum = cpu_max;

  for ( cpu_index = cpu_max ; cpu_index < cpu_config_max; ++cpu_index ) {
    const Scheduler_Assignment *assignment;

    assignment = _Scheduler_Get_initial_assignment( cpu_index );

    if ( _Scheduler_Is_mandatory_processor( assignment ) ) {
      _SMP_Fatal( SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT );
    }
  }

  _SMP_Start_processors( cpu_max );

  _CPU_SMP_Finalize_initialization( cpu_max );
}

void _SMP_Request_start_multitasking( void )
{
  Per_CPU_Control *cpu_self;
  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();

  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 );
    }
  }
}

bool _SMP_Should_start_processor( uint32_t cpu_index )
{
  const Scheduler_Assignment *assignment;

  assignment = _Scheduler_Get_initial_assignment( cpu_index );
  return _Scheduler_Should_start_processor( assignment );
}

void _SMP_Start_multitasking_on_secondary_processor(
  Per_CPU_Control *cpu_self
)
{
  uint32_t cpu_index_self;

  cpu_index_self = _Per_CPU_Get_index( cpu_self );

  if ( cpu_index_self >= rtems_configuration_get_maximum_processors() ) {
    _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_INVALID_PROCESSOR );
  }

  if ( !_SMP_Should_start_processor( cpu_index_self ) ) {
    _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR );
  }

  _Per_CPU_State_change( cpu_self, PER_CPU_STATE_READY_TO_START_MULTITASKING );

  _Thread_Start_multitasking();
}

void _SMP_Request_shutdown( void )
{
  ISR_Level level;

  _ISR_Local_disable( level );
  (void) level;

  _Per_CPU_State_change( _Per_CPU_Get(), PER_CPU_STATE_SHUTDOWN );
}

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 );

  _CPU_SMP_Send_interrupt( cpu_index );
}

void _SMP_Send_message_broadcast( unsigned long message )
{
  uint32_t cpu_max;
  uint32_t cpu_index_self;
  uint32_t cpu_index;

  _Assert( _Debug_Is_thread_dispatching_allowed() );
  cpu_max = _SMP_Get_processor_maximum();
  cpu_index_self = _SMP_Get_current_processor();

  for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
    if (
      cpu_index != cpu_index_self
        && _Processor_mask_Is_set( &_SMP_Online_processors, cpu_index )
    ) {
      _SMP_Send_message( cpu_index, message );
    }
  }
}

void _SMP_Send_message_multicast(
  const Processor_mask *targets,
  unsigned long         message
)
{
  uint32_t cpu_max;
  uint32_t cpu_index;

  cpu_max = _SMP_Get_processor_maximum();

  for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
    if ( _Processor_mask_Is_set( targets, cpu_index ) ) {
      _SMP_Send_message( cpu_index, message );
    }
  }
}