source: rtems/cpukit/score/src/percpu.c @ fce900b5

5
Last change on this file since fce900b5 was 5b0d2c1, checked in by Sebastian Huber <sebastian.huber@…>, on 03/03/16 at 12:37:14

score: Add _SMP_Before_multitasking_action()

The use case for this is the Cortex-A9 MPCore which has per-processor
registers (only accessible by a particular processor) for the global
timer used by the clock driver. This might be useful for other drivers
as well.

Update #2554.

  • Property mode set to 100644
File size: 5.9 KB
Line 
1/**
2 * @file
3 *
4 * @brief Allocate and Initialize Per CPU Structures
5 * @ingroup PerCPU
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/percpu.h>
22#include <rtems/score/assert.h>
23#include <rtems/score/isrlock.h>
24#include <rtems/score/smpimpl.h>
25#include <rtems/config.h>
26
27RTEMS_STATIC_ASSERT(
28  sizeof( CPU_Uint32ptr ) >= sizeof( uintptr_t ),
29  CPU_Uint32ptr_greater_equal_uintptr_t
30);
31
32RTEMS_STATIC_ASSERT(
33  sizeof( CPU_Uint32ptr ) >= sizeof( uint32_t ),
34  CPU_Uint32ptr_greater_equal_uint32_t
35);
36
37#if defined(RTEMS_SMP)
38
39typedef struct {
40  SMP_Action_handler handler;
41  void *arg;
42} SMP_Before_multicast_action;
43
44ISR_LOCK_DEFINE( static, _Per_CPU_State_lock, "Per-CPU State" )
45
46static void _Per_CPU_State_acquire( ISR_lock_Context *lock_context )
47{
48  _ISR_lock_ISR_disable_and_acquire( &_Per_CPU_State_lock, lock_context );
49}
50
51static void _Per_CPU_State_release( ISR_lock_Context *lock_context )
52{
53  _ISR_lock_Release_and_ISR_enable( &_Per_CPU_State_lock, lock_context );
54}
55
56static void _Per_CPU_State_before_multitasking_action( Per_CPU_Control *cpu )
57{
58  uintptr_t action_value;
59
60  action_value = _Atomic_Load_uintptr(
61    &cpu->before_multitasking_action,
62    ATOMIC_ORDER_ACQUIRE
63  );
64
65  if ( action_value != 0 ) {
66    SMP_Before_multicast_action *action =
67      (SMP_Before_multicast_action *) action_value;
68
69    ( *action->handler )( action->arg );
70
71    _Atomic_Store_uintptr(
72      &cpu->before_multitasking_action,
73      0,
74      ATOMIC_ORDER_RELEASE
75    );
76  }
77}
78
79static void _Per_CPU_State_busy_wait(
80  Per_CPU_Control *cpu,
81  Per_CPU_State new_state
82)
83{
84  Per_CPU_State state = cpu->state;
85
86  switch ( new_state ) {
87    case PER_CPU_STATE_REQUEST_START_MULTITASKING:
88      while (
89        state != PER_CPU_STATE_READY_TO_START_MULTITASKING
90          && state != PER_CPU_STATE_SHUTDOWN
91      ) {
92        _CPU_SMP_Processor_event_receive();
93        state = cpu->state;
94      }
95      break;
96    case PER_CPU_STATE_UP:
97      while (
98        state != PER_CPU_STATE_REQUEST_START_MULTITASKING
99          && state != PER_CPU_STATE_SHUTDOWN
100      ) {
101        _Per_CPU_State_before_multitasking_action( cpu );
102        _CPU_SMP_Processor_event_receive();
103        state = cpu->state;
104      }
105      break;
106    default:
107      /* No need to wait */
108      break;
109  }
110}
111
112static Per_CPU_State _Per_CPU_State_get_next(
113  Per_CPU_State current_state,
114  Per_CPU_State new_state
115)
116{
117  switch ( current_state ) {
118    case PER_CPU_STATE_INITIAL:
119      switch ( new_state ) {
120        case PER_CPU_STATE_READY_TO_START_MULTITASKING:
121        case PER_CPU_STATE_SHUTDOWN:
122          /* Change is acceptable */
123          break;
124        default:
125          new_state = PER_CPU_STATE_SHUTDOWN;
126          break;
127      }
128      break;
129    case PER_CPU_STATE_READY_TO_START_MULTITASKING:
130      switch ( new_state ) {
131        case PER_CPU_STATE_REQUEST_START_MULTITASKING:
132        case PER_CPU_STATE_SHUTDOWN:
133          /* Change is acceptable */
134          break;
135        default:
136          new_state = PER_CPU_STATE_SHUTDOWN;
137          break;
138      }
139      break;
140    case PER_CPU_STATE_REQUEST_START_MULTITASKING:
141      switch ( new_state ) {
142        case PER_CPU_STATE_UP:
143        case PER_CPU_STATE_SHUTDOWN:
144          /* Change is acceptable */
145          break;
146        default:
147          new_state = PER_CPU_STATE_SHUTDOWN;
148          break;
149      }
150      break;
151    default:
152      new_state = PER_CPU_STATE_SHUTDOWN;
153      break;
154  }
155
156  return new_state;
157}
158
159void _Per_CPU_State_change(
160  Per_CPU_Control *cpu,
161  Per_CPU_State new_state
162)
163{
164  ISR_lock_Context lock_context;
165  Per_CPU_State next_state;
166
167  _Per_CPU_State_busy_wait( cpu, new_state );
168
169  _Per_CPU_State_acquire( &lock_context );
170
171  next_state = _Per_CPU_State_get_next( cpu->state, new_state );
172  cpu->state = next_state;
173
174  if ( next_state == PER_CPU_STATE_SHUTDOWN ) {
175    uint32_t cpu_max = rtems_configuration_get_maximum_processors();
176    uint32_t cpu_index;
177
178    for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
179      Per_CPU_Control *cpu_other = _Per_CPU_Get_by_index( cpu_index );
180
181      if ( cpu_other != cpu ) {
182        switch ( cpu_other->state ) {
183          case PER_CPU_STATE_UP:
184            _SMP_Send_message( cpu_index, SMP_MESSAGE_SHUTDOWN );
185            break;
186          default:
187            /* Nothing to do */
188            break;
189        }
190
191        cpu_other->state = PER_CPU_STATE_SHUTDOWN;
192      }
193    }
194  }
195
196  _CPU_SMP_Processor_event_broadcast();
197
198  _Per_CPU_State_release( &lock_context );
199
200  if (
201    next_state == PER_CPU_STATE_SHUTDOWN
202      && new_state != PER_CPU_STATE_SHUTDOWN
203  ) {
204    _SMP_Fatal( SMP_FATAL_SHUTDOWN );
205  }
206}
207
208bool _SMP_Before_multitasking_action(
209  Per_CPU_Control    *cpu,
210  SMP_Action_handler  handler,
211  void               *arg
212)
213{
214  bool done;
215
216  _Assert( _Per_CPU_Is_boot_processor( _Per_CPU_Get() ) );
217
218  if ( _Per_CPU_Is_processor_online( cpu ) ) {
219    SMP_Before_multicast_action action = {
220      .handler = handler,
221      .arg = arg
222    };
223    Per_CPU_State expected_state = PER_CPU_STATE_READY_TO_START_MULTITASKING;
224
225    _Atomic_Store_uintptr(
226      &cpu->before_multitasking_action,
227      (uintptr_t) &action,
228      ATOMIC_ORDER_RELEASE
229    );
230
231    _CPU_SMP_Processor_event_broadcast();
232
233    _Per_CPU_State_busy_wait( cpu, expected_state );
234
235    do {
236      done = _Atomic_Load_uintptr(
237        &cpu->before_multitasking_action,
238        ATOMIC_ORDER_ACQUIRE
239      ) == 0;
240    } while ( !done && cpu->state == expected_state );
241  } else {
242    done = false;
243  }
244
245  return done;
246}
247
248#else
249  /*
250   * On single core systems, we can efficiently directly access a single
251   * statically allocated per cpu structure.  And the fields are initialized
252   * as individual elements just like it has always been done.
253   */
254  Per_CPU_Control_envelope _Per_CPU_Information[1];
255#endif
Note: See TracBrowser for help on using the repository browser.