source: rtems/cpukit/score/src/smp.c @ eea21eac

5
Last change on this file since eea21eac was eea21eac, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 13, 2019 at 5:18:36 AM

bsps: Rework work area initialization

The work area initialization was done by the BSP through
bsp_work_area_initialize(). This approach predated the system
initialization through the system initialization linker set. The
workspace and C program heap were unconditionally initialized. The aim
is to support RTEMS application configurations which do not need the
workspace and C program heap. In these configurations, the workspace
and C prgram heap should not get initialized.

Change all bsp_work_area_initialize() to implement _Memory_Get()
instead. Move the dirty memory, sbrk(), per-CPU data, workspace, and
malloc() heap initialization into separate system initialization steps.
This makes it also easier to test the individual initialization steps.

This change adds a dependency to _Heap_Extend() to all BSPs. This
dependency will be removed in a follow up change.

Update #3838.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief SMP Support
5 *  @ingroup RTEMSScore
6 */
7
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#if 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>
25#include <rtems/score/schedulerimpl.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
36Processor_mask _SMP_Online_processors;
37
38uint32_t _SMP_Processor_maximum;
39
40static const Scheduler_Assignment *_Scheduler_Get_initial_assignment(
41  uint32_t cpu_index
42)
43{
44  return &_Scheduler_Initial_assignments[ cpu_index ];
45}
46
47static bool _Scheduler_Is_mandatory_processor(
48  const Scheduler_Assignment *assignment
49)
50{
51  return (assignment->attributes & SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) != 0;
52}
53
54static bool _Scheduler_Should_start_processor(
55  const Scheduler_Assignment *assignment
56)
57{
58  return assignment->scheduler != NULL;
59}
60
61static 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
105      _Processor_mask_Set( &_SMP_Online_processors, cpu_index );
106      _Processor_mask_Set( &context->Processors, cpu_index );
107      cpu->Scheduler.control = scheduler;
108      cpu->Scheduler.context = context;
109    }
110  }
111}
112
113void _SMP_Handler_initialize( void )
114{
115  uint32_t cpu_config_max;
116  uint32_t cpu_max;
117  uint32_t cpu_index;
118
119  cpu_config_max = rtems_configuration_get_maximum_processors();
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" );
128    _Chain_Initialize_empty( &cpu->Threads_in_need_for_help );
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
154void _SMP_Request_start_multitasking( void )
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
176bool _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
184void _SMP_Start_multitasking_on_secondary_processor(
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
202  _Thread_Start_multitasking();
203}
204
205void _SMP_Request_shutdown( void )
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
215void _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
224void _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
237        && _Processor_mask_Is_set( &_SMP_Online_processors, cpu_index )
238    ) {
239      _SMP_Send_message( cpu_index, message );
240    }
241  }
242}
243
244void _SMP_Send_message_multicast(
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
261static 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
277    cpu_max = rtems_configuration_get_maximum_processors();
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
292RTEMS_SYSINIT_ITEM(
293  _Per_CPU_Data_initialize,
294  RTEMS_SYSINIT_PER_CPU_DATA,
295  RTEMS_SYSINIT_ORDER_MIDDLE
296);
Note: See TracBrowser for help on using the repository browser.