RTEMS
smp.c
Go to the documentation of this file.
1 
8 /*
9  * COPYRIGHT (c) 1989-2011.
10  * On-Line Applications Research Corporation (OAR).
11  *
12  * The license and distribution terms for this file may be
13  * found in the file LICENSE in this distribution or at
14  * http://www.rtems.org/license/LICENSE.
15  */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include <rtems/score/smpimpl.h>
22 #include <rtems/score/assert.h>
23 #include <rtems/score/memory.h>
24 #include <rtems/score/percpudata.h>
26 #include <rtems/score/threadimpl.h>
27 #include <rtems/config.h>
28 #include <rtems/sysinit.h>
29 
30 #include <string.h>
31 
32 #if CPU_USE_DEFERRED_FP_SWITCH == TRUE
33  #error "deferred FP switch not implemented for SMP"
34 #endif
35 
36 Processor_mask _SMP_Online_processors;
37 
38 uint32_t _SMP_Processor_maximum;
39 
40 static const Scheduler_Assignment *_Scheduler_Get_initial_assignment(
41  uint32_t cpu_index
42 )
43 {
44  return &_Scheduler_Initial_assignments[ cpu_index ];
45 }
46 
47 static bool _Scheduler_Is_mandatory_processor(
48  const Scheduler_Assignment *assignment
49 )
50 {
51  return (assignment->attributes & SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) != 0;
52 }
53 
54 static bool _Scheduler_Should_start_processor(
55  const Scheduler_Assignment *assignment
56 )
57 {
58  return assignment->scheduler != NULL;
59 }
60 
61 static void _SMP_Start_processors( uint32_t cpu_max )
62 {
63  uint32_t cpu_index_self;
64  uint32_t cpu_index;
65 
66  cpu_index_self = _SMP_Get_current_processor();
67 
68  for ( cpu_index = 0 ; cpu_index < cpu_max; ++cpu_index ) {
69  const Scheduler_Assignment *assignment;
70  Per_CPU_Control *cpu;
71  bool started;
72 
73  assignment = _Scheduler_Get_initial_assignment( cpu_index );
74  cpu = _Per_CPU_Get_by_index( cpu_index );
75 
76  if ( cpu_index != cpu_index_self ) {
77  if ( _Scheduler_Should_start_processor( assignment ) ) {
78  started = _CPU_SMP_Start_processor( cpu_index );
79 
80  if ( !started && _Scheduler_Is_mandatory_processor( assignment ) ) {
81  _SMP_Fatal( SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED );
82  }
83  } else {
84  started = false;
85  }
86  } else {
87  started = true;
88 
89  cpu->boot = true;
90 
91  if ( !_Scheduler_Should_start_processor( assignment ) ) {
92  _SMP_Fatal( SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER );
93  }
94  }
95 
96  cpu->online = started;
97 
98  if ( started ) {
99  const Scheduler_Control *scheduler;
100  Scheduler_Context *context;
101 
102  scheduler = assignment->scheduler;
103  context = _Scheduler_Get_context( scheduler );
104 
106  _Processor_mask_Set( &context->Processors, cpu_index );
107  cpu->Scheduler.control = scheduler;
108  cpu->Scheduler.context = context;
109  }
110  }
111 }
112 
114 {
115  uint32_t cpu_config_max;
116  uint32_t cpu_max;
117  uint32_t cpu_index;
118 
120 
121  for ( cpu_index = 0 ; cpu_index < cpu_config_max; ++cpu_index ) {
122  Per_CPU_Control *cpu;
123 
124  cpu = _Per_CPU_Get_by_index( cpu_index );
125  _ISR_lock_Set_name( &cpu->Lock, "Per-CPU" );
126  _ISR_lock_Set_name( &cpu->Jobs.Lock, "Per-CPU Jobs" );
127  _ISR_lock_Set_name( &cpu->Watchdog.Lock, "Per-CPU Watchdog" );
129  }
130 
131  /*
132  * Discover and initialize the secondary cores in an SMP system.
133  */
134 
135  cpu_max = _CPU_SMP_Initialize();
136  cpu_max = cpu_max < cpu_config_max ? cpu_max : cpu_config_max;
137  _SMP_Processor_maximum = cpu_max;
138 
139  for ( cpu_index = cpu_max ; cpu_index < cpu_config_max; ++cpu_index ) {
140  const Scheduler_Assignment *assignment;
141 
142  assignment = _Scheduler_Get_initial_assignment( cpu_index );
143 
144  if ( _Scheduler_Is_mandatory_processor( assignment ) ) {
145  _SMP_Fatal( SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT );
146  }
147  }
148 
149  _SMP_Start_processors( cpu_max );
150 
151  _CPU_SMP_Finalize_initialization( cpu_max );
152 }
153 
155 {
156  Per_CPU_Control *cpu_self;
157  uint32_t cpu_max;
158  uint32_t cpu_index;
159 
160  cpu_self = _Per_CPU_Get();
161  _Per_CPU_State_change( cpu_self, PER_CPU_STATE_READY_TO_START_MULTITASKING );
162 
163  cpu_max = _SMP_Get_processor_maximum();
164 
165  for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
166  Per_CPU_Control *cpu;
167 
168  cpu = _Per_CPU_Get_by_index( cpu_index );
169 
170  if ( _Per_CPU_Is_processor_online( cpu ) ) {
171  _Per_CPU_State_change( cpu, PER_CPU_STATE_REQUEST_START_MULTITASKING );
172  }
173  }
174 }
175 
176 bool _SMP_Should_start_processor( uint32_t cpu_index )
177 {
178  const Scheduler_Assignment *assignment;
179 
180  assignment = _Scheduler_Get_initial_assignment( cpu_index );
181  return _Scheduler_Should_start_processor( assignment );
182 }
183 
185  Per_CPU_Control *cpu_self
186 )
187 {
188  uint32_t cpu_index_self;
189 
190  cpu_index_self = _Per_CPU_Get_index( cpu_self );
191 
192  if ( cpu_index_self >= rtems_configuration_get_maximum_processors() ) {
193  _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_INVALID_PROCESSOR );
194  }
195 
196  if ( !_SMP_Should_start_processor( cpu_index_self ) ) {
197  _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR );
198  }
199 
200  _Per_CPU_State_change( cpu_self, PER_CPU_STATE_READY_TO_START_MULTITASKING );
201 
203 }
204 
206 {
207  ISR_Level level;
208 
209  _ISR_Local_disable( level );
210  (void) level;
211 
212  _Per_CPU_State_change( _Per_CPU_Get(), PER_CPU_STATE_SHUTDOWN );
213 }
214 
215 void _SMP_Send_message( uint32_t cpu_index, unsigned long message )
216 {
217  Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
218 
219  _Atomic_Fetch_or_ulong( &cpu->message, message, ATOMIC_ORDER_RELEASE );
220 
221  _CPU_SMP_Send_interrupt( cpu_index );
222 }
223 
224 void _SMP_Send_message_broadcast( unsigned long message )
225 {
226  uint32_t cpu_max;
227  uint32_t cpu_index_self;
228  uint32_t cpu_index;
229 
230  _Assert( _Debug_Is_thread_dispatching_allowed() );
231  cpu_max = _SMP_Get_processor_maximum();
232  cpu_index_self = _SMP_Get_current_processor();
233 
234  for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
235  if (
236  cpu_index != cpu_index_self
238  ) {
239  _SMP_Send_message( cpu_index, message );
240  }
241  }
242 }
243 
245  const Processor_mask *targets,
246  unsigned long message
247 )
248 {
249  uint32_t cpu_max;
250  uint32_t cpu_index;
251 
252  cpu_max = _SMP_Get_processor_maximum();
253 
254  for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
255  if ( _Processor_mask_Is_set( targets, cpu_index ) ) {
256  _SMP_Send_message( cpu_index, message );
257  }
258  }
259 }
260 
261 static void _Per_CPU_Data_initialize( void )
262 {
263  uintptr_t size;
264 
265  size = RTEMS_LINKER_SET_SIZE( _Per_CPU_Data );
266 
267  if ( size > 0 ) {
268  const Memory_Information *mem;
269  Per_CPU_Control *cpu;
270  uint32_t cpu_index;
271  uint32_t cpu_max;
272 
273  mem = _Memory_Get();
274  cpu = _Per_CPU_Get_by_index( 0 );
275  cpu->data = RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data );
276 
278 
279  for ( cpu_index = 1 ; cpu_index < cpu_max ; ++cpu_index ) {
280  cpu = _Per_CPU_Get_by_index( cpu_index );
281  cpu->data = _Memory_Allocate( mem, size, CPU_CACHE_LINE_BYTES );
282 
283  if( cpu->data == NULL ) {
284  _Internal_error( INTERNAL_ERROR_NO_MEMORY_FOR_PER_CPU_DATA );
285  }
286 
287  memcpy( cpu->data, RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data ), size);
288  }
289  }
290 }
291 
292 RTEMS_SYSINIT_ITEM(
293  _Per_CPU_Data_initialize,
294  RTEMS_SYSINIT_PER_CPU_DATA,
295  RTEMS_SYSINIT_ORDER_MIDDLE
296 );
void _SMP_Handler_initialize(void)
Initializes SMP Handler.
Definition: smp.c:113
Processor is ready to start multitasking.
Definition: percpu.h:153
Memory Handler API.
Scheduler context.
Definition: scheduler.h:247
#define _ISR_Local_disable(_level)
Disables interrupts on this processor.
Definition: isrlevel.h:57
bool _SMP_Should_start_processor(uint32_t cpu_index)
Checks if the processor with the specified index should be started.
Definition: smp.c:176
void _SMP_Start_multitasking_on_secondary_processor(Per_CPU_Control *cpu_self)
Performs high-level initialization of a secondary processor and runs the application threads...
Definition: smp.c:184
struct Per_CPU_Control::@15 Jobs
FIFO list of jobs to be performed by this processor.
ISR_lock_Control Lock
This lock protects some members of this structure.
Definition: percpu.h:481
#define SCHEDULER_ASSIGN_PROCESSOR_MANDATORY
The presence of this processor is mandatory.
Definition: scheduler.h:339
void _SMP_Send_message_multicast(const Processor_mask *targets, unsigned long message)
Sends an SMP message to a set of processors.
Definition: smp.c:244
void _SMP_Send_message_broadcast(unsigned long message)
Sends an SMP message to all other online processors.
Definition: smp.c:224
Inlined Routines Associated with the Manipulation of the Scheduler.
bool boot
Indicates if the processor is the one that performed the initial system initialization.
Definition: percpu.h:595
This header file defines parts of the application configuration information API.
const struct Scheduler_Context * context
The scheduler context of the scheduler owning this processor.
Definition: percpu.h:522
The memory information.
Definition: memory.h:80
Chain_Control Threads_in_need_for_help
Chain of threads in need for help.
Definition: percpu.h:497
Information for the Assert Handler.
RTEMS_INLINE_ROUTINE bool _Processor_mask_Is_set(const Processor_mask *mask, uint32_t index)
Checks if the specified index bit of the mask is set.
const Scheduler_Assignment _Scheduler_Initial_assignments[]
The scheduler assignments.
uint32_t attributes
The scheduler assignment attributes.
Definition: scheduler.h:359
Scheduler assignment.
Definition: scheduler.h:344
Per CPU Core Structure.
Definition: percpu.h:347
static void _SMP_Fatal(SMP_Fatal_code code)
Terminates with the given code.
Definition: smpimpl.h:72
uint32_t ISR_Level
Definition: isrlevel.h:41
char * data
Begin of the per-CPU data area.
Definition: percpu.h:543
void _Thread_Start_multitasking(void) RTEMS_NO_RETURN
Starts thread multitasking.
void _SMP_Request_shutdown(void)
Requests a shutdown of all processors.
Definition: smp.c:205
Processor_mask Processors
Lock to protect this scheduler instance.
Definition: scheduler.h:257
struct Per_CPU_Control::@13 Watchdog
Watchdog state for this processor.
const struct _Scheduler_Control * control
The scheduler control of the scheduler owning this processor.
Definition: percpu.h:514
bool online
Indicates if the processor has been successfully started via _CPU_SMP_Start_processor().
Definition: percpu.h:589
void _SMP_Request_start_multitasking(void)
Requests a multitasking start on all configured and available processors.
Definition: smp.c:154
This is the terminal state.
Definition: percpu.h:173
const Scheduler_Control * scheduler
The scheduler for this processor.
Definition: scheduler.h:348
static __inline__ void _Chain_Initialize_empty(Chain_Control *the_chain)
Initializes this chain as empty.
Definition: chainimpl.h:505
Definition of custom per-CPU items.
Processor_mask _SMP_Online_processors
Set of online processors.
Definition: smp.c:36
Scheduler control.
Definition: scheduler.h:264
#define _ISR_lock_Set_name(_lock, _name)
Sets the name of an ISR lock.
Definition: isrlock.h:211
static __inline__ Scheduler_Context * _Scheduler_Get_context(const Scheduler_Control *scheduler)
Gets the context of the scheduler.
Definition: schedulerimpl.h:85
void _Internal_error(Internal_errors_Core_list core_error) RTEMS_NO_RETURN
Terminates the system with an INTERNAL_ERROR_CORE fatal source and the specified core error code...
Definition: interr.c:51
void * _Memory_Allocate(const Memory_Information *information, uintptr_t size, uintptr_t alignment)
Allocate a memory area from the memory information.
Inlined Routines from the Thread Handler.
Atomic_Ulong message
Bit field for SMP messages.
Definition: percpu.h:505
#define rtems_configuration_get_maximum_processors()
Returns the maximum number of processors which are configured for this application.
Definition: config.h:194
const Memory_Information * _Memory_Get(void)
Return the memory information of this platform.
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG.
Definition: assert.h:100
void _SMP_Send_message(uint32_t cpu_index, unsigned long message)
Sends an SMP message to a processor.
Definition: smp.c:215
Multitasking start of processor is requested.
Definition: percpu.h:163
SuperCore SMP Implementation.
RTEMS_INLINE_ROUTINE void _Processor_mask_Set(Processor_mask *mask, uint32_t index)
Sets the specified index bit of the mask.